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  Header_to_orig_x  0
  56: # define  Header_to_orig_y  (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 *header   = "%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 real_header[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

Defined functions

allocate defined in line 1158; used 11 times
do_file defined in line 794; used 3 times
establish_font defined in line 722; used 3 times
get_options defined in line 502; used 3 times
itoa defined in line 1129; used 3 times
main defined in line 154; never used
next_arg defined in line 693; used 10 times
page_end defined in line 1107; used 2 times
page_start defined in line 957; used 2 times
process_arg defined in line 597; used 1 times
rindex defined in line 1200; used 4 times
strecpy defined in line 1118; used 5 times
system_error defined in line 1185; used 4 times
unravel_pages defined in line 523; used 1 times

Defined variables

argc defined in line 138; used 17 times
argv defined in line 139; used 18 times
banner defined in line 91; used 6 times
bodyfont defined in line 151; used 5 times
bodyfont_name defined in line 88; used 2 times
bottom_margin defined in line 110; used 3 times
column_separation defined in line 111; used 2 times
columns defined in line 87; used 3 times
copies defined in line 92; used 3 times
curr_page_select defined in line 119; used 4 times
current_column defined in line 955; used 4 times
file_stat defined in line 132; used 3 times
filename defined in line 117; used 8 times
header defined in line 93; used 5 times
headfont defined in line 150; used 4 times
headfont_name defined in line 89; used 2 times
ipress_file defined in line 122; used 5 times
italicfont defined in line 152; used 2 times
italicfont_name defined in line 90; used 1 times
left_margin defined in line 107; used 4 times
lflg defined in line 82; used 2 times
line_number defined in line 124; used 5 times
line_spacing defined in line 128; used 2 times
myname defined in line 116; used 9 times
name defined in line 94; used 17 times
null_file defined in line 123; used 2 times
output defined in line 95; used 15 times
page_high defined in line 121; used 4 times
page_low defined in line 120; used 3 times
page_number defined in line 125; used 6 times
page_select defined in line 118; used 6 times
pages defined in line 96; used 5 times
pages_printed defined in line 126; used 2 times
pwd defined in line 131; used 5 times
real_header defined in line 115; used 2 times
rflg defined in line 83; used 6 times
right_margin defined in line 108; used 2 times
send_to_printer defined in line 114; used 2 times
special_font defined in line 127; used 2 times
tab_amount defined in line 129; used 1 times
template defined in line 99; used 1 times
tflg defined in line 84; used 3 times
top_margin defined in line 109; used 4 times

Defined struct's

font defined in line 142; used 8 times

Defined typedef's

boolean defined in line 70; used 8 times

Defined macros

Break_size defined in line 37; used 2 times
Default_universal_prefix defined in line 38; used 2 times
F_bodyfont defined in line 61; used 2 times
F_headfont defined in line 60; used 2 times
F_italicfont defined in line 62; used 1 times
F_transform defined in line 59; used 2 times
Font_Terminal defined in line 135; used 2 times
Half_INCH defined in line 49; used 1 times
  • in line 51
Header_to_orig_x defined in line 55; used 1 times
Header_to_orig_y defined in line 56; used 1 times
INCH defined in line 48; used 3 times
Line_size defined in line 39; used 3 times
No defined in line 64; used 13 times
Orig_x defined in line 53; used 4 times
Orig_y defined in line 54; used 1 times
Page_length defined in line 52; used 2 times
Page_width defined in line 51; used 3 times
QIP defined in line 35; used 2 times
Sixth_INCH defined in line 50; used 3 times
Start_new_num defined in line 536; used 2 times
Yes defined in line 65; used 12 times
Last modified: 1986-01-14
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4602
Valid CSS Valid XHTML 1.0 Strict