Update to groff 1.19.2.
[dragonfly.git] / contrib / groff-1.19 / src / preproc / eqn / text.cpp
blobe39221276b58c16945deca2cfb52cf53659c8050
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992, 2003 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
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.
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.
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, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
21 #include "eqn.h"
22 #include "pbox.h"
23 #include "ptable.h"
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);
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);
51 const char *spacing_type_table[] = {
52 "ordinary",
53 "operator",
54 "binary",
55 "relation",
56 "opening",
57 "closing",
58 "punctuation",
59 "inner",
60 "suppress",
64 const int DIGIT_TYPE = 0;
65 const int LETTER_TYPE = 1;
67 const char *font_type_table[] = {
68 "digit",
69 "letter",
73 struct char_info {
74 int spacing_type;
75 int font_type;
76 char_info();
79 char_info::char_info()
80 : spacing_type(ORDINARY_TYPE), font_type(DIGIT_TYPE)
84 static char_info char_table[256];
86 declare_ptable(char_info)
87 implement_ptable(char_info)
89 PTABLE(char_info) special_char_table;
91 static int get_special_char_spacing_type(const char *ch)
93 char_info *p = special_char_table.lookup(ch);
94 return p ? p->spacing_type : ORDINARY_TYPE;
97 static int get_special_char_font_type(const char *ch)
99 char_info *p = special_char_table.lookup(ch);
100 return p ? p->font_type : DIGIT_TYPE;
103 static void set_special_char_type(const char *ch, int st, int ft)
105 char_info *p = special_char_table.lookup(ch);
106 if (!p) {
107 p = new char_info[1];
108 special_char_table.define(ch, p);
110 if (st >= 0)
111 p->spacing_type = st;
112 if (ft >= 0)
113 p->font_type = ft;
116 void init_char_table()
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;
141 static int lookup_spacing_type(const char *type)
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;
149 static int lookup_font_type(const char *type)
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;
157 void box::set_spacing_type(char *type)
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;
167 char_box::char_box(unsigned char cc)
168 : c(cc), next_is_italic(0), prev_is_italic(0)
170 spacing_type = char_table[c].spacing_type;
173 void char_box::hint(unsigned flags)
175 if (flags & HINT_PREV_IS_ITALIC)
176 prev_is_italic = 1;
177 if (flags & HINT_NEXT_IS_ITALIC)
178 next_is_italic = 1;
181 void char_box::output()
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);
200 int char_box::left_is_italic()
202 int font_type = char_table[c].font_type;
203 return font_type == LETTER_TYPE;
206 int char_box::right_is_italic()
208 int font_type = char_table[c].font_type;
209 return font_type == LETTER_TYPE;
212 int char_box::is_char()
214 return 1;
217 void char_box::debug_print()
219 if (c == '\\') {
220 putc('\\', stderr);
221 putc('\\', stderr);
223 else
224 putc(c, stderr);
227 special_char_box::special_char_box(const char *t)
229 s = strsave(t);
230 spacing_type = get_special_char_spacing_type(s);
233 special_char_box::~special_char_box()
235 a_delete s;
238 void special_char_box::output()
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");
248 int special_char_box::is_char()
250 return 1;
253 void special_char_box::debug_print()
255 fprintf(stderr, "\\[%s]", s);
259 void char_box::handle_char_type(int st, int ft)
261 if (st >= 0)
262 char_table[c].spacing_type = st;
263 if (ft >= 0)
264 char_table[c].font_type = ft;
267 void special_char_box::handle_char_type(int st, int ft)
269 set_special_char_type(s, st, ft);
272 void set_char_type(const char *type, char *ch)
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;
282 box *b = split_text(ch);
283 b->handle_char_type(st, ft);
284 delete b;
287 /* We give primes special treatment so that in ``x' sub 2'', the ``2''
288 will be tucked under the prime */
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);
302 box *make_prime_box(box *pp)
304 return new prime_box(pp);
307 prime_box::prime_box(box *pp) : pointer_box(pp)
309 pb = new special_char_box("fm");
312 prime_box::~prime_box()
314 delete pb;
317 int prime_box::compute_metrics(int style)
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;
333 void prime_box::compute_subscript_kern()
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);
341 void prime_box::output()
343 p->output();
344 pb->output();
347 void prime_box::handle_char_type(int st, int ft)
349 p->handle_char_type(st, ft);
350 pb->handle_char_type(st, ft);
353 void prime_box::debug_print()
355 p->debug_print();
356 putc('\'', stderr);
359 box *split_text(char *text)
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;
386 goto normal_char;
387 case '>':
388 if (*s == '=') {
389 b = new special_char_box(">=");
390 s++;
391 break;
393 goto normal_char;
394 case '\\':
395 if (*s == '\0') {
396 lex_error("bad escape");
397 break;
399 c = *s++;
400 switch (c) {
401 case '(':
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);
411 else {
412 lex_error("bad escape");
415 else {
416 lex_error("bad escape");
419 break;
420 case '[':
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);
432 break;
433 case 'f':
434 case 'g':
435 case 'k':
436 case 'n':
437 case '*':
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++)
448 break;
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);
460 break;
461 case '-':
462 case '_':
464 char buf[2];
465 buf[0] = c;
466 buf[1] = '\0';
467 b = new special_char_box(buf);
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':
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;
491 default:
492 lex_error("unquoted escape");
493 b = new quoted_text_box(strsave(s - 2));
494 s = strchr(s, '\0');
495 break;
497 break;
498 default:
499 normal_char:
500 b = new char_box(c);
501 break;
503 while (*s == '\'') {
504 if (b == 0)
505 b = new quoted_text_box(0);
506 b = new prime_box(b);
507 s++;
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);
516 else
517 fb = b;
520 a_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);