|
|
1.1 root 1: /*
2: * maharani - a czarina-like program that generates interpress files
3: *
4: * Written for Xerox Corporation by William LeFebvre
5: *
6: * Copyright (c) 1984, 1985, 1986 Xerox Corporation
7: *
8: * HISTORY
9: * 23-Sep-86 Lee Moore (lee) at Xerox Webster Research Center
10: * Added Jim Mayer's fix to the space allocator.
11: *
12: * 13-apr-86 Ed Flint (ed) at Xerox Webster Research Center
13: * do_file will reset to left margin when encountering carriage return
14: *
15: * 11-Feb-86 Lee Moore (lee) at Xerox Webster Research Center
16: * Added various suggestions from Larry Parmalee at Cornell U.
17: * 1) Margin adjustments. Margins vary according to portrait or
18: * landscape mode. If headings are suppressed, then that area
19: * is used for text. Room left to punch holes at left.
20: * 2) Baseline spacing is tightened up for smaller font sizes
21: * 3) options can now reset each other
22: * 4) added "-P" option to specifiy output device (for compatibility
23: * with lpr system stuff.)
24: * 5) Improved maha environment variable handling (pair up and eliminate
25: * double and single quotes).
26: * 6) Interpress file now has mode 600 (for security reasons)
27: * 7) Maximum line length increased.
28: *
29: * 13-Jan-86 Lee Moore (lee) at Xerox Webster Research Center
30: * Changed a call to strcpyn to strncpy.
31: *
32: * 8-apr-85 ed flint
33: * conditional compilation for vax11-c (vms)
34: *
35: * 26-mar-85 ed flint @ Xerox, WRC
36: * add fclose after do_file to prevent running out of open file descriptors
37: */
38:
39: #ifdef vax11c
40: # include stdio
41: # include ssdef
42: # include ctype
43: # include descrip
44: #else
45: # include <stdio.h>
46: # include <pwd.h>
47: # include <strings.h>
48: # include <sys/types.h>
49: # include <sys/stat.h>
50: # include <sys/time.h>
51: #endif
52:
53: # include "iptokens.h"
54: # include "literal.h"
55: # include "operator.h"
56:
57:
58: /*
59: * the following defines a program that will queue an Interpress master
60: * for printing
61: */
62: # define QIP "qip"
63:
64: # define Break_size 1024
65: # define Default_universal_prefix "Xerox/XC1-1-1/"
66: # define Line_size 192 /* upped from 132 */
67:
68: /* All page boundaries are computed in the 1/10 point co-ordinate system */
69: /*
70: * Orig_y is an offset from the top of the page. It must be converted
71: * to a measurement from the bottom of the page (a calculation that is
72: * rotation-dependent).
73: */
74:
75: # define INCH 720
76: # define Half_INCH 360
77: # define Sixth_INCH 120 /* one line at 6 lpi */
78: # define Page_width (8 * INCH + Half_INCH)
79: # define Page_length (11 * INCH)
80: /* rflg ? Landscape mode : Portrait mode */
81: # define Orig_x (rflg ? (1.5 * INCH/10) : (9 * INCH/10))
82: # define Orig_y (rflg ? (Sixth_INCH * 8) : (Sixth_INCH * 5))
83: # define Header_to_orig_x 0
84: # define Header_to_orig_y (2 * Sixth_INCH)
85:
86: /* Frame variable defines */
87: # define F_transform 0
88: # define F_headfont 1
89: # define F_bodyfont 2
90: # define F_italicfont 3
91:
92: # define No 0
93: # define Yes 1
94:
95: extern int errno;
96:
97: /* enum, perhaps? */
98: typedef char boolean;
99:
100: /* routines that return something other than int */
101: char *strecpy();
102: char *allocate();
103: char *next_arg();
104: char *sbrk();
105: char *getenv();
106: char *itoa();
107: char *rindex();
108:
109: /* option flags */
110: boolean lflg = No; /* line printer mode */
111: boolean rflg = No; /* rotation - landscape mode */
112: boolean tflg = No; /* omit title */
113:
114: /* valued options */
115: int columns = 1;
116: char *bodyfont_name = "Vintage-Printwheel/10";
117: char *headfont_name = "Modern-Bold/12";
118: char *italicfont_name = "Modern-Bold-Italic/12";
119: char *banner = NULL;
120: char *copies = "1";
121: char *printer = NULL; /* destination printer */
122: char *header = "%f %t Page %p, line %l";
123: char *name = NULL;
124: char *output = NULL;
125: char *pages = NULL;
126:
127: #ifdef vax11c
128: char *template = "IPPXXXXXX";
129: #endif
130:
131: /*
132: * page characteristics: these variables define the extremes for the
133: * current page or column. 'column_separation' is the distance between
134: * the left sides of each column on the page.
135: */
136: #ifndef notdef
137: int left_margin = (9 * INCH / 10); /* x origin in portrait mode */
138: #else
139: int left_margin = Orig_x;
140: #endif
141: int right_margin;
142: int top_margin;
143: int bottom_margin;
144: int column_separation;
145:
146: /* sundries */
147: boolean send_to_printer = Yes;
148: char real_header[256]; /* header built here */
149: char *myname; /* name invoked with */
150: char *filename;
151: int *page_select = NULL; /* array of page selections */
152: int *curr_page_select;
153: int page_low;
154: int page_high;
155: int ipress_file; /* interpress file descriptor */
156: int null_file; /* fd for /dev/null */
157: int line_number;
158: int page_number;
159: int pages_printed = 0; /* total pages for this interpress file */
160: int special_font = 0; /* fonts that require special handling */
161: int line_spacing;
162: int tab_amount = 8;
163: #ifndef vax11c
164: struct passwd *pwd; /* passwd entry for this user */
165: struct stat file_stat; /* stat of current file */
166: #endif
167:
168: # define Font_Terminal 1
169:
170: /* current arguments */
171: int argc;
172: char **argv;
173:
174: /* font structure definition */
175: struct font
176: {
177: char *ft_universal_name;
178: char *ft_leaf_name;
179: int ft_size;
180: };
181:
182: /* fonts used */
183: struct font headfont;
184: struct font bodyfont;
185: struct font italicfont;
186:
187: main(_argc, _argv)
188:
189: int _argc;
190: char **_argv;
191:
192: {
193: char *ptr; /* temporary pointers used for loops and such */
194: char *src;
195: char *dest;
196: int length;
197: int i;
198: FILE *file; /* file currently processing */
199: #ifdef vax11c
200: int error;
201: int retlen;
202: char command[256];
203: $DESCRIPTOR(mahadesc,"MAHAENV");
204: $DESCRIPTOR(cmddesc,command);
205: #endif
206:
207: /* get our name */
208: if (_argc < 1)
209: {
210: exit(1);
211: }
212:
213: #ifdef vax11c
214: myname= _argv[0];
215: #else
216: if ((myname = rindex(_argv[0], '/')) == NULL)
217: {
218: myname = _argv[0];
219: }
220: else
221: {
222: myname++;
223: }
224: #endif
225:
226: /* get the options specified in the environment (defaults) */
227:
228: #ifdef vax11c
229: if ( (error= lib$get_symbol(&mahadesc,&cmddesc,&retlen)) == SS$_NORMAL )
230: {
231: if ( retlen != 0 )
232: {
233: command[retlen & 0xff]= '\0'; /* null terminate string */
234: src= command;
235: /* break the string up into null terminated arguments */
236: /* half the length is a good upper bound on number of arguments */
237: argv = (char **)allocate(strlen(src) / 2);
238: for (argc = 1, ptr = src; *ptr != '\0'; argc++)
239: {
240: while (*ptr == ' ')
241: ptr++;
242: argv[argc] = ptr;
243: while (*ptr != ' ' && *ptr != '\0')
244: {
245: if (*ptr == '"')
246: {
247: while (*++ptr != '"' && *ptr != '\0');
248: }
249: else if (*ptr == '\'')
250: {
251: while (*++ptr != '\'' && *ptr != '\0');
252: }
253: ptr++;
254: }
255: *ptr++ = '\0';
256: }
257:
258: /* terminate the argument list */
259: argv[argc] = NULL;
260:
261: /* process the options found in the environment */
262: get_options();
263: }
264: }
265:
266: #else
267: if ((src = getenv("MAHA")) != NULL)
268: {
269: /* break the string up into null terminated arguments */
270: /* half the length is a good upper bound on number of arguments */
271: argv = (char **)allocate(strlen(src) / 2);
272: for (argc = 1, ptr = src; *ptr != '\0'; argc++)
273: {
274: register char *dst;
275: char quote;
276:
277: while (*ptr == ' ')
278: ptr++;
279: argv[argc] = dst = ptr;
280: while (*ptr != ' ' && *ptr != '\0')
281: {
282: if (*ptr == '"' || *ptr == '\'')
283: {
284: quote = *ptr++; /* Save + skip quote */
285:
286: while( *ptr != quote && *ptr != '\0')
287: *dst++ = *ptr++;
288:
289: if (*ptr != '\0')
290: ptr++; /* Skip closing quote */
291: }
292: else
293: *dst++ = *ptr++;
294: }
295: if (*ptr != '\0')
296: ptr++; /* skip 1st trailing space */
297:
298: *dst = '\0'; /* end arg. */
299: }
300:
301: /* terminate the argument list */
302: argv[argc] = NULL;
303:
304: /* process the options found in the environment */
305: get_options();
306: }
307: #endif
308:
309: /* use the real arguments */
310: argc = _argc;
311: argv = _argv;
312:
313: /* process (real) arguments */
314: get_options();
315:
316: /* establish and verify the requested fonts */
317: establish_font(headfont_name, &headfont);
318: establish_font(bodyfont_name, &bodyfont);
319: establish_font(italicfont_name, &italicfont);
320:
321: #ifndef vax11c
322: /* get passwd entry for future reference */
323: pwd = getpwuid(geteuid());
324: #endif
325:
326: /* setup output file */
327: if (output == NULL)
328: {
329:
330: /* build a temporary file name */
331:
332: #ifdef vax11c
333: output= mktemp(template);
334: #else
335: output = allocate(1 + 5 + 1 + 2 + 1);
336: (void) sprintf(output, "/tmp/@%d.ip", getpid());
337: #endif
338: }
339:
340: #ifdef vax11c
341: if ((ipress_file = creat(output, 0, "rfm=udf")) == -1)
342: #else
343: if ((ipress_file = creat(output, 0600)) == -1)
344: #endif
345: {
346: system_error(output);
347: exit(1);
348: }
349: ip_select(ipress_file);
350:
351: #ifndef vax11c
352: /* open the null device for throwing away output */
353: null_file = open("/dev/null", 1);
354:
355: /* set null strings to default values */
356: if (name == NULL)
357: {
358: /* banner name defaults to full name from gecos field */
359: name = pwd->pw_gecos;
360:
361: /* perform expansion and stripping */
362: if ((ptr = index(name, ',')) != NULL)
363: {
364: *ptr = '\0'; /* this affects pwd->pw_gecos, too! */
365: }
366: if (index(name, '&') != NULL)
367: {
368: name = allocate(strlen(name) + strlen(pwd->pw_name) + 1);
369: for (src = pwd->pw_gecos, dest = name; *src != '\0'; src++, dest++)
370: {
371: if (*src == '&')
372: {
373: for (ptr = pwd->pw_name; *ptr != '\0'; ptr++)
374: {
375: *dest++ = *ptr;
376: }
377: }
378: else
379: {
380: *dest = *src;
381: }
382: }
383: }
384: }
385: #endif
386:
387: if (banner == NULL)
388: {
389: /* banner defaults to file name(s) */
390: if (argc == 0)
391: {
392: banner = "out of the blue";
393: }
394: else
395: {
396: for (length = 0, i = 0; i < argc; i++)
397: {
398: length += strlen(argv[i]) + 2;
399: }
400: banner = allocate(length + 1);
401: for (ptr = banner, i = 0; i < argc; i++)
402: {
403: ptr = strecpy(ptr, argv[i]);
404: ptr = strecpy(ptr, ", ");
405: }
406: ptr -= 2;
407: *ptr = '\0';
408: }
409: }
410:
411: /* unravel the page specifiation */
412: /* we will never need more than strlen(pages) ints to hold the info */
413: if (pages != NULL)
414: {
415: page_select = (int *)allocate(strlen(pages) * sizeof(int));
416: unravel_pages(pages, page_select);
417: }
418:
419: /* write the preamble for the interpress file */
420: AppendOp(OP_beginBlock);
421: AppendOp(OP_beginBody); /* preamble start */
422:
423: /* setup font definitions in frame */
424: SetupFont(headfont.ft_universal_name,
425: headfont.ft_size * 10.,
426: F_headfont);
427: SetupFont(bodyfont.ft_universal_name,
428: bodyfont.ft_size * 10.,
429: F_bodyfont);
430: SetupFont(italicfont.ft_universal_name,
431: headfont.ft_size * 10., /* use headfont's size */
432: F_italicfont);
433:
434: /* remember special fonts */
435: if (strcmp(bodyfont.ft_leaf_name, "Terminal") == 0)
436: {
437: special_font = Font_Terminal;
438: }
439:
440: /* save scaling transform that uses 1/10 point co-ordinate system */
441: top_margin = (rflg ? Page_width : Page_length) - Orig_y;
442:
443: if (tflg) /* the user may not want headings... */
444: top_margin += Header_to_orig_y; /* use heading area */
445:
446: bottom_margin = 2 * Sixth_INCH;
447: right_margin = (rflg ? Page_length : Page_width) - Orig_x;
448: column_separation = (right_margin - Orig_x) / columns;
449: line_spacing = (bodyfont.ft_size +
450: ((bodyfont.ft_size > 8) ? 2 : 0)) * 10;
451: if (rflg)
452: {
453: /* we need a rotation transform, too */
454: Rotate(90.);
455: Translate((double)Page_width, (double)0);
456: }
457: AppendRational(353L,10000000L);
458: AppendOp(OP_scale);
459: if (rflg)
460: {
461: AppendOp(OP_concat);
462: AppendOp(OP_concat);
463: }
464: AppendInteger((long) F_transform);
465: AppendOp(OP_fset);
466:
467: AppendOp(OP_endBody); /* end preamble */
468:
469: if (argc == 0)
470: {
471: /* no filenames -- do standard input */
472: filename = NULL;
473: do_file(stdin);
474: }
475:
476: for (; argc > 0; argc--, argv++)
477: {
478: filename = argv[0];
479: if (strcmp(filename, "-") == 0)
480: {
481: /* this is really standard input */
482: filename = NULL;
483: do_file(stdin);
484: }
485: else
486: {
487: /* open the file */
488: if ((file = fopen(filename, "r")) == NULL)
489: {
490: system_error(filename);
491: }
492: else
493: {
494: do_file(file);
495: (void) fclose(file);
496: }
497: }
498: }
499:
500: /* wrap up the output */
501: ip_select(ipress_file);
502: AppendOp(OP_endBlock);
503: ip_close();
504:
505: /* send to the printer */
506: if (send_to_printer)
507: {
508: if (pages_printed == 0)
509: {
510: /* don't print anything but remove temporary */
511: #ifdef vax11c
512: delete(output);
513: #else
514: (void) unlink(output);
515: #endif
516: }
517: else
518: {
519: #ifdef vax11c
520: char buff[256];
521: int wait= 0;
522: $DESCRIPTOR(buffdesc,buff);
523:
524: (void) strcpy(buff,"xpress/noformat ");
525: (void) strcat(buff,output);
526: buffdesc.dsc$w_length= strlen(buff);
527: if ( (error= lib$spawn(&buffdesc,0,0,&wait)) != SS$_NORMAL )
528: {
529: fprintf(stderr,"\nFile %s contains interpress master\n",output);
530: exit(error);
531: }
532: delete(output);
533: #else
534: char *buff;
535:
536: /* exec a "qip" to queue the file */
537: buff = allocate(strlen(name) + 1 + 1);
538: (void) strcpy(buff, "F");
539: (void) strcat(buff, name);
540:
541: if (printer)
542: execlp(QIP, "qip", "-q", printer, "-c", copies, "-nc", "-nk",
543: "-t", banner, "-x", buff, output, 0);
544: else
545: execlp(QIP, "qip", "-c", copies, "-nc", "-nk",
546: "-t", banner, "-x", buff, output, 0);
547:
548: fprintf(stderr, "Can't execl the queing program: %s\n", QIP);
549: perror(QIP);
550: fprintf(stderr, "File %s contains interpress master.\n", output);
551: exit(1);
552: #endif
553: }
554: }
555: }
556:
557: get_options()
558:
559: {
560: while (--argc > 0)
561: {
562: argv++;
563: if (!process_arg())
564: {
565: break;
566: }
567: }
568: }
569:
570: /*
571: * unravel_pages(str, spec) - unravel the page range specification in "str"
572: * into integer pairs in "spec". The first two
573: * ints in "spec" bound the first range of pages,
574: * the next two bound the second range, and so on.
575: * The array is terminated with the pair 0, 0.
576: */
577:
578: unravel_pages(str, spec)
579:
580: char *str;
581: int *spec;
582:
583: {
584: int last_num = 0;
585: int this_num = 0;
586: register char ch;
587: boolean is_range = No;
588: boolean bad_spec = No;
589: boolean done = No;
590:
591: # define Start_new_num (last_num = this_num, this_num = 0)
592:
593: while (!done)
594: {
595: if ((ch = *str++) == '\0')
596: {
597: /* set "done" flag and pretend it's the end of a number */
598: done = Yes;
599: ch = ',';
600: }
601: if (ch >= '0' && ch <= '9')
602: {
603: this_num *= 10;
604: this_num += ch - '0';
605: }
606: else if (ch == '-')
607: {
608: if (this_num < last_num && *str != '\0')
609: {
610: bad_spec = Yes;
611: }
612: *spec++ = this_num;
613: Start_new_num;
614: is_range = Yes;
615: }
616: else if (ch == ',')
617: {
618: if (this_num < last_num)
619: {
620: bad_spec = Yes;
621: }
622: *spec++ = this_num;
623: if (is_range)
624: {
625: is_range = No;
626: }
627: else
628: {
629: *spec++ = this_num;
630: }
631: Start_new_num;
632: }
633: else
634: {
635: fprintf(stderr, "%s: bad character in page specification\n",
636: myname);
637: exit(1);
638: }
639: }
640: if (*--spec == 0)
641: {
642: *spec = 1 << 15; /* infinity */
643: }
644: if (bad_spec)
645: {
646: fprintf(stderr,
647: "%s: pages should be given in non-descending order.\n",
648: myname);
649: }
650: }
651:
652: process_arg()
653:
654: {
655: register char ch;
656: register int temp;
657: register char *p1;
658: register char *p2;
659:
660: if (argv[0][0] == '-')
661: {
662: if ((ch = argv[0][1]) > '0' && ch <= '9')
663: {
664: /* this is a column count specifier */
665: columns = ch - '0';
666: }
667: else switch(ch)
668: {
669: case '\0': /* not an option */
670: return(No);
671:
672: case 'b':
673: banner = next_arg();
674: break;
675:
676: case 'c':
677: temp = atoi(copies = next_arg());
678: if (temp < 1)
679: {
680: fprintf(stderr,
681: "%s: bogus number of copies; you only get one!\n",
682: myname);
683: copies = "1";
684: }
685: break;
686:
687: case 'f':
688: bodyfont_name = next_arg();
689: break;
690:
691: case 'F':
692: headfont_name = next_arg();
693: break;
694:
695: case 'H': /* replace header */
696: tflg = No;
697: header = next_arg();
698: break;
699:
700: case 'h': /* append to header */
701: tflg = No;
702: p1 = next_arg();
703: p2 = allocate(strlen(header) + strlen(p1) + 1);
704: (void) strcpy(p2, header);
705: (void) strcat(p2, " ");
706: (void) strcat(p2, p1);
707: header = p2;
708: break;
709:
710: case 'l':
711: tflg = lflg = Yes;
712: break;
713:
714: case 'n':
715: name = next_arg();
716: break;
717:
718: case 'o':
719: output = next_arg();
720: send_to_printer = No;
721: break;
722:
723: case 'P':
724: printer = next_arg();
725: break;
726:
727: case 'r':
728: rflg = Yes;
729: break;
730:
731: case 'R':
732: rflg = No;
733: break;
734:
735: case 's':
736: pages = next_arg();
737: break;
738:
739: case 't':
740: tflg = Yes;
741: break;
742:
743: default:
744: fprintf(stderr, "%s: unknown option '%c'\n", myname, ch);
745: }
746: return(Yes);
747: }
748: else
749: {
750: return(No);
751: }
752: }
753:
754: char *next_arg()
755:
756: {
757: if (argv[0][2] == '\0')
758: {
759: if (--argc > 0)
760: {
761: return((++argv)[0]);
762: }
763: else
764: {
765: argv++;
766: return(NULL);
767: }
768: }
769: else
770: {
771: return(&(argv[0][2]));
772: }
773: }
774:
775: /*
776: * establish_font(name, font) - break apart the parts of the string "name"
777: * and fill in the structure pointed to by
778: * "font". Also, verify that the font requested
779: * actually exists. This routine also
780: * understands universal font names.
781: */
782:
783: establish_font(name, font)
784:
785: char *name;
786: struct font *font;
787:
788: {
789: register char *unamep;
790: register char *ptr;
791: char *slashp;
792: register int size;
793:
794: if (name[0] != '/')
795: {
796: /* not a universal name -- put the default on the front */
797: font->ft_universal_name = unamep =
798: allocate(strlen(Default_universal_prefix) +
799: strlen(name) + 1);
800: (void) strcpy(unamep, Default_universal_prefix);
801: (void) strcat(unamep, name);
802: }
803: else
804: {
805: /* already is a universal name -- just allocate space for it */
806: font->ft_universal_name = unamep = allocate(strlen(name));
807:
808: /* copy in the whole name, without the leading slash */
809: (void) strcpy(unamep, name + 1);
810: }
811:
812: /* strip size off the end, if it is there */
813: if ((slashp = ptr = rindex(unamep, '/')) != NULL)
814: {
815: register char ch;
816:
817: size = 0;
818: while ((ch = *++ptr) != '\0')
819: {
820: if (ch < '0' || ch > '9')
821: {
822: /* last element is not a number -- no point size */
823: size = 0;
824: break;
825: }
826:
827: /* shift this digit in */
828: size *= 10;
829: size += (ch - '0');
830: }
831:
832: /* if no point size, use default */
833: if (size == 0)
834: {
835: font->ft_size = 10;
836: }
837: else
838: {
839: font->ft_size = size;
840: *slashp = '\0';
841: }
842: }
843:
844: /* set pointer to last element */
845: if ((ptr = rindex(unamep, '/')) != NULL)
846: {
847: font->ft_leaf_name = ptr + 1;
848: }
849: else
850: {
851: font->ft_leaf_name = font->ft_universal_name;
852: }
853: }
854:
855: do_file(file)
856:
857: FILE *file;
858:
859: {
860: char *src;
861: char *dest;
862: char input_line[Line_size];
863: char line_buffer[Line_size];
864: char ch;
865: int current_line;
866: int lines_on_page;
867: int length;
868: int column;
869:
870: #ifndef vax11c
871: /* fstat it to get information displayed in the header */
872: if (fstat(fileno(file), &file_stat) == -1)
873: {
874: system_error("fstat botched");
875: return;
876: }
877: #endif
878:
879: /* reset essentials */
880: page_number = 0;
881: line_number = 1;
882: lines_on_page = 0;
883: curr_page_select = page_select;
884: if (pages != NULL)
885: {
886: page_low = page_select[0];
887: page_high = page_select[1];
888: }
889: current_line = top_margin;
890:
891: /*
892: * Strangeness: page_number is incremented by page_start and
893: * line_number is incremented in the "while(fgets..." loop.
894: */
895:
896: /* start the first page */
897: page_start();
898:
899: /*
900: * More strangeness: we had to set line_number to 1 to trick
901: * page_start into reporting the right line count in the header. Now
902: * we reset it to 0 before entering the read/print loop.
903: */
904: line_number = 0;
905:
906: while (fgets(input_line, Line_size, file) != NULL)
907: {
908: /* new line */
909: line_number++;
910:
911: /* remember the length */
912: length = strlen(input_line);
913:
914: /* nuke any trailing newline */
915: if (input_line[length - 1] == '\n')
916: {
917: input_line[--length] = '\0';
918: }
919:
920: if (lflg ? lines_on_page >= 66 : current_line < bottom_margin)
921: {
922: /* start a new page */
923: page_end(No);
924: page_start();
925: lines_on_page = 0;
926:
927: /* remember, y goes backwards */
928: current_line = top_margin;
929: }
930:
931: /* make sure that the line actually contains something */
932: if (input_line[0] != '\0')
933: {
934: /* set x and y for the beginning of the line */
935: Setxy((double)left_margin, (double)current_line);
936:
937: /* copy from input_line to line_buffer making any necessary
938: changes along the way */
939: column = 0;
940: src = input_line;
941: dest = line_buffer;
942: while ((ch = *src) != '\0')
943: {
944: switch(ch)
945: {
946: case '\r': /* carriage return */
947: *dest = '\0';
948: if (line_buffer[0] != '\0')
949: {
950: ShowString(line_buffer);
951: }
952: Setxy((double)left_margin, (double)current_line);
953: dest= line_buffer;
954: break;
955:
956: case '\f': /* new page after this line */
957: current_line = bottom_margin;
958: lines_on_page = 66;
959: break;
960:
961: case '\t': /* tab expansion */
962: do
963: {
964: *dest++ = ' ';
965: column++;
966: } while (column % tab_amount != 0);
967: break;
968:
969: case '$':
970: *dest++ = '\244';
971: column++;
972: break;
973:
974: case '-':
975: if (special_font == Font_Terminal)
976: {
977: /* heavy hackery here */
978: *dest = '\0';
979: ShowString(line_buffer);
980: Setyrel(-20.);
981: ShowString("\305");
982: Setyrel(20.);
983: dest = line_buffer;
984: column++;
985: break;
986: }
987: /* else fall thru ... */
988:
989: default:
990: *dest++ = ch;
991: column++;
992: }
993: src++;
994: }
995: *dest = '\0';
996: if (line_buffer[0] != '\0')
997: {
998: ShowString(line_buffer);
999: }
1000: }
1001:
1002: /* advance the line counters */
1003: current_line -= line_spacing;
1004: lines_on_page++;
1005: }
1006:
1007: /* wrap up the file */
1008: page_end(Yes);
1009: }
1010:
1011: /*
1012: * page handling: a distinction is made between virtual pages and actual
1013: * pages. A virtual page is one series of lines from the file that appears
1014: * vertically on the printed page. The actual page is the page as the
1015: * printer prints it (a printed page, if you will). There may be several
1016: * virtual pages on one actual page. The page_start and page_end routines
1017: * that follow start and terminate virtual pages. The mapping between
1018: * virtual and actual pages is a function of the options specified by the
1019: * user. If the user requests two column output then there will be two
1020: * virtual pages for every actual page. These pages will sit side-by-side on
1021: * the actual page. The mapping is accomplished by changing the variables
1022: * left_margin and right_margin. "page_start" also handles printing of the
1023: * page header, since there is only one of these on every actual page.
1024: */
1025:
1026: static int current_column;
1027:
1028: page_start()
1029:
1030: {
1031: boolean in_set;
1032:
1033: #ifdef vax11c
1034: long bintim;
1035: #endif
1036:
1037: /* reset the column count if starting a new file */
1038: if (line_number == 1)
1039: {
1040: current_column = 0;
1041: }
1042:
1043: /* either move the left margin or put out a new page */
1044: if (current_column != 0)
1045: {
1046: left_margin += column_separation;
1047: }
1048: else
1049: {
1050: /* increment page count and reset margin */
1051: page_number++;
1052: left_margin = Orig_x;
1053:
1054: /* is it in the page specification set? */
1055: if (page_select == NULL)
1056: {
1057: /* every page is in the set if there is no specification */
1058: in_set = Yes;
1059: }
1060: else
1061: {
1062: if (page_low <= page_number && page_number <= page_high)
1063: {
1064: in_set = Yes;
1065: ip_select(ipress_file);
1066: if (page_number == page_high)
1067: {
1068: /* at the top of the current range -- time to move up */
1069: curr_page_select += 2;
1070: page_low = curr_page_select[0];
1071: page_high = curr_page_select[1];
1072: }
1073: }
1074: else
1075: {
1076: /* not in set -- redirect output to null device */
1077: in_set = No;
1078: ip_select(null_file);
1079: }
1080: }
1081:
1082: if (in_set)
1083: {
1084: register char *src;
1085: register char *dst;
1086: register char ch;
1087:
1088: /* increment total page count */
1089: pages_printed++;
1090:
1091: /* output stuff for new ip page */
1092: AppendOp(OP_beginBody);
1093:
1094: /* set the transformation */
1095: Fget(F_transform);
1096: AppendOp(OP_concatt);
1097:
1098: /* build the header if we need to print it */
1099: if (!tflg)
1100: {
1101: /* move characters from header to real_header */
1102: /* and expand format items along the way. */
1103: src = header;
1104: dst = real_header;
1105: while ((ch = *src) != '\0')
1106: {
1107: if (ch == '%')
1108: {
1109: switch(ch = *++src)
1110: {
1111: case 'f': /* file name */
1112: dst = strecpy(dst,
1113: filename == NULL ?
1114: "Standard input" :
1115: filename);
1116: break;
1117:
1118: case 't': /* mtime */
1119: #ifdef vax11c
1120:
1121: time(&bintim);
1122: strncpy(dst,ctime(&bintim), 24);
1123: dst += 24;
1124: #else
1125: /*
1126: * ctime returns a 26 character string that
1127: * has a newline and null at the end.
1128: * 26 - 2 == 24.
1129: */
1130: if (file_stat.st_mtime != 0)
1131: {
1132: (void) strncpy(dst,ctime(&file_stat.st_mtime),24);
1133: dst += 24;
1134: }
1135: #endif
1136: break;
1137:
1138: case 'p': /* page number */
1139: dst = itoa(dst, page_number);
1140: break;
1141:
1142: case 'l': /* line number */
1143: dst = itoa(dst, line_number);
1144: break;
1145:
1146: case '\0': /* end of the string */
1147: src--; /* maintain loop invariant */
1148: break;
1149:
1150: default: /* copy the character */
1151: *dst++ = ch;
1152: /* break; */
1153: }
1154: }
1155: else
1156: {
1157: *dst++ = ch;
1158: }
1159: src++;
1160: }
1161:
1162: /* terminate the real header */
1163: *dst = '\0';
1164:
1165: /* display the header */
1166: Setxy((double)(left_margin - Header_to_orig_x),
1167: (double)(top_margin + Header_to_orig_y));
1168: Setfont(F_headfont);
1169: ShowString(real_header);
1170: }
1171: }
1172: }
1173:
1174: /* select the body font */
1175: Setfont(F_bodyfont);
1176: }
1177:
1178: page_end(eof)
1179:
1180: int eof;
1181:
1182: {
1183: if ((current_column = ++current_column % columns) == 0 || eof)
1184: {
1185: AppendOp(OP_endBody);
1186: }
1187: }
1188:
1189: char *strecpy(dest, src)
1190:
1191: register char *src;
1192: register char *dest;
1193:
1194: {
1195: while (*dest++ = *src++)
1196: ;
1197: return(--dest);
1198: }
1199:
1200: char *itoa(buff, val)
1201:
1202: char *buff;
1203: int val;
1204:
1205: {
1206: char tbuff[12]; /* will build number here -- max of 10 digits */
1207: register char *ptr = tbuff + 11;
1208:
1209: *ptr-- = '\0';
1210: while (val != 0)
1211: {
1212: *ptr-- = (val % 10) + '0';
1213: val /= 10;
1214: }
1215: return(strecpy(buff, ++ptr));
1216: }
1217:
1218: /*
1219: * allocate(space) - allocate "space" bytes with sbrk. This routine uses a
1220: * fairly naive algorithm. It sbrk-s space in Break_size
1221: * chunks and allocates space from a chunk until a request
1222: * for more space than is left in the chunk is made. Then,
1223: * it allocates a new chunk. The unused space at the end
1224: * of the old chunk remains unused. This does NOT depend
1225: * on sbrk returning contiguous chunks of memory during the
1226: * life of the program. If the request is greater than
1227: * Break_size, the next multiple of Break_size greater
1228: * than the request size is chosen.
1229: */
1230:
1231: char *allocate(space)
1232:
1233: int space;
1234:
1235: {
1236: static char *hi_water = NULL;
1237: static char *max_alloc = NULL;
1238: register char *ptr;
1239:
1240: if (hi_water == NULL || max_alloc + space > hi_water)
1241: {
1242: int alloc_size = (space <= Break_size
1243: ? Break_size
1244: : ((space + Break_size-1) / Break_size) * Break_size);
1245:
1246: hi_water = sbrk(alloc_size);
1247:
1248: if ((int)hi_water == -1)
1249: {
1250: system_error("out of space");
1251: exit(1);
1252: }
1253:
1254: max_alloc = hi_water + alloc_size - 1;
1255: }
1256:
1257: ptr = hi_water;
1258: hi_water += space;
1259: return(ptr);
1260: }
1261:
1262: system_error(message)
1263:
1264: char *message;
1265:
1266: {
1267: int saved_errno;
1268:
1269: /* value of errno not preserved by fprintf */
1270: saved_errno = errno;
1271: fprintf(stderr, "%s: ", myname);
1272: errno = saved_errno;
1273: perror(message);
1274: }
1275:
1276: #ifdef vax11c
1277: char *rindex(string, c)
1278: char *string, c;
1279: {
1280: register char *pos;
1281:
1282: pos = 0;
1283: do {
1284: if (*string == c)
1285: pos = string;
1286: } while (*string++);
1287: return(pos);
1288: }
1289:
1290: #endif
1291:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.