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