xref: /netbsd-src/external/gpl2/groff/dist/src/preproc/eqn/text.cpp (revision 89a07cf815a29524268025a1139fac4c5190f765)
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@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 
char_info()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 
get_special_char_spacing_type(const char * ch)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 
get_special_char_font_type(const char * ch)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 
set_special_char_type(const char * ch,int st,int ft)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 
init_char_table()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 
lookup_spacing_type(const char * type)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 
lookup_font_type(const char * type)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 
set_spacing_type(char * type)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 
char_box(unsigned char cc)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 
hint(unsigned flags)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 
output()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 
left_is_italic()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 
right_is_italic()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 
is_char()214 int char_box::is_char()
215 {
216   return 1;
217 }
218 
debug_print()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 
special_char_box(const char * t)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 
~special_char_box()235 special_char_box::~special_char_box()
236 {
237   a_delete s;
238 }
239 
output()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 
is_char()250 int special_char_box::is_char()
251 {
252   return 1;
253 }
254 
debug_print()255 void special_char_box::debug_print()
256 {
257   fprintf(stderr, "\\[%s]", s);
258 }
259 
260 
handle_char_type(int st,int ft)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 
handle_char_type(int st,int ft)269 void special_char_box::handle_char_type(int st, int ft)
270 {
271   set_special_char_type(s, st, ft);
272 }
273 
set_char_type(const char * type,char * ch)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 
make_prime_box(box * pp)304 box *make_prime_box(box *pp)
305 {
306   return new prime_box(pp);
307 }
308 
prime_box(box * pp)309 prime_box::prime_box(box *pp) : pointer_box(pp)
310 {
311   pb = new special_char_box("fm");
312 }
313 
~prime_box()314 prime_box::~prime_box()
315 {
316   delete pb;
317 }
318 
compute_metrics(int style)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 
compute_subscript_kern()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 
output()343 void prime_box::output()
344 {
345   p->output();
346   pb->output();
347 }
348 
handle_char_type(int st,int ft)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 
debug_print()355 void prime_box::debug_print()
356 {
357   p->debug_print();
358   putc('\'', stderr);
359 }
360 
split_text(char * text)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