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