home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / util / gnu / groff_src.lha / groff-1.10src / grotty / tty.cc < prev   
C/C++ Source or Header  |  1995-06-22  |  10KB  |  444 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 "driver.h"
  22.  
  23. #ifndef SHRT_MIN
  24. #define SHRT_MIN (-32768)
  25. #endif
  26.  
  27. #ifndef SHRT_MAX
  28. #define SHRT_MAX 32767
  29. #endif
  30.  
  31. #define TAB_WIDTH 8
  32.  
  33. static int horizontal_tab_flag = 0;
  34. static int form_feed_flag = 0;
  35. static int bold_flag = 1;
  36. static int underline_flag = 1;
  37. static int overstrike_flag = 1;
  38. static int draw_flag = 1;
  39.  
  40. enum {
  41.   UNDERLINE_MODE = 01,
  42.   BOLD_MODE = 02,
  43.   VDRAW_MODE = 04,
  44.   HDRAW_MODE = 010
  45. };
  46.  
  47. // Mode to use for bold-underlining.
  48. static unsigned char bold_underline_mode = BOLD_MODE|UNDERLINE_MODE;
  49.  
  50. class tty_font : public font {
  51.   tty_font(const char *);
  52.   unsigned char mode;
  53. public:
  54.   ~tty_font();
  55.   unsigned char get_mode() { return mode; }
  56. #if 0
  57.   void handle_x_command(int argc, const char **argv);
  58. #endif
  59.   static tty_font *load_tty_font(const char *);
  60. };
  61.  
  62. tty_font *tty_font::load_tty_font(const char *s)
  63. {
  64.   tty_font *f = new tty_font(s);
  65.   if (!f->load()) {
  66.     delete f;
  67.     return 0;
  68.   }
  69.   const char *num = f->get_internal_name();
  70.   long n;
  71.   if (num != 0 && (n = strtol(num, 0, 0)) != 0)
  72.     f->mode = int(n & (BOLD_MODE|UNDERLINE_MODE));
  73.   if (!underline_flag)
  74.     f->mode &= ~UNDERLINE_MODE;
  75.   if (!bold_flag)
  76.     f->mode &= ~BOLD_MODE;
  77.   if ((f->mode & (BOLD_MODE|UNDERLINE_MODE)) == (BOLD_MODE|UNDERLINE_MODE))
  78.     f->mode = (f->mode & ~(BOLD_MODE|UNDERLINE_MODE)) | bold_underline_mode;
  79.   return f;
  80. }
  81.  
  82. tty_font::tty_font(const char *nm)
  83. : font(nm), mode(0)
  84. {
  85. }
  86.  
  87. tty_font::~tty_font()
  88. {
  89. }
  90.  
  91. #if 0
  92. void tty_font::handle_x_command(int argc, const char **argv)
  93. {
  94.   if (argc >= 1 && strcmp(argv[0], "bold") == 0)
  95.     mode |= BOLD_MODE;
  96.   else if (argc >= 1 && strcmp(argv[0], "underline") == 0)
  97.     mode |= UNDERLINE_MODE;
  98. }
  99. #endif
  100.  
  101. class glyph {
  102.   static glyph *free_list;
  103. public:
  104.   glyph *next;
  105.   short hpos;
  106.   unsigned char code;
  107.   unsigned char mode;
  108.   void *operator new(size_t);
  109.   void operator delete(void *);
  110.   inline int draw_mode() { return mode & (VDRAW_MODE|HDRAW_MODE); }
  111. };
  112.  
  113. glyph *glyph::free_list = 0;
  114.  
  115. void *glyph::operator new(size_t)
  116. {
  117.   if (!free_list) {
  118.     const int BLOCK = 1024;
  119.     free_list = (glyph *)new char[sizeof(glyph)*BLOCK];
  120.     for (int i = 0; i < BLOCK - 1; i++)
  121.       free_list[i].next = free_list + i + 1;
  122.     free_list[BLOCK - 1].next = 0;
  123.   }
  124.   glyph *p = free_list;
  125.   free_list = free_list->next;
  126.   p->next = 0;
  127.   return p;
  128. }
  129.  
  130. void glyph::operator delete(void *p)
  131. {
  132.   if (p) {
  133.     ((glyph *)p)->next = free_list;
  134.     free_list = (glyph *)p;
  135.   }
  136. }
  137.  
  138. class tty_printer : public printer {
  139.   glyph **lines;
  140.   int nlines;
  141.   int cached_v;
  142.   int cached_vpos;
  143.   void add_char(unsigned char, int, int, unsigned char);
  144. public:
  145.   tty_printer();
  146.   ~tty_printer();
  147.   void set_char(int, font *, const environment *, int);
  148.   void draw(int code, int *p, int np, const environment *env);
  149.   void begin_page(int) { }
  150.   void end_page(int page_length);
  151.   font *make_font(const char *);
  152. };
  153.  
  154. tty_printer::tty_printer() : cached_v(0)
  155. {
  156.   nlines = 66;
  157.   lines = new glyph *[nlines];
  158.   for (int i = 0; i < nlines; i++)
  159.     lines[i] = 0;
  160. }
  161.  
  162. tty_printer::~tty_printer()
  163. {
  164.   a_delete lines;
  165. }
  166.  
  167. void tty_printer::set_char(int i, font *f, const environment *env, int w)
  168. {
  169.   if (w != font::hor)
  170.     fatal("width of character not equal to horizontal resolution");
  171.   add_char(f->get_code(i), env->hpos, env->vpos, ((tty_font *)f)->get_mode());
  172. }
  173.  
  174. void tty_printer::add_char(unsigned char c, int h, int v, unsigned char mode)
  175. {
  176. #if 0
  177.   // This is too expensive.
  178.   if (h % font::hor != 0)
  179.     fatal("horizontal position not a multiple of horizontal resolution");
  180. #endif
  181.   int hpos = h / font::hor;
  182.   if (hpos < SHRT_MIN || hpos > SHRT_MAX) {
  183.     error("character with ridiculous horizontal position discarded");
  184.     return;
  185.   }
  186.   int vpos;
  187.   if (v == cached_v && cached_v != 0)
  188.     vpos = cached_vpos;
  189.   else {
  190.     if (v % font::vert != 0)
  191.       fatal("vertical position not a multiple of vertical resolution");
  192.     vpos = v / font::vert;
  193.     if (vpos > nlines) {
  194.       glyph **old_lines = lines;
  195.       lines = new glyph *[vpos + 1];
  196.       memcpy(lines, old_lines, nlines*sizeof(glyph *));
  197.       for (int i = nlines; i <= vpos; i++)
  198.     lines[i] = 0;
  199.       a_delete old_lines;
  200.       nlines = vpos + 1;
  201.     }
  202.     // Note that the first output line corresponds to groff
  203.     // position font::vert.
  204.     if (vpos <= 0) {
  205.       error("character above first line discarded");
  206.       return;
  207.     }
  208.     cached_v = v;
  209.     cached_vpos = vpos;
  210.   }
  211.   glyph *g = new glyph;
  212.   g->hpos = hpos;
  213.   g->code = c;
  214.   g->mode = mode;
  215.  
  216.   // The list will be reversed later.  After reversal, it must be in
  217.   // increasing order of hpos, with HDRAW characters before VDRAW
  218.   // characters before normal characters at each hpos, and otherwise
  219.   // in order of occurrence.
  220.  
  221.   glyph **pp;
  222.   for (pp = lines + (vpos - 1); *pp; pp = &(*pp)->next)
  223.     if ((*pp)->hpos < hpos
  224.     || ((*pp)->hpos == hpos && (*pp)->draw_mode() >= g->draw_mode()))
  225.       break;
  226.  
  227.   g->next = *pp;
  228.   *pp = g;
  229. }
  230.  
  231. void tty_printer::draw(int code, int *p, int np, const environment *env)
  232. {
  233.   if (code != 'l' || !draw_flag)
  234.     return;
  235.   if (np != 2) {
  236.     error("2 arguments required for line");
  237.     return;
  238.   }
  239.   if (p[0] == 0) {
  240.     // vertical line
  241.     int v = env->vpos;
  242.     int len = p[1];
  243.     if (len < 0) {
  244.       v += len;
  245.       len = -len;
  246.     }
  247.     while (len >= 0) {
  248.       add_char('|', env->hpos, v, VDRAW_MODE);
  249.       len -= font::vert;
  250.       v += font::vert;
  251.     }
  252.   }
  253.   if (p[1] == 0) {
  254.     // horizontal line
  255.     int h = env->hpos;
  256.     int len = p[0];
  257.     if (len < 0) {
  258.       h += len;
  259.       len = -len;
  260.     }
  261.     while (len >= 0) {
  262.       add_char('-', h, env->vpos, HDRAW_MODE);
  263.       len -= font::hor;
  264.       h += font::hor;
  265.     }
  266.   }
  267. }
  268.  
  269. void tty_printer::end_page(int page_length)
  270. {
  271.   if (page_length % font::vert != 0)
  272.     error("vertical position at end of page not multiple of vertical resolution");
  273.   int lines_per_page = page_length / font::vert;
  274.   int last_line;
  275.   for (last_line = nlines; last_line > 0; last_line--)
  276.     if (lines[last_line - 1])
  277.       break;
  278. #if 0
  279.   if (last_line > lines_per_page) {
  280.     error("characters past last line discarded");
  281.     do {
  282.       --last_line;
  283.       while (lines[last_line]) {
  284.     glyph *tem = lines[last_line];
  285.     lines[last_line] = tem->next;
  286.     delete tem;
  287.       }
  288.     } while (last_line > lines_per_page);
  289.   }
  290. #endif
  291.   for (int i = 0; i < last_line; i++) {
  292.     glyph *p = lines[i];
  293.     lines[i] = 0;
  294.     glyph *g = 0;
  295.     while (p) {
  296.       glyph *tem = p->next;
  297.       p->next = g;
  298.       g = p;
  299.       p = tem;
  300.     }
  301.     int hpos = 0;
  302.     
  303.     glyph *nextp;
  304.     for (p = g; p; delete p, p = nextp) {
  305.       nextp = p->next;
  306.       if (nextp && p->hpos == nextp->hpos) {
  307.     if (p->draw_mode() == HDRAW_MODE && nextp->draw_mode() == VDRAW_MODE) {
  308.       nextp->code = '+';
  309.       continue;
  310.     }
  311.     if (p->draw_mode() != 0 && p->draw_mode() == nextp->draw_mode()) {
  312.       nextp->code = p->code;
  313.       continue;
  314.     }
  315.     if (!overstrike_flag)
  316.       continue;
  317.       }
  318.       if (hpos > p->hpos) {
  319.     do {
  320.       putchar('\b');
  321.       hpos--;
  322.     } while (hpos > p->hpos);
  323.       }
  324.       else {
  325.     if (horizontal_tab_flag) {
  326.       for (;;) {
  327.         int next_tab_pos = ((hpos + TAB_WIDTH) / TAB_WIDTH) * TAB_WIDTH;
  328.         if (next_tab_pos > p->hpos)
  329.           break;
  330.         putchar('\t');
  331.         hpos = next_tab_pos;
  332.       }
  333.     }
  334.     for (; hpos < p->hpos; hpos++)
  335.       putchar(' ');
  336.       }
  337.       assert(hpos == p->hpos);
  338.       if (p->mode & UNDERLINE_MODE) {
  339.     putchar('_');
  340.     putchar('\b');
  341.       }
  342.       if (p->mode & BOLD_MODE) {
  343.     putchar(p->code);
  344.     putchar('\b');
  345.       }
  346.       putchar(p->code);
  347.       hpos++;
  348.     }
  349.     putchar('\n');
  350.   }
  351.   if (form_feed_flag) {
  352.     if (last_line < lines_per_page)
  353.       putchar('\f');
  354.   }
  355.   else {
  356.     for (; last_line < lines_per_page; last_line++)
  357.       putchar('\n');
  358.   }
  359. }
  360.  
  361. font *tty_printer::make_font(const char *nm)
  362. {
  363.   return tty_font::load_tty_font(nm);
  364. }
  365.  
  366. printer *make_printer()
  367. {
  368.   return new tty_printer;
  369. }
  370.  
  371. static void usage();
  372.  
  373. int main(int argc, char **argv)
  374. {
  375.   program_name = argv[0];
  376.   static char stderr_buf[BUFSIZ];
  377.   setbuf(stderr, stderr_buf);
  378.   int c;
  379.   while ((c = getopt(argc, argv, "F:vhfbuoBUd")) != EOF)
  380.     switch(c) {
  381.     case 'v':
  382.       {
  383.     extern const char *version_string;
  384.     fprintf(stderr, "grotty version %s\n", version_string);
  385.     fflush(stderr);
  386.     break;
  387.       }
  388.     case 'b':
  389.       // Do not embolden by overstriking.
  390.       bold_flag = 0;
  391.       break;
  392.     case 'u':
  393.       // Do not underline.
  394.       underline_flag = 0;
  395.       break;
  396.     case 'o':
  397.       // Do not overstrike (other than emboldening and underlining).
  398.       overstrike_flag = 0;
  399.       break;
  400.     case 'B':
  401.       // Do bold-underlining as bold.
  402.       bold_underline_mode = BOLD_MODE;
  403.       break;
  404.     case 'U':
  405.       // Do bold-underlining as underlining.
  406.       bold_underline_mode = UNDERLINE_MODE;
  407.       break;
  408.     case 'h':
  409.       // Use horizontal tabs.
  410.       horizontal_tab_flag = 1;
  411.       break;
  412.     case 'f':
  413.       form_feed_flag = 1;
  414.       break;
  415.     case 'F':
  416.       font::command_line_font_dir(optarg);
  417.       break;
  418.     case 'd':
  419.       // Ignore \D commands.
  420.       draw_flag = 0;
  421.       break;
  422.     case '?':
  423.       usage();
  424.       break;
  425.     default:
  426.       assert(0);
  427.     }
  428.   if (optind >= argc)
  429.     do_file("-");
  430.   else {
  431.     for (int i = optind; i < argc; i++)
  432.       do_file(argv[i]);
  433.   }
  434.   delete pr;
  435.   return 0;
  436. }
  437.  
  438. static void usage()
  439. {
  440.   fprintf(stderr, "usage: %s [-hfvbuodBU] [-F dir] [files ...]\n",
  441.       program_name);
  442.   exit(1);
  443. }
  444.