home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / groff / grops / ps.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-30  |  46.6 KB  |  1,973 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 "driver.h"
  22. #include "stringclass.h"
  23. #include "cset.h"
  24.  
  25. extern "C" {
  26.   // Sun's stdlib.h fails to declare this.
  27.   char *mktemp(char *);
  28. }
  29.  
  30. static int landscape_flag = 0;
  31. static int ncopies = 1;
  32. static int linewidth = -1;
  33.  
  34. #define DEFAULT_LINEWIDTH 40    /* in ems/1000 */
  35. #define FILL_MAX 1000
  36.  
  37. // Maximum number of definitions in the prologue (used for sizing the
  38. // dictionary.)
  39.  
  40. const int MAX_PROLOGUE_DEFS = 50;
  41. const char *const dict_name = "grops";
  42. const char *const defs_dict_name = "DEFS";
  43. const int DEFS_DICT_SPARE = 50;
  44.  
  45. #define PROLOGUE "prologue"
  46.  
  47. double degrees(double r)
  48. {
  49.   return r*180.0/M_PI;
  50. }
  51.  
  52. double radians(double d)
  53. {
  54.   return d*M_PI/180.0;
  55. }
  56.  
  57. inline double transform_fill(int fill)
  58. {
  59.   return 1 - fill/double(FILL_MAX);
  60. }
  61.  
  62. class ps_output {
  63. public:
  64.   ps_output(FILE *, int max_line_length);
  65.   ps_output &put_string(const char *, int);
  66.   ps_output &put_number(int);
  67.   ps_output &put_fix_number(int);
  68.   ps_output &put_float(double);
  69.   ps_output &put_symbol(const char *);
  70.   ps_output &put_literal_symbol(const char *);
  71.   ps_output &set_fixed_point(int);
  72.   ps_output &simple_comment(const char *);
  73.   ps_output &begin_comment(const char *);
  74.   ps_output &comment_arg(const char *);
  75.   ps_output &end_comment();
  76.   ps_output &set_file(FILE *);
  77.   ps_output &include_file(FILE *);
  78.   ps_output ©_file(FILE *);
  79.   ps_output &end_line();
  80.   ps_output &put_delimiter(char);
  81.   ps_output &special(const char *);
  82. private:
  83.   FILE *fp;
  84.   int col;
  85.   int max_line_length;        // not including newline
  86.   int need_space;
  87.   int fixed_point;
  88. };
  89.  
  90. ps_output::ps_output(FILE *f, int n)
  91. : fp(f), max_line_length(n), col(0), need_space(0), fixed_point(0)
  92. {
  93. }
  94.  
  95. ps_output &ps_output::set_file(FILE *f)
  96. {
  97.   fp = f;
  98.   col = 0;
  99.   return *this;
  100. }
  101.  
  102. ps_output &ps_output::include_file(FILE *infp)
  103. {
  104.   if (col != 0)
  105.     putc('\n', fp);
  106.   int c;
  107. #ifdef BROKEN_SPOOLER
  108.   // Strip the first line if it's a comment.  I believe
  109.   // some spoolers get confused by %! in the middle of a file.
  110.   if ((c = getc(infp)) == '%') {
  111.     while ((c = getc(infp)) != '\n' && c != '\r' && c != EOF)
  112.       ;
  113.   }
  114.   else if (c != EOF)
  115.     ungetc(c, infp);
  116. #endif /* BROKEN_SPOOLER */
  117.   // We strip out lines beginning with STRIPENDUM.
  118. #ifdef BROKEN_SPOOLER
  119. #define STRIPENDUM "%%"
  120. #else
  121. #define STRIPENDUM "%%IncludeFont:"
  122. #endif
  123.   // Index into STRIPENDUM of next character to be matched.
  124.   int match = 0;
  125.   while ((c = getc(infp)) != EOF) {
  126.     if (match >= 0) {
  127.       if (c == STRIPENDUM[match]) {
  128.     if (++match == sizeof(STRIPENDUM) - 1) {
  129.       match = -1;
  130.       while ((c = getc(infp)) != EOF)
  131.         if (c == '\r' || c == '\n') {
  132.           match = 0;
  133.           break;
  134.         }
  135.     }
  136.       }
  137.       else {
  138.     for (int i = 0; i < match; i++)
  139.       putc(STRIPENDUM[i], fp);
  140.     putc(c, fp);
  141.     match = (c == '\n' || c == '\r' ? 0 : -1);
  142.       }
  143.     }
  144.     else {
  145.       putc(c, fp);
  146.       match = (c == '\n' || c == '\r' ? 0 : -1);
  147.     }
  148.   }
  149.   for (int i = 0; i < match; i++)
  150.     putc(STRIPENDUM[i], fp);
  151.   if (match != 0)
  152.     putc('\n', fp);
  153.   int lastc = '\n';
  154.   while ((c = getc(infp)) != EOF) {
  155.     putc(c, fp);
  156.     lastc = c;
  157.   }
  158.   if (lastc != '\n')
  159.     putc('\n', fp);
  160.   col = 0;
  161.   need_space = 0;
  162.   return *this;
  163. }
  164.  
  165. ps_output &ps_output::copy_file(FILE *infp)
  166. {
  167.   int c;
  168.   while ((c = getc(infp)) != EOF)
  169.     putc(c, fp);
  170.   return *this;
  171. }
  172.  
  173. ps_output &ps_output::end_line()
  174. {
  175.   if (col != 0) {
  176.     putc('\n', fp);
  177.     col = 0;
  178.   }
  179.   return *this;
  180. }
  181.  
  182. ps_output &ps_output::special(const char *s)
  183. {
  184.   if (s == 0 || *s == '\0')
  185.     return *this;
  186.   if (col != 0) {
  187.     putc('\n', fp);
  188.     col = 0;
  189.   }
  190.   fputs(s, fp);
  191.   if (strchr(s, '\0')[-1] != '\n')
  192.     putc('\n', fp);
  193.   need_space = 0;
  194.   return *this;
  195. }
  196.  
  197. ps_output &ps_output::simple_comment(const char *s)
  198. {
  199.   if (col != 0)
  200.     putc('\n', fp);
  201.   putc('%', fp);
  202.   putc('%', fp);
  203.   fputs(s, fp);
  204.   putc('\n', fp);
  205.   col = 0;
  206.   need_space = 0;
  207.   return *this;
  208. }
  209.  
  210. ps_output &ps_output::begin_comment(const char *s)
  211. {
  212.   if (col != 0)
  213.     putc('\n', fp);
  214.   putc('%', fp);
  215.   putc('%', fp);
  216.   fputs(s, fp);
  217.   col = 2 + strlen(s);
  218.   return *this;
  219. }
  220.  
  221. ps_output &ps_output::end_comment()
  222. {
  223.   if (col != 0) {
  224.     putc('\n', fp);
  225.     col = 0;
  226.   }
  227.   need_space = 0;
  228.   return *this;
  229. }
  230.  
  231. ps_output &ps_output::comment_arg(const char *s)
  232. {
  233.   int len = strlen(s);
  234.   if (col + len + 1 > max_line_length) {
  235.     putc('\n', fp);
  236.     fputs("%%+", fp);
  237.     col = 3;
  238.   }
  239.   putc(' ',  fp);
  240.   fputs(s, fp);
  241.   col += len + 1;
  242.   return *this;
  243. }
  244.  
  245. ps_output &ps_output::set_fixed_point(int n)
  246. {
  247.   assert(n >= 0 && n <= 10);
  248.   fixed_point = n;
  249.   return *this;
  250. }
  251.  
  252. ps_output &ps_output::put_delimiter(char c)
  253. {
  254.   if (col + 1 > max_line_length) {
  255.     putc('\n', fp);
  256.     col = 0;
  257.   }
  258.   putc(c, fp);
  259.   col++;
  260.   need_space = 0;
  261.   return *this;
  262. }
  263.  
  264. ps_output &ps_output::put_string(const char *s, int n)
  265. {
  266.   int len = 0;
  267.   for (int i = 0; i < n; i++) {
  268.     char c = s[i];
  269.     if (isascii(c) && isprint(c)) {
  270.       if (c == '(' || c == ')' || c == '\\')
  271.     len += 2;
  272.       else
  273.     len += 1;
  274.     }
  275.     else
  276.       len += 4;
  277.   }
  278.   if (len > n*2) {
  279.     if (col + n*2 + 2 > max_line_length && n*2 + 2 <= max_line_length) {
  280.       putc('\n', fp);
  281.       col = 0;
  282.     }
  283.     if (col + 1 > max_line_length) {
  284.       putc('\n', fp);
  285.       col = 0;
  286.     }
  287.     putc('<', fp);
  288.     col++;
  289.     for (i = 0; i < n; i++) {
  290.       if (col + 2 > max_line_length) {
  291.     putc('\n', fp);
  292.     col = 0;
  293.       }
  294.       fprintf(fp, "%02x", s[i] & 0377);
  295.       col += 2;
  296.     }
  297.     putc('>', fp);
  298.     col++;
  299.   }
  300.   else {
  301.     if (col + len + 2 > max_line_length && len + 2 <= max_line_length) {
  302.       putc('\n', fp);
  303.       col = 0;
  304.     }
  305.     if (col + 2 > max_line_length) {
  306.       putc('\n', fp);
  307.       col = 0;
  308.     }
  309.     putc('(', fp);
  310.     col++;
  311.     for (i = 0; i < n; i++) {
  312.       char c = s[i];
  313.       if (isascii(c) && isprint(c)) {
  314.     if (c == '(' || c == ')' || c == '\\')
  315.       len = 2;
  316.     else
  317.       len = 1;
  318.       }
  319.       else
  320.     len = 4;
  321.       if (col + len + 1 > max_line_length) {
  322.     putc('\\', fp);
  323.     putc('\n', fp);
  324.     col = 0;
  325.       }
  326.       switch (len) {
  327.       case 1:
  328.     putc(c, fp);
  329.     break;
  330.       case 2:
  331.     putc('\\', fp);
  332.     putc(c, fp);
  333.     break;
  334.       case 4:
  335.     fprintf(fp, "\\%03o", c & 0377);
  336.     break;
  337.       default:
  338.     assert(0);
  339.       }
  340.       col += len;
  341.     }
  342.     putc(')', fp);
  343.     col++;
  344.   }
  345.   need_space = 0;
  346.   return *this;
  347. }
  348.  
  349. ps_output &ps_output::put_number(int n)
  350. {
  351.   char buf[1 + INT_DIGITS + 1];
  352.   sprintf(buf, "%d", n);
  353.   int len = strlen(buf);
  354.   if (col > 0 && col + len + need_space > max_line_length) {
  355.     putc('\n', fp);
  356.     col = 0;
  357.     need_space = 0;
  358.   }
  359.   if (need_space) {
  360.     putc(' ', fp);
  361.     col++;
  362.   }
  363.   fputs(buf, fp);
  364.   col += len;
  365.   need_space = 1;
  366.   return *this;
  367. }
  368.  
  369.  
  370. ps_output &ps_output::put_fix_number(int i)
  371. {
  372.   const char *p = iftoa(i, fixed_point);
  373.   int len = strlen(p);
  374.   if (col > 0 && col + len + need_space > max_line_length) {
  375.     putc('\n', fp);
  376.     col = 0;
  377.     need_space = 0;
  378.   }
  379.   if (need_space) {
  380.     putc(' ', fp);
  381.     col++;
  382.   }
  383.   fputs(p, fp);
  384.   col += len;
  385.   need_space = 1;
  386.   return *this;
  387. }
  388.  
  389. ps_output &ps_output::put_float(double d)
  390. {
  391.   char buf[128];
  392.   sprintf(buf, "%.4f", d);
  393.   int len = strlen(buf);
  394.   if (col > 0 && col + len + need_space > max_line_length) {
  395.     putc('\n', fp);
  396.     col = 0;
  397.     need_space = 0;
  398.   }
  399.   if (need_space) {
  400.     putc(' ', fp);
  401.     col++;
  402.   }
  403.   fputs(buf, fp);
  404.   col += len;
  405.   need_space = 1;
  406.   return *this;
  407. }
  408.  
  409. ps_output &ps_output::put_symbol(const char *s)
  410. {
  411.   int len = strlen(s);
  412.   if (col > 0 && col + len + need_space > max_line_length) {
  413.     putc('\n', fp);
  414.     col = 0;
  415.     need_space = 0;
  416.   }
  417.   if (need_space) {
  418.     putc(' ', fp);
  419.     col++;
  420.   }
  421.   fputs(s, fp);
  422.   col += len;
  423.   need_space = 1;
  424.   return *this;
  425. }
  426.  
  427. ps_output &ps_output::put_literal_symbol(const char *s)
  428. {
  429.   int len = strlen(s);
  430.   if (col > 0 && col + len + 1 > max_line_length) {
  431.     putc('\n', fp);
  432.     col = 0;
  433.   }
  434.   putc('/', fp);
  435.   fputs(s, fp);
  436.   col += len + 1;
  437.   need_space = 1;
  438.   return *this;
  439. }
  440.  
  441. class ps_font : public font {
  442.   ps_font(const char *);
  443. public:
  444.   int encoding_index;
  445.   char *encoding;
  446.   char *reencoded_name;
  447.   ~ps_font();
  448.   void handle_unknown_font_command(int argc, const char **argv);
  449.   static ps_font *load_ps_font(const char *);
  450. };
  451.  
  452. ps_font *ps_font::load_ps_font(const char *s)
  453. {
  454.   ps_font *f = new ps_font(s);
  455.   if (!f->load()) {
  456.     delete f;
  457.     return 0;
  458.   }
  459.   return f;
  460. }
  461.  
  462. ps_font::ps_font(const char *nm)
  463. : font(nm), encoding(0), reencoded_name(0), encoding_index(-1)
  464. {
  465. }
  466.  
  467. ps_font::~ps_font()
  468. {
  469.   delete encoding;
  470.   delete reencoded_name;
  471. }
  472.  
  473. void ps_font::handle_unknown_font_command(int argc, const char **argv)
  474. {
  475.   if (strcmp(argv[0], "encoding") == 0) {
  476.     if (argc != 2)
  477.       error("`encoding' command requires exactly 1 argument");
  478.     else
  479.       encoding = strsave(argv[1]);
  480.   }
  481. }
  482.  
  483.  
  484. struct style {
  485.   font *f;
  486.   int point_size;
  487.   int height;
  488.   int slant;
  489.   style();
  490.   style(font *, int, int, int);
  491.   int operator==(const style &) const;
  492.   int operator!=(const style &) const;
  493. };
  494.  
  495. style::style() : f(0)
  496. {
  497. }
  498.  
  499. style::style(font *p, int sz, int h, int sl)
  500. : f(p), point_size(sz), height(h), slant(sl)
  501. {
  502. }
  503.  
  504. int style::operator==(const style &s) const
  505. {
  506.   return (f == s.f && point_size == s.point_size
  507.       && height == s.height && slant == s.slant);
  508. }
  509.  
  510. int style::operator!=(const style &s) const
  511. {
  512.   return !(*this == s);
  513. }
  514.  
  515. struct depend_list;
  516.  
  517. struct document_font {
  518.   enum { LISTED = 01, NEEDED = 02, SUPPLIED = 04 };
  519.   char *name;
  520.   char *filename;
  521.   int flags;
  522.   document_font *next;
  523.   depend_list *depends_on;
  524.   int mark;
  525.   document_font(const char *);
  526.   ~document_font();
  527.   void download(ps_output &);
  528. };
  529.  
  530. struct depend_list {
  531.   document_font *p;
  532.   depend_list *next;
  533. };
  534.  
  535.  
  536. class ps_printer : public printer {
  537.   FILE *tempfp;
  538.   ps_output out;
  539.   int res;
  540.   int space_char_index;
  541.   int pages_output;
  542.   int paper_length;
  543.   int equalise_spaces;
  544.   enum { SBUF_SIZE = 256 };
  545.   char sbuf[SBUF_SIZE];
  546.   int sbuf_len;
  547.   int sbuf_start_hpos;
  548.   int sbuf_vpos;
  549.   int sbuf_end_hpos;
  550.   int sbuf_space_width;
  551.   int sbuf_space_count;
  552.   int sbuf_space_diff_count;
  553.   int sbuf_space_code;
  554.   int sbuf_kern;
  555.   style sbuf_style;
  556.   style output_style;
  557.   int output_hpos;
  558.   int output_vpos;
  559.   int output_draw_point_size;
  560.   int line_thickness;
  561.   int output_line_thickness;
  562.   int fill;
  563.   unsigned char output_space_code;
  564.   enum { MAX_DEFINED_STYLES = 50 };
  565.   style defined_styles[MAX_DEFINED_STYLES];
  566.   int ndefined_styles;
  567.   int next_encoding_index;
  568.   string defs;
  569.   int ndefs;
  570.   document_font *doc_fonts;
  571.  
  572.   void flush_sbuf();
  573.   void set_style(const style &);
  574.   void set_space_code(unsigned char c);
  575.   int set_encoding_index(ps_font *);
  576.   void do_exec(char *, const environment *);
  577.   void do_import(char *, const environment *);
  578.   void do_def(char *, const environment *);
  579.   void do_mdef(char *, const environment *);
  580.   void do_file(char *, const environment *);
  581.   void set_line_thickness(const environment *);
  582.   void fill_path();
  583.   void merge_download_fonts();
  584.   void merge_import_fonts(FILE *);
  585.   void merge_ps_fonts();
  586.   void print_font_comment();
  587.   void print_supplied_font_comment();
  588.   void print_needed_font_comment();
  589.   void print_include_font_comments();
  590.   document_font *lookup_doc_font(const char *);
  591.   void encode_fonts();
  592.   void download_fonts();
  593.   void define_encoding(const char *, int);
  594.   void reencode_font(ps_font *);
  595.   void read_download_file();
  596. public:
  597.   ps_printer();
  598.   ~ps_printer();
  599.   void set_char(int i, font *f, const environment *env, int w);
  600.   void draw(int code, int *p, int np, const environment *env);
  601.   void begin_page(int);
  602.   void end_page();
  603.   void special(char *arg, const environment *env);
  604.   font *make_font(const char *);
  605.   void end_of_line();
  606. };
  607.  
  608. ps_printer::ps_printer()
  609. : pages_output(0),
  610.   sbuf_len(0),
  611.   output_hpos(-1),
  612.   output_vpos(-1),
  613.   out(0, 79),
  614.   ndefined_styles(0),
  615.   next_encoding_index(0),
  616.   line_thickness(-1),
  617.   fill(FILL_MAX + 1),
  618.   ndefs(0),
  619.   doc_fonts(0)
  620. {
  621.   static char temp_filename[] = "/tmp/gropsXXXXXX";
  622.   mktemp(temp_filename);
  623.   tempfp = fopen(temp_filename, "w+");
  624.   if (tempfp == 0)
  625.     fatal("can't open temporary file `%1': %2",
  626.       temp_filename, strerror(errno));
  627.   if (unlink(temp_filename) < 0)
  628.     error("can't unlink `%1': %2", temp_filename, strerror(errno));
  629.   out.set_file(tempfp);
  630.   if (linewidth < 0)
  631.     linewidth = DEFAULT_LINEWIDTH;
  632.   if (font::hor != 1)
  633.     fatal("horizontal resolution must be 1");
  634.   if (font::vert != 1)
  635.     fatal("vertical resolution must be 1");
  636.   if (font::res % (font::sizescale*72) != 0)
  637.     fatal("res must be a multiple of 72*sizescale");
  638.   int r = font::res;
  639.   int point = 0;
  640.   while (r % 10 == 0) {
  641.     r /= 10;
  642.     point++;
  643.   }
  644.   res = r;
  645.   out.set_fixed_point(point);
  646.   space_char_index = font::name_to_index("space");
  647.   paper_length = font::paperlength;
  648.   if (paper_length == 0)
  649.     paper_length = 11*font::res;
  650.   equalise_spaces = font::res >= 72000;
  651. }
  652.  
  653. int ps_printer::set_encoding_index(ps_font *f)
  654. {
  655.   if (f->encoding_index >= 0)
  656.     return f->encoding_index;
  657.   for (font_pointer_list *p = font_list; p; p = p->next)
  658.     if (p->p != f) {
  659.       char *encoding = ((ps_font *)p->p)->encoding;
  660.       int encoding_index = ((ps_font *)p->p)->encoding_index;
  661.       if (encoding != 0 && encoding_index >= 0 
  662.       && strcmp(f->encoding, encoding) == 0) {
  663.     return f->encoding_index = encoding_index;
  664.       }
  665.     }
  666.   return f->encoding_index = next_encoding_index++;
  667. }
  668.  
  669. void ps_printer::set_char(int i, font *f, const environment *env, int w)
  670. {
  671.   if (i == space_char_index)
  672.     return;
  673.   unsigned char code = f->get_code(i);
  674.   style sty(f, env->size, env->height, env->slant);
  675.   if (sty.slant != 0) {
  676.     if (sty.slant > 80 || sty.slant < -80) {
  677.       error("silly slant `%1' degrees", sty.slant);
  678.       sty.slant = 0;
  679.     }
  680.   }
  681.   if (sbuf_len > 0) {
  682.     if (sbuf_len < SBUF_SIZE
  683.     && sty == sbuf_style
  684.     && sbuf_vpos == env->vpos) {
  685.       if (sbuf_end_hpos == env->hpos) {
  686.     sbuf[sbuf_len++] = code;
  687.     sbuf_end_hpos += w + sbuf_kern;
  688.     return;
  689.       }
  690.       if (sbuf_len == 1 && sbuf_kern == 0) {
  691.     sbuf_kern = env->hpos - sbuf_end_hpos;
  692.     sbuf_end_hpos = env->hpos + sbuf_kern + w;
  693.     sbuf[sbuf_len++] = code;
  694.     return;
  695.       }
  696.       /* If sbuf_end_hpos - sbuf_kern == env->hpos, we are better off
  697.      starting a new string. */
  698.       if (sbuf_len < SBUF_SIZE - 1 && env->hpos >= sbuf_end_hpos
  699.       && (sbuf_kern == 0 || sbuf_end_hpos - sbuf_kern != env->hpos)) {
  700.     if (sbuf_space_code < 0) {
  701.       if (f->contains(space_char_index)) {
  702.         sbuf_space_code = f->get_code(space_char_index);
  703.         sbuf_space_width = env->hpos - sbuf_end_hpos;
  704.         sbuf_end_hpos = env->hpos + w + sbuf_kern;
  705.         sbuf[sbuf_len++] = sbuf_space_code;
  706.         sbuf[sbuf_len++] = code;
  707.         sbuf_space_count++;
  708.         return;
  709.       }
  710.     }
  711.     else {
  712.       int diff = env->hpos - sbuf_end_hpos - sbuf_space_width;
  713.       if (diff == 0 || (equalise_spaces && (diff == 1 || diff == -1))) {
  714.         sbuf_end_hpos = env->hpos + w + sbuf_kern;
  715.         sbuf[sbuf_len++] = sbuf_space_code;
  716.         sbuf[sbuf_len++] = code;
  717.         sbuf_space_count++;
  718.         if (diff == 1)
  719.           sbuf_space_diff_count++;
  720.         else if (diff == -1)
  721.           sbuf_space_diff_count--;
  722.         return;
  723.       }
  724.     }
  725.       }
  726.     }
  727.     flush_sbuf();
  728.   }
  729.   sbuf_len = 1;
  730.   sbuf[0] = code;
  731.   sbuf_end_hpos = env->hpos + w;
  732.   sbuf_start_hpos = env->hpos;
  733.   sbuf_vpos = env->vpos;
  734.   sbuf_style = sty;
  735.   sbuf_space_code = -1;
  736.   sbuf_space_width = 0;
  737.   sbuf_space_count = sbuf_space_diff_count = 0;
  738.   sbuf_kern = 0;
  739. }
  740.  
  741. int is_small_h(int n)
  742. {
  743.   return n < (font::res*2)/72 && n > -(font::res*10)/72;
  744. }
  745.  
  746. int is_small_v(int n)
  747. {
  748.   return n < (font::res*4)/72 && n > -(font::res*4)/72;
  749. }
  750.  
  751. static char *make_encoding_name(int encoding_index)
  752. {
  753.   static char buf[3 + INT_DIGITS + 1];
  754.   sprintf(buf, "ENC%d", encoding_index);
  755.   return buf;
  756. }
  757.  
  758. const char *const WS = " \t\n\r";
  759.  
  760. void ps_printer::define_encoding(const char *encoding, int encoding_index)
  761. {
  762.   char *vec[256];
  763.   for (int i = 0; i < 256; i++)
  764.     vec[i] = 0;
  765.   char *path;
  766.   FILE *fp = font::open_file(encoding, &path);
  767.   if (fp == 0)
  768.     fatal("can't open encoding file `%1'", encoding);
  769.   int lineno = 1;
  770.   char buf[256];
  771.   while (fgets(buf, 512, fp) != 0) {
  772.     char *p = buf;
  773.     while (isascii(*p) && isspace(*p))
  774.       p++;
  775.     if (*p != '#' && *p != '\0' && (p = strtok(buf, WS)) != 0) {
  776.       char *q = strtok(0, WS);
  777.       int n;
  778.       if (q == 0 || sscanf(q, "%d", &n) != 1 || n < 0 || n >= 256)
  779.     fatal_with_file_and_line(path, lineno, "bad second field");
  780.       vec[n] = new char[strlen(p) + 1];
  781.       strcpy(vec[n], p);
  782.     }
  783.     lineno++;
  784.   }
  785.   delete path;
  786.   out.put_literal_symbol(make_encoding_name(encoding_index));
  787.   out.put_delimiter('[');
  788.   for (i = 0; i < 256; i++) {
  789.     if (vec[i] == 0)
  790.       out.put_literal_symbol(".notdef");
  791.     else
  792.       out.put_literal_symbol(vec[i]);
  793.   }
  794.   out.put_delimiter(']').put_symbol("def");
  795. }
  796.  
  797. void ps_printer::reencode_font(ps_font *f)
  798. {
  799.   out.put_literal_symbol(f->reencoded_name)
  800.      .put_symbol(make_encoding_name(f->encoding_index))
  801.      .put_literal_symbol(f->get_internal_name())
  802.      .put_symbol("RE");
  803. }
  804.  
  805. void ps_printer::encode_fonts()
  806. {
  807.   if (next_encoding_index == 0)
  808.     return;
  809.   char *done_encoding = new char[next_encoding_index];
  810.   for (int i = 0; i < next_encoding_index; i++)
  811.     done_encoding[i] = 0;
  812.   for (font_pointer_list *f = font_list; f; f = f->next) {
  813.     int encoding_index = ((ps_font *)f->p)->encoding_index;
  814.     if (encoding_index >= 0) {
  815.       assert(encoding_index < next_encoding_index);
  816.       if (!done_encoding[encoding_index]) {
  817.     done_encoding[encoding_index] = 1;
  818.     define_encoding(((ps_font *)f->p)->encoding, encoding_index);
  819.       }
  820.       reencode_font((ps_font *)f->p);
  821.     }
  822.   }
  823.   delete done_encoding;
  824. }
  825.  
  826. void ps_printer::set_style(const style &sty)
  827. {
  828.   char buf[1 + INT_DIGITS + 1];
  829.   for (int i = 0; i < ndefined_styles; i++)
  830.     if (sty == defined_styles[i]) {
  831.       sprintf(buf, "F%d", i);
  832.       out.put_symbol(buf);
  833.       return;
  834.     }
  835.   if (ndefined_styles >= MAX_DEFINED_STYLES)
  836.     ndefined_styles = 0;
  837.   sprintf(buf, "F%d", ndefined_styles);
  838.   out.put_literal_symbol(buf);
  839.   const char *psname = sty.f->get_internal_name();
  840.   if (psname == 0)
  841.     fatal("no internalname specified for font `%1'", sty.f->get_name());
  842.   char *encoding = ((ps_font *)sty.f)->encoding;
  843.   if (encoding != 0) {
  844.     char *s = ((ps_font *)sty.f)->reencoded_name;
  845.     if (s == 0) {
  846.       int ei = set_encoding_index((ps_font *)sty.f);
  847.       char *tem = new char[strlen(psname) + 1 + INT_DIGITS + 1];
  848.       sprintf(tem, "%s@%d", psname, ei);
  849.       psname = tem;
  850.       ((ps_font *)sty.f)->reencoded_name = tem;
  851.     }
  852.     else
  853.       psname = s;
  854.   }
  855.   out.put_fix_number((font::res/(72*font::sizescale))*sty.point_size);
  856.   if (sty.height != 0 || sty.slant != 0) {
  857.     int h = sty.height == 0 ? sty.point_size : sty.height;
  858.     h *= font::res/(72*font::sizescale);
  859.     int c = int(h*tan(radians(sty.slant)) + .5);
  860.     out.put_fix_number(c).put_fix_number(h).put_literal_symbol(psname)
  861.        .put_symbol("MF");
  862.   }
  863.   else {
  864.     out.put_literal_symbol(psname).put_symbol("SF");
  865.   }
  866.   defined_styles[ndefined_styles++] = sty;
  867. }
  868.  
  869. void ps_printer::set_space_code(unsigned char c)
  870. {
  871.   out.put_literal_symbol("SC").put_number(c).put_symbol("def");
  872. }
  873.  
  874. void ps_printer::end_of_line()
  875. {
  876.   flush_sbuf();
  877.   // this ensures that we do an absolute motion to the beginning of a line
  878.   output_vpos = output_hpos = -1;
  879. }
  880.  
  881. void ps_printer::flush_sbuf()
  882. {
  883.   enum {
  884.     NONE,
  885.     RELATIVE_H,
  886.     RELATIVE_V,
  887.     RELATIVE_HV,
  888.     ABSOLUTE
  889.     } motion = NONE;
  890.   int space_flag = 0;
  891.   if (sbuf_len == 0)
  892.     return;
  893.   if (output_style != sbuf_style) {
  894.     set_style(sbuf_style);
  895.     output_style = sbuf_style;
  896.   }
  897.   int extra_space = 0;
  898.   if (output_hpos < 0 || output_vpos < 0
  899.       || !is_small_h(output_hpos - sbuf_start_hpos)
  900.       || !is_small_v(output_vpos - sbuf_vpos))
  901.     motion = ABSOLUTE;
  902.   else {
  903.     if (output_hpos != sbuf_start_hpos)
  904.       motion = RELATIVE_H;
  905.     if (output_vpos != sbuf_vpos) {
  906.       if  (motion != NONE)
  907.     motion = RELATIVE_HV;
  908.       else
  909.     motion = RELATIVE_V;
  910.     }
  911.   }
  912.   if (sbuf_space_code >= 0) {
  913.     int w = sbuf_style.f->get_width(space_char_index, sbuf_style.point_size);
  914.     if (w + sbuf_kern != sbuf_space_width) {
  915.       if (sbuf_space_code != output_space_code) {
  916.     set_space_code(sbuf_space_code);
  917.     output_space_code = sbuf_space_code;
  918.       }
  919.       space_flag = 1;
  920.       extra_space = sbuf_space_width - w - sbuf_kern;
  921.       if (sbuf_space_diff_count > sbuf_space_count/2)
  922.     extra_space++;
  923.       else if (sbuf_space_diff_count < -(sbuf_space_count/2))
  924.     extra_space--;
  925.     }
  926.   }
  927.   if (space_flag)
  928.     out.put_fix_number(extra_space);
  929.   if (sbuf_kern != 0)
  930.     out.put_fix_number(sbuf_kern);
  931.   out.put_string(sbuf, sbuf_len);
  932.   char sym[2];
  933.   sym[0] = 'A' + motion*4 + space_flag + 2*(sbuf_kern != 0);
  934.   sym[1] = '\0';
  935.   switch (motion) {
  936.   case NONE:
  937.     break;
  938.   case ABSOLUTE:
  939.     out.put_fix_number(sbuf_start_hpos)
  940.        .put_fix_number(sbuf_vpos);
  941.     break;
  942.   case RELATIVE_H:
  943.     out.put_fix_number(sbuf_start_hpos - output_hpos);
  944.     break;
  945.   case RELATIVE_V:
  946.     out.put_fix_number(sbuf_vpos - output_vpos);
  947.     break;
  948.   case RELATIVE_HV:
  949.     out.put_fix_number(sbuf_start_hpos - output_hpos)
  950.        .put_fix_number(sbuf_vpos - output_vpos);
  951.     break;
  952.   default:
  953.     assert(0);
  954.   }
  955.   out.put_symbol(sym);
  956.   output_hpos = sbuf_end_hpos;
  957.   output_vpos = sbuf_vpos;
  958.   sbuf_len = 0;
  959. }
  960.  
  961.  
  962. void ps_printer::set_line_thickness(const environment *env)
  963. {
  964.   if (line_thickness < 0) {
  965.     if (output_draw_point_size != env->size) {
  966.       // we ought to check for overflow here
  967.       int lw = ((font::res/(72*font::sizescale))*linewidth*env->size)/1000;
  968.       out.put_fix_number(lw).put_symbol("LW");
  969.       output_draw_point_size = env->size;
  970.       output_line_thickness = -1;
  971.     }
  972.   }
  973.   else {
  974.     if (output_line_thickness != line_thickness) {
  975.       out.put_fix_number(line_thickness).put_symbol("LW");
  976.       output_line_thickness = line_thickness;
  977.       output_draw_point_size = -1;
  978.     }
  979.   }
  980. }
  981.  
  982. void ps_printer::fill_path()
  983. {
  984.   if (fill > FILL_MAX)
  985.     out.put_symbol("BL");
  986.   else
  987.     out.put_float(transform_fill(fill)).put_symbol("FL");
  988. }
  989.  
  990. void ps_printer::draw(int code, int *p, int np, const environment *env)
  991. {
  992.   int fill_flag = 0;
  993.   switch (code) {
  994.   case 'C':
  995.     fill_flag = 1;
  996.     // fall through
  997.   case 'c':
  998.     // troff adds an extra argument to C
  999.     if (np != 1 && !(code == 'C' && np == 2)) {
  1000.       error("1 argument required for circle");
  1001.       break;
  1002.     }
  1003.     out.put_fix_number(env->hpos + p[0]/2)
  1004.        .put_fix_number(env->vpos)
  1005.        .put_fix_number(p[0]/2)
  1006.        .put_symbol("DC");
  1007.     if (fill_flag) {
  1008.       fill_path();
  1009.     }
  1010.     else {
  1011.       set_line_thickness(env);
  1012.       out.put_symbol("ST");
  1013.     }
  1014.     break;
  1015.   case 'l':
  1016.     if (np != 2) {
  1017.       error("2 arguments required for line");
  1018.       break;
  1019.     }
  1020.     set_line_thickness(env);
  1021.     out.put_fix_number(p[0] + env->hpos)
  1022.        .put_fix_number(p[1] + env->vpos)
  1023.        .put_fix_number(env->hpos)
  1024.        .put_fix_number(env->vpos)
  1025.        .put_symbol("DL");
  1026.     break;
  1027.   case 'E':
  1028.     fill_flag = 1;
  1029.     // fall through
  1030.   case 'e':
  1031.     if (np != 2) {
  1032.       error("2 arguments required for ellipse");
  1033.       break;
  1034.     }
  1035.     out.put_fix_number(p[0])
  1036.        .put_fix_number(p[1])
  1037.        .put_fix_number(env->hpos + p[0]/2)
  1038.        .put_fix_number(env->vpos)
  1039.        .put_symbol("DE");
  1040.     if (fill_flag) {
  1041.       fill_path();
  1042.     }
  1043.     else {
  1044.       set_line_thickness(env);
  1045.       out.put_symbol("ST");
  1046.     }
  1047.     break;
  1048.   case 'P':
  1049.     fill_flag = 1;
  1050.     // fall through
  1051.   case 'p':
  1052.     {
  1053.       if (np & 1) {
  1054.     error("even number of arguments required for polygon");
  1055.     break;
  1056.       }
  1057.       if (np == 0) {
  1058.     error("no arguments for polygon");
  1059.     break;
  1060.       }
  1061.       out.put_fix_number(env->hpos)
  1062.      .put_fix_number(env->vpos)
  1063.      .put_symbol("MT");
  1064.       for (int i = 0; i < np; i += 2)
  1065.     out.put_fix_number(p[i])
  1066.        .put_fix_number(p[i+1])
  1067.        .put_symbol("RL");
  1068.       out.put_symbol("CL");
  1069.       if (fill_flag) {
  1070.     fill_path();
  1071.       }
  1072.       else {
  1073.     set_line_thickness(env);
  1074.     out.put_symbol("ST");
  1075.       }
  1076.       break;
  1077.     }
  1078.   case '~':
  1079.     {
  1080.       if (np & 1) {
  1081.     error("even number of arguments required for spline");
  1082.     break;
  1083.       }
  1084.       if (np == 0) {
  1085.     error("no arguments for spline");
  1086.     break;
  1087.       }
  1088.       out.put_fix_number(env->hpos)
  1089.      .put_fix_number(env->vpos)
  1090.      .put_symbol("MT");
  1091.       out.put_fix_number(p[0]/2)
  1092.      .put_fix_number(p[1]/2)
  1093.      .put_symbol("RL");
  1094.       /* tnum/tden should be between 0 and 1; the closer it is to 1
  1095.      the tighter the curve will be to the guiding lines; 2/3
  1096.      is the standard value */
  1097.       const int tnum = 2;
  1098.       const int tden = 3;
  1099.       for (int i = 0; i < np - 2; i += 2) {
  1100.     out.put_fix_number((p[i]*tnum)/(2*tden))
  1101.        .put_fix_number((p[i + 1]*tnum)/(2*tden))
  1102.        .put_fix_number(p[i]/2 + (p[i + 2]*(tden - tnum))/(2*tden))
  1103.        .put_fix_number(p[i + 1]/2 + (p[i + 3]*(tden - tnum))/(2*tden))
  1104.        .put_fix_number((p[i] - p[i]/2) + p[i + 2]/2)
  1105.        .put_fix_number((p[i + 1] - p[i + 1]/2) + p[i + 3]/2)
  1106.        .put_symbol("RC");
  1107.       }
  1108.       out.put_fix_number(p[np - 2] - p[np - 2]/2)
  1109.      .put_fix_number(p[np - 1] - p[np - 1]/2)
  1110.      .put_symbol("RL");
  1111.       set_line_thickness(env);
  1112.       out.put_symbol("ST");
  1113.     }
  1114.     break;
  1115.   case 'a':
  1116.     {
  1117.       if (np != 4) {
  1118.     error("4 arguments required for arc");
  1119.     break;
  1120.       }
  1121.       set_line_thickness(env);
  1122.       int x = p[0] + p[2];
  1123.       int y = p[1] + p[3];
  1124.       double n = p[0]*double(x) + p[1]*double(y);
  1125.       if (n == 0)
  1126.     out.put_fix_number(x + env->hpos)
  1127.        .put_fix_number(y + env->vpos)
  1128.        .put_fix_number(env->hpos)
  1129.        .put_fix_number(env->vpos)
  1130.        .put_symbol("DL");
  1131.       else {
  1132.     double k = (double(x)*x + double(y)*y)/(2.0*n);
  1133.     double cx = k*p[0];
  1134.     double cy = k*p[1];
  1135.     out.put_fix_number(env->hpos + int(cx))
  1136.        .put_fix_number(env->vpos + int(cy))
  1137.        .put_fix_number(int(sqrt(cx*cx + cy*cy)))
  1138.        .put_float(degrees(atan2(-cy, -cx)))
  1139.        .put_float(degrees(atan2(y - cy, x - cx)))
  1140.        .put_symbol("DA");
  1141.       }
  1142.     }
  1143.     break;
  1144.   case 't':
  1145.     {
  1146.       if (np == 0) {
  1147.     line_thickness = -1;
  1148.       }
  1149.       else {
  1150.     // troff gratuitously adds an extra 0
  1151.     if (np != 1 && np != 2) {
  1152.       error("0 or 1 argument required for thickness");
  1153.       break;
  1154.     }
  1155.     line_thickness = p[0];
  1156.       }
  1157.       break;
  1158.     }
  1159.   case 'f':
  1160.     {
  1161.       if (np != 1 && np != 2) {
  1162.     error("1 argument required for fill");
  1163.     break;
  1164.       }
  1165.       fill = p[0];
  1166.       if (fill < 0 || fill > FILL_MAX) {
  1167.     // This means fill with the current color.
  1168.     fill = FILL_MAX + 1;
  1169.       }
  1170.       break;
  1171.     }      
  1172.   default:
  1173.     error("unrecognised drawing command `%1'", char(code));
  1174.     break;
  1175.   }
  1176.  
  1177.   output_hpos = output_vpos = -1;
  1178. }
  1179.  
  1180. void ps_printer::begin_page(int n)
  1181. {
  1182.   out.begin_comment("Page:").comment_arg(itoa(n));
  1183.   out.comment_arg(itoa(++pages_output)).end_comment();
  1184.   output_style.f = 0;
  1185.   output_space_code = 32;
  1186.   output_draw_point_size = -1;
  1187.   output_line_thickness = -1;
  1188.   output_hpos = output_vpos = -1;
  1189.   ndefined_styles = 0;
  1190.   out.put_symbol("BP");
  1191. }
  1192.  
  1193. void ps_printer::end_page()
  1194. {
  1195.   flush_sbuf();
  1196.   out.put_symbol("EP");
  1197. }
  1198.  
  1199. font *ps_printer::make_font(const char *nm)
  1200. {
  1201.   return ps_font::load_ps_font(nm);
  1202. }
  1203.  
  1204. ps_printer::~ps_printer()
  1205. {
  1206.   out.simple_comment("Trailer");
  1207.   out.put_symbol("end");
  1208.   out.end_line();
  1209.   if (fseek(tempfp, 0L, 0) < 0)
  1210.     fatal("fseek on temporary file failed");
  1211.   fputs("%!PS-Adobe-2.1\n", stdout);
  1212.   out.set_file(stdout);
  1213.   {
  1214.     extern const char *version_string;
  1215.     out.begin_comment("Creator:")
  1216.        .comment_arg("groff")
  1217.        .comment_arg("version")
  1218.        .comment_arg(version_string)
  1219.        .end_comment();
  1220.   }
  1221.   read_download_file();
  1222.   merge_ps_fonts();
  1223.   merge_download_fonts();
  1224.   print_font_comment();
  1225.   print_supplied_font_comment();
  1226.   print_needed_font_comment();
  1227.   out.begin_comment("Pages:").comment_arg(itoa(pages_output)).end_comment();
  1228.   out.simple_comment("EndComments");
  1229.   char *path;
  1230.   FILE *fp = font::open_file(PROLOGUE, &path);
  1231.   if (fp == 0)
  1232.     fatal("can't find `%1'", PROLOGUE);
  1233.   out.put_literal_symbol(dict_name);
  1234.   out.put_number(MAX_DEFINED_STYLES + MAX_PROLOGUE_DEFS).put_symbol("dict");
  1235.   out.put_symbol("def");
  1236.   out.put_symbol(dict_name).put_symbol("begin");
  1237.   out.include_file(fp);
  1238.   fclose(fp);
  1239.   if (ndefs > 0)
  1240.     ndefs += DEFS_DICT_SPARE;
  1241.   out.put_literal_symbol(defs_dict_name)
  1242.      .put_number(ndefs + 1)
  1243.      .put_symbol("dict")
  1244.      .put_symbol("def");
  1245.   out.put_symbol(defs_dict_name)
  1246.      .put_symbol("begin");
  1247.   out.put_literal_symbol("u")
  1248.      .put_delimiter('{')
  1249.      .put_fix_number(1)
  1250.      .put_symbol("mul")
  1251.      .put_delimiter('}')
  1252.      .put_symbol("bind")
  1253.      .put_symbol("def");
  1254.   defs += '\0';
  1255.   out.special(defs.contents());
  1256.   out.put_symbol("end");
  1257.   delete path;
  1258.   out.put_symbol("end");
  1259. #ifndef BROKEN_SPOOLER
  1260.   out.simple_comment("EndProlog");
  1261. #endif /* !BROKEN_SPOOLER */
  1262.   print_include_font_comments();
  1263.   download_fonts();
  1264. #ifndef BROKEN_SPOOLER
  1265.   out.simple_comment("BeginSetup");
  1266. #endif /* !BROKEN_SPOOLER */
  1267.   out.put_symbol(dict_name).put_symbol("begin");
  1268.   out.put_literal_symbol("#copies").put_number(ncopies).put_symbol("def");
  1269.   out.put_literal_symbol("RES").put_number(res).put_symbol("def");
  1270.   out.put_literal_symbol("PL").put_fix_number(paper_length).put_symbol("def");
  1271.   out.put_literal_symbol("LS")
  1272.      .put_symbol(landscape_flag ? "true" : "false")
  1273.      .put_symbol("def");
  1274.   encode_fonts();
  1275. #ifndef BROKEN_SPOOLER
  1276.   out.simple_comment("EndSetup");
  1277. #else /* !BROKEN_SPOOLER */
  1278.   out.simple_comment("EndProlog");
  1279. #endif /* BROKEN_SPOOLER */
  1280.   out.end_line();
  1281.   out.copy_file(tempfp);
  1282.   fclose(tempfp);
  1283. }
  1284.  
  1285. void ps_printer::special(char *arg, const environment *env)
  1286. {
  1287.   typedef void (ps_printer::*SPECIAL_PROCP)(char *, const environment *);
  1288.   static struct {
  1289.     const char *name;
  1290.     SPECIAL_PROCP proc;
  1291.   } proc_table[] = {
  1292.     "exec", &ps_printer::do_exec,
  1293.     "def", &ps_printer::do_def,
  1294.     "mdef", &ps_printer::do_mdef,
  1295.     "import", &ps_printer::do_import,
  1296.     "file", &ps_printer::do_file,
  1297.   };
  1298.   for (char *p = arg; *p == ' ' || *p == '\n'; p++)
  1299.     ;
  1300.   char *tag = p;
  1301.   for (; *p != '\0' && *p != ':' && *p != ' ' && *p != '\n'; p++)
  1302.     ;
  1303.   if (*p == '\0' || strncmp(tag, "ps", p - tag) != 0) {
  1304.     error("X command without `ps:' tag ignored");
  1305.     return;
  1306.   }
  1307.   p++;
  1308.   for (; *p == ' ' || *p == '\n'; p++)
  1309.     ;
  1310.   char *command = p;
  1311.   for (; *p != '\0' && *p != ' ' && *p != '\n'; p++)
  1312.     ;
  1313.   if (*command == '\0') {
  1314.     error("X command without `ps:' tag ignored");
  1315.     return;
  1316.   }
  1317.   for (int i = 0; i < sizeof(proc_table)/sizeof(proc_table[0]); i++)
  1318.     if (strncmp(command, proc_table[i].name, p - command) == 0) {
  1319.       flush_sbuf();
  1320.       (this->*(proc_table[i].proc))(p, env);
  1321.       return;
  1322.     }
  1323.   error("X command `%1' not recognised", command);
  1324. }
  1325.  
  1326. // A conforming PostScript document must not have lines longer
  1327. // than 255 characters (excluding line termination characters).
  1328.  
  1329. static int check_line_lengths(const char *p)
  1330. {
  1331.   for (;;) {
  1332.     const char *end = strchr(p, '\n');
  1333.     if (end == 0)
  1334.       end = strchr(p, '\0');
  1335.     if (end - p > 255)
  1336.       return 0;
  1337.     if (*end == '\0')
  1338.       break;
  1339.     p = end + 1;
  1340.   }
  1341.   return 1;
  1342. }
  1343.  
  1344. void ps_printer::do_exec(char *arg, const environment *env)
  1345. {
  1346.   while (csspace(*arg))
  1347.     arg++;
  1348.   if (*arg == '\0') {
  1349.     error("missing argument to X exec command");
  1350.     return;
  1351.   }
  1352.   if (!check_line_lengths(arg)) {
  1353.     error("lines in X exec command must not be more than 255 characters long");
  1354.     return;
  1355.   }
  1356.   out.put_fix_number(env->hpos)
  1357.      .put_fix_number(env->vpos)
  1358.      .put_symbol("EBEGIN")
  1359.      .special(arg)
  1360.      .put_symbol("EEND");
  1361.   output_hpos = output_vpos = -1;
  1362.   output_style.f = 0;
  1363.   output_draw_point_size = -1;
  1364.   output_line_thickness = -1;
  1365.   ndefined_styles = 0;
  1366. }
  1367.  
  1368. void ps_printer::do_file(char *arg, const environment *env)
  1369. {
  1370.   while (csspace(*arg))
  1371.     arg++;
  1372.   if (*arg == '\0') {
  1373.     error("missing argument to X file command");
  1374.     return;
  1375.   }
  1376.   const char *filename = arg;
  1377.   do {
  1378.     ++arg;
  1379.   } while (*arg != '\0' && *arg != ' ' && *arg != '\n');
  1380.   FILE *fp = fopen(filename, "r");
  1381.   if (!fp) {
  1382.     error("can't open `%1': %2", filename, strerror(errno));
  1383.     return;
  1384.   }
  1385.   out.put_fix_number(env->hpos)
  1386.      .put_fix_number(env->vpos)
  1387.      .put_symbol("EBEGIN")
  1388.      .include_file(fp)
  1389.      .put_symbol("EEND");
  1390.   fclose(fp);
  1391.   output_hpos = output_vpos = -1;
  1392.   output_style.f = 0;
  1393.   output_draw_point_size = -1;
  1394.   output_line_thickness = -1;
  1395.   ndefined_styles = 0;
  1396. }
  1397.  
  1398. void ps_printer::do_def(char *arg, const environment *)
  1399. {
  1400.   while (csspace(*arg))
  1401.     arg++;
  1402.   if (!check_line_lengths(arg)) {
  1403.     error("lines in X def command must not be more than 255 characters long");
  1404.     return;
  1405.   }
  1406.   defs += arg;
  1407.   if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n')
  1408.     defs += '\n';
  1409.   ndefs++;
  1410. }
  1411.  
  1412. // Like def, but the first argument says how many definitions it contains.
  1413.  
  1414. void ps_printer::do_mdef(char *arg, const environment *)
  1415. {
  1416.   char *p;
  1417.   int n = (int)strtol(arg, &p, 10);
  1418.   if (n == 0 && p == arg) {
  1419.     error("first argument to X mdef must be an integer");
  1420.     return;
  1421.   }
  1422.   if (n < 0) {
  1423.     error("out of range argument `%1' to X mdef command", int(n));
  1424.     return;
  1425.   }
  1426.   arg = p;
  1427.   while (csspace(*arg))
  1428.     arg++;
  1429.   if (!check_line_lengths(arg)) {
  1430.     error("lines in X mdef command must not be more than 255 characters long");
  1431.     return;
  1432.   }
  1433.   defs += arg;
  1434.   if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n')
  1435.     defs += '\n';
  1436.   ndefs += n;
  1437. }
  1438.  
  1439. void ps_printer::do_import(char *arg, const environment *env)
  1440. {
  1441.   while (*arg == ' ' || *arg == '\n')
  1442.     arg++;
  1443.   for (char *p = arg; *p != '\0' && *p != ' ' && *p != '\n'; p++)
  1444.     ;
  1445.   if (*p != '\0')
  1446.     *p++ = '\0';
  1447.   int parms[6];
  1448.   int nparms = 0;
  1449.   while (nparms < 6) {
  1450.     char *end;
  1451.     long n = strtol(p, &end, 10);
  1452.     if (n == 0 && end == p)
  1453.       break;
  1454.     parms[nparms++] = int(n);
  1455.     p = end;
  1456.   }
  1457.   if (csalpha(*p) && (p[1] == '\0' || p[1] == ' ' || p[1] == '\n')) {
  1458.     error("scaling indicators not allowed in arguments for X import command");
  1459.     return;
  1460.   }
  1461.   while (*p == ' ' || *p == '\n')
  1462.     p++;
  1463.   if (nparms < 5) {
  1464.     if (*p == '\0')
  1465.       error("too few arguments for X import command");
  1466.     else
  1467.       error("invalid argument `%1' for X import command", p);
  1468.     return;
  1469.   }
  1470.   if (*p != '\0') {
  1471.     error("superflous argument `%1' for X import command", p);
  1472.     return;
  1473.   }
  1474.   int llx = parms[0];
  1475.   int lly = parms[1];
  1476.   int urx = parms[2];
  1477.   int ury = parms[3];
  1478.   int desired_width = parms[4];
  1479.   int desired_height = parms[5];
  1480.   if (desired_width <= 0) {
  1481.     error("bad width argument `%1' for X import command: must be > 0",
  1482.       desired_width);
  1483.     return;
  1484.   }
  1485.   if (nparms == 6 && desired_height <= 0) {
  1486.     error("bad height argument `%1' for X import command: must be > 0",
  1487.       desired_height);
  1488.     return;
  1489.   }
  1490.   if (llx == urx) {
  1491.     error("llx and urx arguments for X import command must not be equal");
  1492.     return;
  1493.   }
  1494.   if (lly == ury) {
  1495.     error("lly and ury arguments for X import command must not be equal");
  1496.     return;
  1497.   }
  1498.   if (nparms == 5) {
  1499.     int old_wid = urx - llx;
  1500.     int old_ht = ury - lly;
  1501.     if (old_wid < 0)
  1502.       old_wid = -old_wid;
  1503.     if (old_ht < 0)
  1504.       old_ht = -old_ht;
  1505.     desired_height = int(desired_width*(double(old_ht)/double(old_wid)) + .5);
  1506.   }
  1507.   if (env->vpos - desired_height < 0)
  1508.     warning("top of imported graphic is above the top of the page");
  1509.   FILE *fp = fopen(arg, "r");
  1510.   if (fp == 0) {
  1511.     error("can't open `%1': %2", arg, strerror(errno));
  1512.     return;
  1513.   }
  1514.   merge_import_fonts(fp);
  1515.   out.put_literal_symbol("level1")
  1516.      .put_symbol("save")
  1517.      .put_symbol("def");
  1518.   out.put_number(llx)
  1519.      .put_number(lly)
  1520.      .put_fix_number(desired_width)
  1521.      .put_number(urx - llx)
  1522.      .put_fix_number(-desired_height)
  1523.      .put_number(ury - lly)
  1524.      .put_fix_number(env->hpos)
  1525.      .put_fix_number(env->vpos)
  1526.      .put_symbol("PICTURE");
  1527.   // Put our dictionary off the dictionary stack so that it isn't
  1528.   // zapped by unfriendly applications.
  1529.   out.put_symbol("end");
  1530.   // Disable showpage.
  1531.   out.put_literal_symbol("showpage")
  1532.      .put_delimiter('{')
  1533.      .put_delimiter('}')
  1534.      .put_symbol("def");
  1535.   out.begin_comment("BeginDocument:")
  1536.      .comment_arg(arg)
  1537.      .end_comment();
  1538.   out.include_file(fp);
  1539.   fclose(fp);
  1540.   out.simple_comment("EndDocument");
  1541.   // Clear junk off operand stack, to lessen chance of an invalidrestore.
  1542.   out.put_symbol("clear");
  1543.   out.put_symbol(dict_name)
  1544.      .put_symbol("begin");
  1545.   out.put_symbol("level1")
  1546.      .put_symbol("restore");
  1547. }
  1548.  
  1549. static void add_font(const char *name, int t, document_font **pp)
  1550. {
  1551.   for (; *pp; pp = &(*pp)->next)
  1552.     if (strcmp(name, (*pp)->name) == 0) {
  1553.       (*pp)->flags |= t;
  1554.       return;
  1555.     }
  1556.   *pp = new document_font(name);
  1557.   (*pp)->flags = t;
  1558. }
  1559.  
  1560. // Skip the rest of the current line, including any line termination
  1561. // characters.
  1562.  
  1563. static int skip_line(FILE *fp)
  1564. {
  1565.   // The spec says any combination of \n and \r is allowed as a line
  1566.   // termination.  It seems wrong to allow multiple \n's or multiple
  1567.   // \r's since this would mean we were swallowing blank lines.
  1568.   for (;;) {
  1569.     int c = getc(fp);
  1570.     if (c == '\n') {
  1571.       c = getc(fp);
  1572.       if (c == EOF)
  1573.     return 0;
  1574.       if (c != '\r')
  1575.     ungetc(c, fp);
  1576.       return 1;
  1577.     }
  1578.     if (c == '\r') {
  1579.       c = getc(fp);
  1580.       if (c == EOF)
  1581.     return 0;
  1582.       if (c != '\n')
  1583.     ungetc(c, fp);
  1584.       return 1;
  1585.     }
  1586.     if (c == EOF)
  1587.       break;
  1588.   }
  1589.   return 0;
  1590. }
  1591.  
  1592. static void parse_fonts_arg(FILE *fp, int type, document_font **font_listp,
  1593.                 int *at_endp)
  1594. {
  1595.   // More than enough room for a single name.
  1596.   char buf[256];
  1597.   int c = getc(fp);
  1598.   for (;;) {
  1599.     while (c == ' ' || c == '\t')
  1600.       c = getc(fp);
  1601.     if (c == EOF || c == '\n' || c == '\r')
  1602.       break;
  1603.     int i = 0;
  1604.     do {
  1605.       if (i >= sizeof(buf) - 1)
  1606.     return;
  1607.       if (c == '\0')
  1608.     return;
  1609.       buf[i++] = c;
  1610.       c = getc(fp);
  1611.     } while (c != '\n' && c != '\r' && c != ' ' && c != '\t' && c != EOF);
  1612.     buf[i++] = '\0';
  1613.     if (strcmp(buf, "(atend)") == 0 && at_endp != 0)
  1614.       *at_endp |= type;
  1615.     else
  1616.       add_font(buf, type, font_listp);
  1617.   }
  1618.   if (c == '\n' || c == '\r')
  1619.     ungetc(c, fp);
  1620. }
  1621.  
  1622. static document_font *read_document_fonts(FILE *fp)
  1623. {
  1624.   int last_comment = 0;
  1625.   int document_fonts_at_end = 0;
  1626.   // This says which comments we've seen in the header.  The first of each
  1627.   // is the significant one.
  1628.   int header_comments = 0;
  1629.   char buf[sizeof("DocumentSuppliedFonts:")];
  1630. #define MAGIC "%!PS-Adobe-"
  1631.   if (fread(buf, 1, sizeof(MAGIC)-1, fp) != sizeof(MAGIC)-1
  1632.       || memcmp(buf, MAGIC, sizeof(MAGIC)-1) != 0)
  1633.     return 0;
  1634.   document_font *font_list = 0;
  1635.   enum { HEADER, BODY, TRAILER } state = HEADER;
  1636.   int level = 0;
  1637.   while (skip_line(fp)) {
  1638.     if (state == BODY && document_fonts_at_end == 0)
  1639.       break;
  1640.     int c = getc(fp);
  1641.     if (c == '%')
  1642.       c = getc(fp);
  1643.     if (c == EOF)
  1644.       break;
  1645.     if (c != '%') {
  1646.       if (state == HEADER)
  1647.     state = BODY;
  1648.       if (c == '\n' || c == '\r')
  1649.     ungetc(c, fp);
  1650.       continue;
  1651.     }
  1652.     c = getc(fp);
  1653.     if (c == EOF)
  1654.       break;
  1655.     if (c == '+') {
  1656.       if (last_comment)
  1657.     parse_fonts_arg(fp, last_comment, &font_list, 0);
  1658.       continue;
  1659.     }
  1660.     last_comment = 0;
  1661.     int i = 0;
  1662.     while (c != '\r' && c != '\n' && c != ' ' && c != '\t' && c != EOF) {
  1663.       if (i >= sizeof(buf) - 1) {
  1664.     i = 0;
  1665.     break;
  1666.       }
  1667.       buf[i++] = c;
  1668.       if (c == ':')
  1669.     break;
  1670.       c = getc(fp);
  1671.     }
  1672.     if (c == '\r' || c == '\n')
  1673.       ungetc(c, fp);
  1674.     buf[i++] = '\0';
  1675.     if (strcmp(buf, "BeginDocument:") == 0)
  1676.       level++;
  1677.     else if (strcmp(buf, "EndDocument") == 0) {
  1678.       if (level > 0)
  1679.     level--;
  1680.     }
  1681.     else if (level == 0) {
  1682.       if (strcmp(buf, "Trailer") == 0)
  1683.     state = TRAILER;
  1684.       else if (strcmp(buf, "EndComments") == 0) {
  1685.     if (state == HEADER)
  1686.       state = BODY;
  1687.       }
  1688.       else if (state == HEADER) {
  1689.     int comment_type = 0;
  1690.     if (strcmp(buf, "DocumentFonts:") == 0)
  1691.       comment_type = document_font::LISTED;
  1692.     else if (strcmp(buf, "DocumentNeededFonts:") == 0)
  1693.       comment_type = document_font::NEEDED;
  1694.     else if (strcmp(buf, "DocumentSuppliedFonts:") == 0)
  1695.       comment_type = document_font::SUPPLIED;
  1696.     if (comment_type != 0 && !(header_comments & comment_type)) {
  1697.       parse_fonts_arg(fp, comment_type, &font_list,
  1698.               (comment_type == document_font::LISTED
  1699.                ? &document_fonts_at_end
  1700.                : 0));
  1701.       last_comment = comment_type;
  1702.       header_comments |= comment_type;
  1703.     }
  1704.       }
  1705.       else if (state == TRAILER && strcmp(buf, "DocumentFonts:") == 0) {
  1706.     parse_fonts_arg(fp, document_font::LISTED, &font_list, 0);
  1707.     last_comment = document_font::LISTED;
  1708.       }
  1709.     }
  1710.   }
  1711.   return font_list;
  1712. }
  1713.  
  1714. document_font *ps_printer::lookup_doc_font(const char *nm)
  1715. {
  1716.   for (document_font **p = &doc_fonts; *p; p = &(*p)->next)
  1717.     if (strcmp((*p)->name, nm) == 0)
  1718.       return *p;
  1719.   return *p = new document_font(nm);
  1720. }
  1721.  
  1722. void ps_printer::merge_download_fonts()
  1723. {
  1724.   for (document_font *p = doc_fonts; p; p = p->next)
  1725.     if (p->filename && (p->flags & document_font::NEEDED)) {
  1726.       char *path = 0;
  1727.       FILE *fp = font::open_file(p->filename, &path);
  1728.       delete path;
  1729.       if (fp) {
  1730.     document_font *depends = read_document_fonts(fp);
  1731.     fclose(fp);
  1732.     while (depends) {
  1733.       document_font *tem = depends->next;
  1734.       if (strcmp(p->name, depends->name) != 0) {
  1735.         if ((depends->flags & document_font::LISTED)
  1736.         && !(depends->flags & document_font::SUPPLIED))
  1737.           depends->flags |= document_font::NEEDED;
  1738.         // We ignore the LISTED bit from now on.
  1739.         document_font *q = lookup_doc_font(depends->name);
  1740.         if (q->filename && (depends->flags & document_font::NEEDED)) {
  1741.           depend_list *dep = new depend_list;
  1742.           dep->next = p->depends_on;
  1743.           dep->p = q;
  1744.           p->depends_on = dep;
  1745.           if (!(q->flags & document_font::NEEDED)) {
  1746.         // Move q to the end of the list.
  1747.         for (document_font **pp = &doc_fonts;
  1748.              *pp != q;
  1749.              pp = &(*pp)->next)
  1750.           ;
  1751.         *pp = q->next;
  1752.         q->next = 0;
  1753.         for (; *pp; pp = &(*pp)->next)
  1754.           ;
  1755.         *pp = q;
  1756.           }
  1757.         }
  1758.         q->flags |= depends->flags;
  1759.       }
  1760.       delete depends;
  1761.       depends = tem;
  1762.     }
  1763.       }
  1764.       else {
  1765.     error("can't find font file `%1': %2", p->filename, strerror(errno));
  1766.     delete p->filename;
  1767.     p->filename = 0;
  1768.       }
  1769.     }
  1770. }
  1771.  
  1772. void ps_printer::merge_import_fonts(FILE *fp)
  1773. {
  1774.   document_font *p = read_document_fonts(fp);
  1775.   rewind(fp);
  1776.   while (p) {
  1777.     if ((p->flags & document_font::LISTED)
  1778.     && !(p->flags & document_font::SUPPLIED))
  1779.       p->flags |= document_font::NEEDED;
  1780.     document_font *tem = p->next;
  1781.     document_font *q = lookup_doc_font(p->name);
  1782.     q->flags |= p->flags;
  1783.     delete p;
  1784.     p = tem;
  1785.   }
  1786. }
  1787.  
  1788. void ps_printer::merge_ps_fonts()
  1789. {
  1790.   for (font_pointer_list *f = font_list; f; f = f->next) {
  1791.     ps_font *psf = (ps_font *)(f->p);
  1792.     document_font *p = lookup_doc_font(psf->get_internal_name());
  1793.     p->flags |= document_font::NEEDED;
  1794.   }
  1795. }
  1796.  
  1797. void ps_printer::print_font_comment()
  1798. {
  1799.   out.begin_comment("DocumentFonts:");
  1800.   for (document_font *list = doc_fonts; list; list = list->next)
  1801.     if (list->flags)
  1802.       out.comment_arg(list->name);
  1803.   out.end_comment();
  1804. }
  1805.  
  1806. void ps_printer::print_supplied_font_comment()
  1807. {
  1808.   out.begin_comment("DocumentSuppliedFonts:");
  1809.   for (document_font *list = doc_fonts; list; list = list->next)
  1810.     if (((list->flags & document_font::NEEDED) && list->filename)
  1811.     || ((list->flags & document_font::SUPPLIED)
  1812. #if 0
  1813.         && !(list->flags & document_font::NEEDED)
  1814. #endif
  1815.     ))
  1816.       out.comment_arg(list->name);
  1817.   out.end_comment();
  1818. }
  1819.  
  1820. void ps_printer::print_needed_font_comment()
  1821. {
  1822.   out.begin_comment("DocumentNeededFonts:");
  1823.   for (document_font *list = doc_fonts; list; list = list->next)
  1824.     if ((list->flags & document_font::NEEDED) && !list->filename)
  1825.       out.comment_arg(list->name);
  1826.   out.end_comment();
  1827. }
  1828.  
  1829. void ps_printer::print_include_font_comments()
  1830. {
  1831.   for (document_font *list = doc_fonts; list; list = list->next)
  1832.     if ((list->flags & document_font::NEEDED) && !list->filename)
  1833.       out.begin_comment("IncludeFont:").comment_arg(list->name).end_comment();
  1834. }
  1835.   
  1836. void ps_printer::download_fonts()
  1837. {
  1838.   for (document_font *p = doc_fonts; p; p = p->next)
  1839.     p->download(out);
  1840. }
  1841.  
  1842. void ps_printer::read_download_file()
  1843. {
  1844.   char *path = 0;
  1845.   FILE *fp = font::open_file("download", &path);
  1846.   if (!fp)
  1847.     fatal("can't find `download'");
  1848.   char buf[512];
  1849.   int lineno = 0;
  1850.   while (fgets(buf, sizeof(buf), fp)) {
  1851.     lineno++;
  1852.     char *p = strtok(buf, " \t\r\n");
  1853.     if (p == 0 || *p == '#')
  1854.       continue;
  1855.     char *q = strtok(0, " \t\r\n");
  1856.     if (!q)
  1857.       fatal_with_file_and_line(path, lineno, "missing filename");
  1858.     lookup_doc_font(p)->filename = strsave(q);
  1859.   }
  1860.   delete path;
  1861.   fclose(fp);
  1862. }
  1863.  
  1864. document_font::document_font(const char *s)
  1865. : name(strsave(s)), filename(0), flags(0), next(0), depends_on(0), mark(0)
  1866. {
  1867.   assert(name != 0);
  1868. }
  1869.  
  1870. document_font::~document_font()
  1871. {
  1872.   delete name;
  1873.   delete filename;
  1874.   while (depends_on) {
  1875.     depend_list *tem = depends_on->next;
  1876.     delete depends_on;
  1877.     depends_on = tem;
  1878.   }
  1879. }
  1880.  
  1881. void document_font::download(ps_output &out)
  1882. {
  1883.   if (!filename)
  1884.     return;
  1885.   if (!(flags & NEEDED))
  1886.       return;
  1887.   // Do a reverse topological sort on the dependency graph.
  1888.   if (mark == 0) {
  1889.     mark = -1;
  1890.     for (depend_list *p = depends_on; p; p = p->next)
  1891.       p->p->download(out);
  1892.     char *path = 0;
  1893.     FILE *fp = font::open_file(filename, &path);
  1894.     // This shouldn't normally happen because we checked that the file
  1895.     // exists in merge_download_fonts.
  1896.     if (!fp)
  1897.       fatal("can't open `%1': %2", filename, strerror(errno));
  1898.     out.begin_comment("BeginFont:").comment_arg(name).end_comment();
  1899.     out.begin_comment("BeginDocument:").comment_arg(filename).end_comment();
  1900.     out.include_file(fp);
  1901.     out.simple_comment("EndDocument");
  1902.     out.simple_comment("EndFont");
  1903.     fclose(fp);
  1904.     delete path;
  1905.     mark = 1;
  1906.   }
  1907.   else if (mark < 0)
  1908.     error("loop detected in font dependencies for `%1'", name);
  1909. }
  1910.  
  1911. printer *make_printer()
  1912. {
  1913.   return new ps_printer;
  1914. }
  1915.  
  1916. static void usage();
  1917.  
  1918. int main(int argc, char **argv)
  1919. {
  1920.   program_name = argv[0];
  1921.   static char stderr_buf[BUFSIZ];
  1922.   setbuf(stderr, stderr_buf);
  1923.   int c;
  1924.   while ((c = getopt(argc, argv, "F:lc:w:v")) != EOF)
  1925.     switch(c) {
  1926.     case 'v':
  1927.       {
  1928.     extern const char *version_string;
  1929.     fprintf(stderr, "grops version %s\n", version_string);
  1930.     fflush(stderr);
  1931.     break;
  1932.       }
  1933.     case 'c':
  1934.       if (sscanf(optarg, "%d", &ncopies) != 1 || ncopies <= 0) {
  1935.     error("bad number of copies `%s'", optarg);
  1936.     ncopies = 1;
  1937.       }
  1938.       break;
  1939.     case 'l':
  1940.       landscape_flag = 1;
  1941.       break;
  1942.     case 'F':
  1943.       font::command_line_font_dir(optarg);
  1944.       break;
  1945.     case 'w':
  1946.       if (sscanf(optarg, "%d", &linewidth) != 1 || linewidth < 0) {
  1947.     error("bad linewidth `%s'", optarg);
  1948.     linewidth = -1;
  1949.       }
  1950.       break;
  1951.     case '?':
  1952.       usage();
  1953.       break;
  1954.     default:
  1955.       assert(0);
  1956.     }
  1957.   if (optind >= argc)
  1958.     do_file("-");
  1959.   else {
  1960.     for (int i = optind; i < argc; i++)
  1961.       do_file(argv[i]);
  1962.   }
  1963.   delete pr;
  1964.   exit(0);
  1965. }
  1966.  
  1967. static void usage()
  1968. {
  1969.   fprintf(stderr, "usage: %s [-l] [-c n] [-w n] [-F dir] [-v] [files ...]\n",
  1970.       program_name);
  1971.   exit(1);
  1972. }
  1973.