|
|
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.