home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / groff / pic / main.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-30  |  11.1 KB  |  572 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.uucp)
  4.  
  5. This file is part of groff.
  6.  
  7. groff is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 1, or (at your option) any later
  10. version.
  11.  
  12. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License along
  18. with groff; see the file LICENSE.  If not, write to the Free Software
  19. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21. #include "pic.h"
  22.  
  23. extern int yyparse();
  24.  
  25. output *out;
  26.  
  27. int flyback_flag;
  28. int zero_length_line_flag = 0;
  29. int driver_extension_flag = 0;
  30. int compatible_flag = 0;
  31. int command_char = '.';        // the character that introduces lines
  32.                 // that should be passed through tranparently
  33. static int lf_flag = 1;        // non-zero if we should attempt to understand
  34.                 // lines beginning with `.lf'
  35.  
  36. void do_file(const char *filename);
  37.  
  38. class top_input : public input {
  39.   FILE *fp;
  40.   int bol;
  41.   int eof;
  42.   int push_back[3];
  43.   int start_lineno;
  44. public:
  45.   top_input(FILE *);
  46.   int get();
  47.   int peek();
  48.   int get_location(const char **, int *);
  49. };
  50.  
  51. top_input::top_input(FILE *p) : fp(p), bol(1), eof(0)
  52. {
  53.   push_back[0] = push_back[1] = push_back[2] = EOF;
  54.   start_lineno = current_lineno;
  55. }
  56.  
  57. int top_input::get()
  58. {
  59.   if (eof)
  60.     return EOF;
  61.   if (push_back[2] != EOF) {
  62.     int c = push_back[2];
  63.     push_back[2] = EOF;
  64.     return c;
  65.   }
  66.   else if (push_back[1] != EOF) {
  67.     int c = push_back[1];
  68.     push_back[1] = EOF;
  69.     return c;
  70.   }
  71.   else if (push_back[0] != EOF) {
  72.     int c = push_back[0];
  73.     push_back[0] = EOF;
  74.     return c;
  75.   }
  76.   int c = getc(fp);
  77.   while (illegal_input_char(c)) {
  78.     error("illegal input character code %1", int(c));
  79.     c = getc(fp);
  80.     bol = 0;
  81.   }
  82.   if (bol && c == '.') {
  83.     c = getc(fp);
  84.     if (c == 'P') {
  85.       c = getc(fp);
  86.       if (c == 'F' || c == 'E') {
  87.     int d = getc(fp);
  88.     if (d != EOF)
  89.       ungetc(d, fp);
  90.     if (d == EOF || d == ' ' || d == '\n' || compatible_flag) {
  91.       eof = 1;
  92.       flyback_flag = c == 'F';
  93.       return EOF;
  94.     }
  95.     push_back[0] = c;
  96.     push_back[1] = 'P';
  97.     return '.';
  98.       }
  99.       if (c == 'S') {
  100.     c = getc(fp);
  101.     if (c != EOF)
  102.       ungetc(c, fp);
  103.     if (c == EOF || c == ' ' || c == '\n' || compatible_flag) {
  104.       error("nested .PS");
  105.       eof = 1;
  106.       return EOF;
  107.     }
  108.     push_back[0] = 'S';
  109.     push_back[1] = 'P';
  110.     return '.';
  111.       }
  112.       if (c != EOF)
  113.     ungetc(c, fp);
  114.       push_back[0] = 'P';
  115.       return '.';
  116.     }
  117.     else {
  118.       if (c != EOF)
  119.     ungetc(c, fp);
  120.       return '.';
  121.     }
  122.   }
  123.   if (c == '\n') {
  124.     bol = 1;
  125.     current_lineno++;
  126.     return '\n';
  127.   }
  128.   bol = 0;
  129.   if (c == EOF) {
  130.     eof = 1;
  131.     error("end of file before .PE or .PF");
  132.     error_with_file_and_line(current_filename, start_lineno - 1,
  133.                  ".PS was here");
  134.   }
  135.   return c;
  136. }
  137.  
  138. int top_input::peek()
  139. {
  140.   if (eof)
  141.     return EOF;
  142.   if (push_back[2] != EOF)
  143.     return push_back[2];
  144.   if (push_back[1] != EOF)
  145.     return push_back[1];
  146.   if (push_back[0] != EOF)
  147.     return push_back[0];
  148.   int c = getc(fp);
  149.   while (illegal_input_char(c)) {
  150.     error("illegal input character code %1", int(c));
  151.     c = getc(fp);
  152.     bol = 0;
  153.   }
  154.   if (bol && c == '.') {
  155.     c = getc(fp);
  156.     if (c == 'P') {
  157.       c = getc(fp);
  158.       if (c == 'F' || c == 'E') {
  159.     int d = getc(fp);
  160.     if (d != EOF)
  161.       ungetc(d, fp);
  162.     if (d == EOF || d == ' ' || d == '\n' || compatible_flag) {
  163.       eof = 1;
  164.       flyback_flag = c == 'F';
  165.       return EOF;
  166.     }
  167.     push_back[0] = c;
  168.     push_back[1] = 'P';
  169.     push_back[2] = '.';
  170.     return '.';
  171.       }
  172.       if (c == 'S') {
  173.     c = getc(fp);
  174.     if (c != EOF)
  175.       ungetc(c, fp);
  176.     if (c == EOF || c == ' ' || c == '\n' || compatible_flag) {
  177.       error("nested .PS");
  178.       eof = 1;
  179.       return EOF;
  180.     }
  181.     push_back[0] = 'S';
  182.     push_back[1] = 'P';
  183.     push_back[2] = '.';
  184.     return '.';
  185.       }
  186.       if (c != EOF)
  187.     ungetc(c, fp);
  188.       push_back[0] = 'P';
  189.       push_back[1] = '.';
  190.       return '.';
  191.     }
  192.     else {
  193.       if (c != EOF)
  194.     ungetc(c, fp);
  195.       push_back[0] = '.';
  196.       return '.';
  197.     }
  198.   }
  199.   if (c != EOF)
  200.     ungetc(c, fp);
  201.   if (c == '\n')
  202.     return '\n';
  203.   return c;
  204. }
  205.  
  206. int top_input::get_location(const char **filenamep, int *linenop)
  207. {
  208.   *filenamep = current_filename;
  209.   *linenop = current_lineno;
  210.   return 1;
  211. }
  212.  
  213. void do_picture(FILE *fp)
  214. {
  215.   flyback_flag = 0;
  216.   int c;
  217.   while ((c = getc(fp)) == ' ')
  218.     ;
  219.   if (c == '<') {
  220.     string filename;
  221.     while ((c = getc(fp)) != EOF) {
  222.       if (c == '\n') {
  223.     current_lineno++;
  224.     break;
  225.       }
  226.       filename += char(c);
  227.     }
  228.     filename += '\0';
  229.     const char *old_filename = current_filename;
  230.     int old_lineno = current_lineno;
  231.     // filenames must be permanent
  232.     do_file(strsave(filename.contents()));
  233.     current_filename = old_filename;
  234.     current_lineno = old_lineno;
  235.     out->set_location(current_filename, current_lineno);
  236.   }
  237.   else {
  238.     out->set_location(current_filename, current_lineno);
  239.     string start_line;
  240.     while (c != EOF) {
  241.       if (c == '\n') {
  242.     current_lineno++;
  243.     break;
  244.       }
  245.       start_line += c;
  246.       c = getc(fp);
  247.     }
  248.     if (c == EOF)
  249.       return;
  250.     start_line += '\0';
  251.     double wid, ht;
  252.     switch (sscanf(&start_line[0], "%lf %lf", &wid, &ht)) {
  253.     case 1:
  254.       ht = 0.0;
  255.       break;
  256.     case 2:
  257.       break;
  258.     default:
  259.       ht = wid = 0.0;
  260.       break;
  261.     }
  262.     out->set_desired_width_height(wid, ht);
  263.     out->set_args(start_line.contents());
  264.     lex_init(new top_input(fp));
  265.     if (yyparse())
  266.       lex_error("giving up on this picture");
  267.     parse_cleanup();
  268.     lex_cleanup();
  269.  
  270.     // skip the rest of the .PF/.PE line
  271.     while ((c = getc(fp)) != EOF && c != '\n')
  272.       ;
  273.     if (c == '\n')
  274.       current_lineno++;
  275.     out->set_location(current_filename, current_lineno);
  276.   }
  277. }
  278.  
  279. void do_file(const char *filename)
  280. {
  281.   FILE *fp;
  282.   if (strcmp(filename, "-") == 0)
  283.     fp = stdin;
  284.   else {
  285.     fp = fopen(filename, "r");
  286.     if (fp == 0)
  287.       fatal("can't open `%1': %2", filename, strerror(errno));
  288.   }
  289.   out->set_location(filename, 1);
  290.   current_filename = filename;
  291.   current_lineno = 1;
  292.   enum { START, MIDDLE, HAD_DOT, HAD_P, HAD_PS, HAD_l, HAD_lf } state = START;
  293.   for (;;) {
  294.     int c = getc(fp);
  295.     if (c == EOF)
  296.       break;
  297.     switch (state) {
  298.     case START:
  299.       if (c == '.')
  300.     state = HAD_DOT;
  301.       else {
  302.     putchar(c);
  303.     if (c == '\n') {
  304.       current_lineno++;
  305.       state = START;
  306.     }
  307.     else
  308.       state = MIDDLE;
  309.       }
  310.       break;
  311.     case MIDDLE:
  312.       putchar(c);
  313.       if (c == '\n') {
  314.     current_lineno++;
  315.     state = START;
  316.       }
  317.       break;
  318.     case HAD_DOT:
  319.       if (c == 'P')
  320.     state = HAD_P;
  321.       else if (lf_flag && c == 'l')
  322.     state = HAD_l;
  323.       else {
  324.     putchar('.');
  325.     putchar(c);
  326.     if (c == '\n') {
  327.       current_lineno++;
  328.       state = START;
  329.     }
  330.     else
  331.       state = MIDDLE;
  332.       }
  333.       break;
  334.     case HAD_P:
  335.       if (c == 'S')
  336.     state = HAD_PS;
  337.       else  {
  338.     putchar('.');
  339.     putchar('P');
  340.     putchar(c);
  341.     if (c == '\n') {
  342.       current_lineno++;
  343.       state = START;
  344.     }
  345.     else
  346.       state = MIDDLE;
  347.       }
  348.       break;
  349.     case HAD_PS:
  350.       if (c == ' ' || c == '\n' || compatible_flag) {
  351.     ungetc(c, fp);
  352.     do_picture(fp);
  353.     state = START;
  354.       }
  355.       else {
  356.     fputs(".PS", stdout);
  357.     putchar(c);
  358.     state = MIDDLE;
  359.       }
  360.       break;
  361.     case HAD_l:
  362.       if (c == 'f')
  363.     state = HAD_lf;
  364.       else {
  365.     putchar('.');
  366.     putchar('l');
  367.     putchar(c);
  368.     if (c == '\n') {
  369.       current_lineno++;
  370.       state = START;
  371.     }
  372.     else
  373.       state = MIDDLE;
  374.       }
  375.       break;
  376.     case HAD_lf:
  377.       if (c == ' ' || c == '\n' || compatible_flag) {
  378.     string line;
  379.     while (c != EOF) {
  380.       line += c;
  381.       if (c == '\n') {
  382.         current_lineno++;
  383.         break;
  384.       }
  385.       c = getc(fp);
  386.     }
  387.     line += '\0';
  388.     interpret_lf_args(line.contents());
  389.     printf(".lf%s", line.contents());
  390.     state = START;
  391.       }
  392.       else {
  393.     fputs(".lf", stdout);
  394.     putchar(c);
  395.     state = MIDDLE;
  396.       }
  397.       break;
  398.     default:
  399.       assert(0);
  400.     }
  401.   }
  402.   switch (state) {
  403.   case START:
  404.     break;
  405.   case MIDDLE:
  406.     putchar('\n');
  407.     break;
  408.   case HAD_DOT:
  409.     fputs(".\n", stdout);
  410.     break;
  411.   case HAD_P:
  412.     fputs(".P\n", stdout);
  413.     break;
  414.   case HAD_PS:
  415.     fputs(".PS\n", stdout);
  416.     break;
  417.   case HAD_l:
  418.     fputs(".l\n", stdout);
  419.     break;
  420.   case HAD_lf:
  421.     fputs(".lf\n", stdout);
  422.     break;
  423.   }
  424.   if (fp != stdin)
  425.     fclose(fp);
  426. }
  427.  
  428. #ifdef FIG_SUPPORT
  429. void do_whole_file(const char *filename)
  430. {
  431.   // Do not set current_filename.
  432.   FILE *fp;
  433.   if (strcmp(filename, "-") == 0)
  434.     fp = stdin;
  435.   else {
  436.     fp = fopen(filename, "r");
  437.     if (fp == 0)
  438.       fatal("can't open `%1': %2", filename, strerror(errno));
  439.   }
  440.   lex_init(new file_input(fp, filename));
  441.   yyparse();
  442.   parse_cleanup();
  443.   lex_cleanup();
  444. }
  445. #endif
  446.  
  447. void usage()
  448. {
  449.   fprintf(stderr, "usage: %s [ -pxvzC ] [ filename ... ]\n", program_name);
  450. #ifdef TEX_SUPPORT
  451.   fprintf(stderr, "       %s -t [ -cvzC ] [ filename ... ]\n", program_name);
  452. #endif
  453. #ifdef FIG_SUPPORT
  454.   fprintf(stderr, "       %s -f [ -v ] [ filename ]\n", program_name);
  455. #endif
  456.   exit(1);
  457. }
  458.  
  459. int main(int argc, char **argv)
  460. {
  461.   program_name = argv[0];
  462.   static char stderr_buf[BUFSIZ];
  463.   setbuf(stderr, stderr_buf);
  464.   int opt;
  465. #ifdef TEX_SUPPORT
  466.   int tex_flag = 0;
  467.   int tpic_flag = 0;
  468. #endif
  469.   int grops_flag = 0;
  470. #ifdef FIG_SUPPORT
  471.   int whole_file_flag = 0;
  472.   int fig_flag = 0;
  473. #endif
  474.   while ((opt = getopt(argc, argv, "T:CDtcvxzpf")) != EOF)
  475.     switch (opt) {
  476.     case 'C':
  477.       compatible_flag = 1;
  478.       break;
  479.     case 'D':
  480.     case 'T':
  481.       break;
  482.     case 'f':
  483. #ifdef FIG_SUPPORT
  484.       whole_file_flag++;
  485.       fig_flag++;
  486. #else
  487.       fatal("fig support not included");
  488. #endif
  489.       break;
  490.     case 'p':
  491.       grops_flag++;
  492.       break;
  493.     case 't':
  494. #ifdef TEX_SUPPORT
  495.       tex_flag++;
  496. #else
  497.       fatal("TeX support not included");
  498. #endif
  499.       break;
  500.     case 'c':
  501. #ifdef TEX_SUPPORT
  502.       tpic_flag++;
  503. #else
  504.       fatal("TeX support not included");
  505. #endif
  506.       break;
  507.     case 'v':
  508.       {
  509.     extern const char *version_string;
  510.     fprintf(stderr, "GNU pic version %s\n", version_string);
  511.     fflush(stderr);
  512.     break;
  513.       }
  514.     case 'x':
  515.       driver_extension_flag++;
  516.       /* fall through */
  517.     case 'z':
  518.       // zero length lines will be printed as dots
  519.       zero_length_line_flag++;
  520.       break;
  521.     case '?':
  522.       usage();
  523.       break;
  524.     default:
  525.       assert(0);
  526.     }
  527.   parse_init();
  528.   if (grops_flag)
  529.     out = make_grops_output();
  530. #ifdef TEX_SUPPORT
  531.   else if (tpic_flag) {
  532.     out = make_tpic_output();
  533.     lf_flag = 0;
  534.   }
  535.   else if (tex_flag) {
  536.     out = make_tex_output();
  537.     command_char = '\\';
  538.     lf_flag = 0;
  539.   }
  540. #endif
  541. #ifdef FIG_SUPPORT
  542.   else if (fig_flag)
  543.     out = make_fig_output();
  544. #endif
  545.   else
  546.     out = make_troff_output();
  547. #ifdef FIG_SUPPORT
  548.   if (whole_file_flag) {
  549.     if (optind >= argc)
  550.       do_whole_file("-");
  551.     else if (argc - optind > 1)
  552.       usage();
  553.     else
  554.       do_whole_file(argv[optind]);
  555.   }
  556.   else {
  557. #endif
  558.     if (optind >= argc)
  559.       do_file("-");
  560.     else
  561.       for (int i = optind; i < argc; i++)
  562.     do_file(argv[i]);
  563. #ifdef FIG_SUPPORT
  564.   }
  565. #endif
  566.   delete out;
  567.   if (ferror(stdout) || fflush(stdout) < 0)
  568.     fatal("output error");
  569.   exit(0);
  570. }
  571.  
  572.