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