home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / gnu / groff-1.09-src.lha / src / amiga / groff-1.09 / eqn / text.cc < prev    next >
C/C++ Source or Header  |  1992-08-03  |  11KB  |  529 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.com)
  4.  
  5. This file is part of groff.
  6.  
  7. groff is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 2, or (at your option) any later
  10. version.
  11.  
  12. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License along
  18. with groff; see the file COPYING.  If not, write to the Free Software
  19. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21. #include "eqn.h"
  22. #include "pbox.h"
  23. #include "ptable.h"
  24.  
  25. class char_box : public simple_box {
  26.   unsigned char c;
  27.   char next_is_italic;
  28.   char prev_is_italic;
  29. public:
  30.   char_box(unsigned char);
  31.   void debug_print();
  32.   void output();
  33.   int is_char();
  34.   int left_is_italic();
  35.   int right_is_italic();
  36.   void hint(unsigned);
  37.   void handle_char_type(int, int);
  38. };
  39.  
  40. class special_char_box : public simple_box {
  41.   char *s;
  42. public:
  43.   special_char_box(const char *);
  44.   ~special_char_box();
  45.   void output();
  46.   void debug_print();
  47.   int is_char();
  48.   void handle_char_type(int, int);
  49. };
  50.  
  51. const char *spacing_type_table[] = {
  52.   "ordinary",
  53.   "operator",
  54.   "binary",
  55.   "relation",
  56.   "opening",
  57.   "closing",
  58.   "punctuation",
  59.   "inner",
  60.   "suppress",
  61.   0,
  62. };
  63.  
  64. const int DIGIT_TYPE = 0;
  65. const int LETTER_TYPE = 1;
  66.  
  67. const char *font_type_table[] = {
  68.   "digit",
  69.   "letter",
  70.   0,
  71. };
  72.  
  73. struct char_info {
  74.   int spacing_type;
  75.   int font_type;
  76.   char_info();
  77. };
  78.  
  79. char_info::char_info()
  80. : spacing_type(ORDINARY_TYPE), font_type(DIGIT_TYPE)
  81. {
  82. }
  83.  
  84. static char_info char_table[256];
  85.  
  86. declare_ptable(char_info)
  87. implement_ptable(char_info)
  88.  
  89. PTABLE(char_info) special_char_table;
  90.  
  91. static int get_special_char_spacing_type(const char *ch)
  92. {
  93.   char_info *p = special_char_table.lookup(ch);
  94.   return p ? p->spacing_type : ORDINARY_TYPE;
  95. }
  96.  
  97. static int get_special_char_font_type(const char *ch)
  98. {
  99.   char_info *p = special_char_table.lookup(ch);
  100.   return p ? p->font_type : DIGIT_TYPE;
  101. }
  102.  
  103. static void set_special_char_type(const char *ch, int st, int ft)
  104. {
  105.   char_info *p = special_char_table.lookup(ch);
  106.   if (!p) {
  107.     p = new char_info;
  108.     special_char_table.define(ch, p);
  109.   }
  110.   if (st >= 0)
  111.     p->spacing_type = st;
  112.   if (ft >= 0)
  113.     p->font_type = ft;
  114. }
  115.  
  116. void init_char_table()
  117. {
  118.   set_special_char_type("pl", 2, -1); // binary
  119.   set_special_char_type("mi", 2, -1);
  120.   set_special_char_type("eq", 3, -1); // relation
  121.   set_special_char_type("<=", 3, -1);
  122.   set_special_char_type(">=", 3, -1);
  123.   char_table['}'].spacing_type = 5; // closing
  124.   char_table[')'].spacing_type = 5;
  125.   char_table[']'].spacing_type = 5;
  126.   char_table['{'].spacing_type = 4; // opening
  127.   char_table['('].spacing_type = 4;
  128.   char_table['['].spacing_type = 4;
  129.   char_table[','].spacing_type = 6; // punctuation
  130.   char_table[';'].spacing_type = 6;
  131.   char_table[':'].spacing_type = 6;
  132.   char_table['.'].spacing_type = 6;
  133.   char_table['>'].spacing_type = 3;
  134.   char_table['<'].spacing_type = 3;
  135.   char_table['*'].spacing_type = 2; // binary
  136.   for (int i = 0; i < 256; i++)
  137.     if (csalpha(i))
  138.       char_table[i].font_type = LETTER_TYPE;
  139. }
  140.  
  141. static int lookup_spacing_type(const char *type)
  142. {
  143.   for (int i = 0; spacing_type_table[i] != 0; i++)
  144.     if (strcmp(spacing_type_table[i], type) == 0)
  145.       return i;
  146.   return -1;
  147. }
  148.  
  149. static int lookup_font_type(const char *type)
  150. {
  151.   for (int i = 0; font_type_table[i] != 0; i++)
  152.     if (strcmp(font_type_table[i], type) == 0)
  153.       return i;
  154.   return -1;
  155. }
  156.  
  157. void box::set_spacing_type(char *type)
  158. {
  159.   int t = lookup_spacing_type(type);
  160.   if (t < 0)
  161.     error("unrecognised type `%1'", type);
  162.   else
  163.     spacing_type = t;
  164.   a_delete type;
  165. }
  166.  
  167. char_box::char_box(unsigned char cc)
  168. : c(cc), prev_is_italic(0), next_is_italic(0)
  169. {
  170.   spacing_type = char_table[c].spacing_type;
  171. }
  172.  
  173. void char_box::hint(unsigned flags)
  174. {
  175.   if (flags & HINT_PREV_IS_ITALIC)
  176.     prev_is_italic = 1;
  177.   if (flags & HINT_NEXT_IS_ITALIC)
  178.     next_is_italic = 1;
  179. }
  180.  
  181. void char_box::output()
  182. {
  183.   int font_type = char_table[c].font_type;
  184.   if (font_type != LETTER_TYPE)
  185.     printf("\\f[%s]", current_roman_font);
  186.   if (!prev_is_italic)
  187.     fputs("\\,", stdout);
  188.   if (c == '\\')
  189.     fputs("\\e", stdout);
  190.   else
  191.     putchar(c);
  192.   if (!next_is_italic)
  193.     fputs("\\/", stdout);
  194.   else
  195.     fputs("\\&", stdout);        // suppress ligaturing and kerning
  196.   if (font_type != LETTER_TYPE)
  197.     fputs("\\fP", stdout);
  198. }
  199.  
  200. int char_box::left_is_italic()
  201. {
  202.   int font_type = char_table[c].font_type;
  203.   return font_type == LETTER_TYPE;
  204. }
  205.  
  206. int char_box::right_is_italic()
  207. {
  208.   int font_type = char_table[c].font_type;
  209.   return font_type == LETTER_TYPE;
  210. }
  211.  
  212. int char_box::is_char()
  213. {
  214.   return 1;
  215. }
  216.  
  217. void char_box::debug_print()
  218. {
  219.   if (c == '\\') {
  220.     putc('\\', stderr);
  221.     putc('\\', stderr);
  222.   }
  223.   else
  224.     putc(c, stderr);
  225. }
  226.  
  227. special_char_box::special_char_box(const char *t)
  228. {
  229.   s = strsave(t);
  230.   spacing_type = get_special_char_spacing_type(s);
  231. }
  232.  
  233. special_char_box::~special_char_box()
  234. {
  235.   a_delete s;
  236. }
  237.  
  238. void special_char_box::output()
  239. {
  240.   int font_type = get_special_char_font_type(s);
  241.   if (font_type != LETTER_TYPE)
  242.     printf("\\f[%s]", current_roman_font);
  243.   printf("\\,\\[%s]\\/", s);
  244.   if (font_type != LETTER_TYPE)
  245.     printf("\\fP");
  246. }
  247.  
  248. int special_char_box::is_char()
  249. {
  250.   return 1;
  251. }
  252.  
  253. void special_char_box::debug_print()
  254. {
  255.   fprintf(stderr, "\\[%s]", s);
  256. }
  257.  
  258.  
  259. void char_box::handle_char_type(int st, int ft)
  260. {
  261.   if (st >= 0)
  262.     char_table[c].spacing_type = st;
  263.   if (ft >= 0)
  264.     char_table[c].font_type = ft;
  265. }
  266.  
  267. void special_char_box::handle_char_type(int st, int ft)
  268. {
  269.   set_special_char_type(s, st, ft);
  270. }
  271.  
  272. void set_char_type(const char *type, char *ch)
  273. {
  274.   assert(ch != 0);
  275.   int st = lookup_spacing_type(type);
  276.   int ft = lookup_font_type(type);
  277.   if (st < 0 && ft < 0) {
  278.     error("bad character type `%1'", type);
  279.     a_delete ch;
  280.     return;
  281.   }
  282.   box *b = split_text(ch);
  283.   b->handle_char_type(st, ft);
  284.   delete b;
  285. }
  286.  
  287. /* We give primes special treatment so that in ``x' sub 2'', the ``2''
  288. will be tucked under the prime */
  289.  
  290. class prime_box : public pointer_box {
  291.   box *pb;
  292. public:
  293.   prime_box(box *);
  294.   ~prime_box();
  295.   int compute_metrics(int style);
  296.   void output();
  297.   void compute_subscript_kern();
  298.   void debug_print();
  299.   void handle_char_type(int, int);
  300. };
  301.  
  302. box *make_prime_box(box *pp)
  303. {
  304.   return new prime_box(pp);
  305. }
  306.  
  307. prime_box::prime_box(box *pp) : pointer_box(pp)
  308. {
  309.   pb = new special_char_box("fm");
  310. }
  311.  
  312. prime_box::~prime_box()
  313. {
  314.   delete pb;
  315. }
  316.  
  317. int prime_box::compute_metrics(int style)
  318. {
  319.   int res = p->compute_metrics(style);
  320.   pb->compute_metrics(style);
  321.   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]"
  322.      "+\\n[" WIDTH_FORMAT "]\n",
  323.      uid, p->uid, pb->uid);
  324.   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
  325.      ">?\\n[" HEIGHT_FORMAT "]\n",
  326.      uid, p->uid, pb->uid);
  327.   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
  328.      ">?\\n[" DEPTH_FORMAT "]\n",
  329.      uid, p->uid, pb->uid);
  330.   return res;
  331. }
  332.  
  333. void prime_box::compute_subscript_kern()
  334. {
  335.   p->compute_subscript_kern();
  336.   printf(".nr " SUB_KERN_FORMAT " 0\\n[" WIDTH_FORMAT "]"
  337.      "+\\n[" SUB_KERN_FORMAT "]>?0\n",
  338.      uid, pb->uid, p->uid);
  339. }
  340.  
  341. void prime_box::output()
  342. {
  343.   p->output();
  344.   pb->output();
  345. }
  346.  
  347. void prime_box::handle_char_type(int st, int ft)
  348. {
  349.   p->handle_char_type(st, ft);
  350.   pb->handle_char_type(st, ft);
  351. }
  352.  
  353. void prime_box::debug_print()
  354. {
  355.   p->debug_print();
  356.   putc('\'', stderr);
  357. }
  358.  
  359. box *split_text(char *text)
  360. {
  361.   list_box *lb = 0;
  362.   box *fb = 0;
  363.   char *s = text;
  364.   while (*s != '\0') {
  365.     char c = *s++;
  366.     box *b = 0;
  367.     switch (c) {
  368.     case '+':
  369.       b = new special_char_box("pl");
  370.       break;
  371.     case '-':
  372.       b = new special_char_box("mi");
  373.       break;
  374.     case '=':
  375.       b = new special_char_box("eq");
  376.       break;
  377.     case '\'':
  378.       b = new special_char_box("fm");
  379.       break;
  380.     case '<':
  381.       if (*s == '=') {
  382.     b = new special_char_box("<=");
  383.     s++;
  384.     break;
  385.       }
  386.       goto normal_char;
  387.     case '>':
  388.       if (*s == '=') {
  389.     b = new special_char_box(">=");
  390.     s++;
  391.     break;
  392.       }
  393.       goto normal_char;
  394.     case '\\':
  395.       if (*s == '\0') {
  396.     lex_error("bad escape");
  397.     break;
  398.       }
  399.       c = *s++;
  400.       switch (c) {
  401.       case '(':
  402.     {
  403.       char buf[3];
  404.       if (*s != '\0') {
  405.         buf[0] = *s++;
  406.         if (*s != '\0') {
  407.           buf[1] = *s++;
  408.           buf[2] = '\0';
  409.           b = new special_char_box(buf);
  410.         }
  411.         else {
  412.           lex_error("bad escape");
  413.         }
  414.       }
  415.       else {
  416.         lex_error("bad escape");
  417.       }
  418.     }
  419.     break;
  420.       case '[':
  421.     {
  422.       char *ch = s;
  423.       while (*s != ']' && *s != '\0')
  424.         s++;
  425.       if (*s == '\0')
  426.         lex_error("bad escape");
  427.       else {
  428.         *s++ = '\0';
  429.         b = new special_char_box(ch);
  430.       }
  431.     }
  432.     break;
  433.       case 'f':
  434.       case 'g':
  435.       case 'k':
  436.       case 'n':
  437.       case '*':
  438.     {
  439.       char *escape_start = s - 2;
  440.       switch (*s) {
  441.       case '(':
  442.         if (*++s != '\0')
  443.           ++s;
  444.         break;
  445.       case '[':
  446.         for (++s; *s != '\0' && *s != ']'; s++)
  447.           ;
  448.         break;
  449.       }
  450.       if (*s == '\0')
  451.         lex_error("bad escape");
  452.       else {
  453.         ++s;
  454.         char *buf = new char[s - escape_start + 1];
  455.         memcpy(buf, escape_start, s - escape_start);
  456.         buf[s - escape_start] = '\0';
  457.         b = new quoted_text_box(buf);
  458.       }
  459.     }
  460.     break;
  461.       case '-':
  462.       case '_':
  463.     {
  464.       char buf[2];
  465.       buf[0] = c;
  466.       buf[1] = '\0';
  467.       b = new special_char_box(buf);
  468.     }
  469.     break;
  470.       case '`':
  471.     b = new special_char_box("ga");
  472.     break;
  473.       case '\'':
  474.     b = new special_char_box("aa");
  475.     break;
  476.       case 'e':
  477.       case '\\':
  478.     b = new char_box('\\');
  479.     break;
  480.       case '^':
  481.       case '|':
  482.       case '0':
  483.     {
  484.       char buf[3];
  485.       buf[0] = '\\';
  486.       buf[1] = c;
  487.       buf[2] = '\0';
  488.       b = new quoted_text_box(strsave(buf));
  489.       break;
  490.     }
  491.       default:
  492.     lex_error("unquoted escape");
  493.     b = new quoted_text_box(strsave(s - 2));
  494.     s = strchr(s, '\0');
  495.     break;
  496.       }
  497.       break;
  498.     default:
  499.     normal_char:
  500.       b = new char_box(c);
  501.       break;
  502.     }
  503.     while (*s == '\'') {
  504.       if (b == 0)
  505.     b = new quoted_text_box(0);
  506.       b = new prime_box(b);
  507.       s++;
  508.     }
  509.     if (b != 0) {
  510.       if (lb != 0)
  511.     lb->append(b);
  512.       else if (fb != 0) {
  513.     lb = new list_box(fb);
  514.     lb->append(b);
  515.       }
  516.       else
  517.     fb = b;
  518.     }
  519.   }
  520.   delete text;
  521.   if (lb != 0)
  522.     return lb;
  523.   else if (fb != 0)
  524.     return fb;
  525.   else
  526.     return new quoted_text_box(0);
  527. }
  528.  
  529.