PageRenderTime 93ms CodeModel.GetById 27ms app.highlight 62ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/groff/src/preproc/eqn/text.cpp

https://bitbucket.org/freebsd/freebsd-head/
C++ | 528 lines | 461 code | 46 blank | 21 comment | 86 complexity | 14e4a7e6b92a8fde86ee57fcbf436354 MD5 | raw file
  1// -*- C++ -*-
  2/* Copyright (C) 1989, 1990, 1991, 1992, 2003 Free Software Foundation, Inc.
  3     Written by James Clark (jjc@jclark.com)
  4
  5This file is part of groff.
  6
  7groff is free software; you can redistribute it and/or modify it under
  8the terms of the GNU General Public License as published by the Free
  9Software Foundation; either version 2, or (at your option) any later
 10version.
 11
 12groff is distributed in the hope that it will be useful, but WITHOUT ANY
 13WARRANTY; without even the implied warranty of MERCHANTABILITY or
 14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 15for more details.
 16
 17You should have received a copy of the GNU General Public License along
 18with groff; see the file COPYING.  If not, write to the Free Software
 19Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
 20
 21#include "eqn.h"
 22#include "pbox.h"
 23#include "ptable.h"
 24
 25class char_box : public simple_box {
 26  unsigned char c;
 27  char next_is_italic;
 28  char prev_is_italic;
 29public:
 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
 40class special_char_box : public simple_box {
 41  char *s;
 42public:
 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
 51const 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
 64const int DIGIT_TYPE = 0;
 65const int LETTER_TYPE = 1;
 66
 67const char *font_type_table[] = {
 68  "digit",
 69  "letter",
 70  0,
 71};
 72
 73struct char_info {
 74  int spacing_type;
 75  int font_type;
 76  char_info();
 77};
 78
 79char_info::char_info()
 80: spacing_type(ORDINARY_TYPE), font_type(DIGIT_TYPE)
 81{
 82}
 83
 84static char_info char_table[256];
 85
 86declare_ptable(char_info)
 87implement_ptable(char_info)
 88
 89PTABLE(char_info) special_char_table;
 90
 91static 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
 97static 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
103static 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[1];
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
116void 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
141static 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
149static 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
157void 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
167char_box::char_box(unsigned char cc)
168: c(cc), next_is_italic(0), prev_is_italic(0)
169{
170  spacing_type = char_table[c].spacing_type;
171}
172
173void 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
181void 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
200int char_box::left_is_italic()
201{
202  int font_type = char_table[c].font_type;
203  return font_type == LETTER_TYPE;
204}
205
206int char_box::right_is_italic()
207{
208  int font_type = char_table[c].font_type;
209  return font_type == LETTER_TYPE;
210}
211
212int char_box::is_char()
213{
214  return 1;
215}
216
217void char_box::debug_print()
218{
219  if (c == '\\') {
220    putc('\\', stderr);
221    putc('\\', stderr);
222  }
223  else
224    putc(c, stderr);
225}
226
227special_char_box::special_char_box(const char *t)
228{
229  s = strsave(t);
230  spacing_type = get_special_char_spacing_type(s);
231}
232
233special_char_box::~special_char_box()
234{
235  a_delete s;
236}
237
238void 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
248int special_char_box::is_char()
249{
250  return 1;
251}
252
253void special_char_box::debug_print()
254{
255  fprintf(stderr, "\\[%s]", s);
256}
257
258
259void 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
267void special_char_box::handle_char_type(int st, int ft)
268{
269  set_special_char_type(s, st, ft);
270}
271
272void 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''
288will be tucked under the prime */
289
290class prime_box : public pointer_box {
291  box *pb;
292public:
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
302box *make_prime_box(box *pp)
303{
304  return new prime_box(pp);
305}
306
307prime_box::prime_box(box *pp) : pointer_box(pp)
308{
309  pb = new special_char_box("fm");
310}
311
312prime_box::~prime_box()
313{
314  delete pb;
315}
316
317int 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
333void 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
341void prime_box::output()
342{
343  p->output();
344  pb->output();
345}
346
347void 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
353void prime_box::debug_print()
354{
355  p->debug_print();
356  putc('\'', stderr);
357}
358
359box *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  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);
527}
528