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