home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / gnu / groff-1.09-src.lha / src / amiga / groff-1.09 / pic / main.cc < prev    next >
C/C++ Source or Header  |  1993-05-27  |  12KB  |  612 lines

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