groff: update vendor branch to v1.20.1
[dragonfly.git] / contrib / groff / src / libs / libgroff / nametoindex.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2006,
3                  2008, 2009
4    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 3 of the License, or
12 (at your option) any later 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
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22 #include "lib.h"
23
24 #include <ctype.h>
25 #include <assert.h>
26 #include <stdlib.h>
27 #include "errarg.h"
28 #include "error.h"
29 #include "font.h"
30 #include "ptable.h"
31 #include "itable.h"
32
33 // Every glyphinfo is actually a charinfo.
34 class charinfo : glyph {
35 public:
36   const char *name;     // The glyph name, or NULL.
37   friend class character_indexer;
38 };
39
40 // PTABLE(charinfo) is a hash table mapping `const char *' to `charinfo *'.
41 declare_ptable(charinfo)
42 implement_ptable(charinfo)
43
44 // ITABLE(charinfo) is a hash table mapping `int >= 0' to `charinfo *'.
45 declare_itable(charinfo)
46 implement_itable(charinfo)
47
48 // This class is as a registry storing all named and numbered glyphs known
49 // so far, and assigns a unique index to each glyph.
50 class character_indexer {
51 public:
52   character_indexer();
53   ~character_indexer();
54   // --------------------- Lookup or creation of a glyph.
55   glyph *ascii_char_glyph(unsigned char);
56   glyph *named_char_glyph(const char *);
57   glyph *numbered_char_glyph(int);
58 private:
59   int next_index;               // Number of glyphs already allocated.
60   PTABLE(charinfo) table;       // Table mapping name to glyph.
61   glyph *ascii_glyph[256];      // Shorthand table for looking up "charNNN"
62                                 // glyphs.
63   ITABLE(charinfo) ntable;      // Table mapping number to glyph.
64   enum { NSMALL = 256 };
65   glyph *small_number_glyph[NSMALL]; // Shorthand table for looking up
66                                 // numbered glyphs with small numbers.
67 };
68
69 character_indexer::character_indexer()
70 : next_index(0)
71 {
72   int i;
73   for (i = 0; i < 256; i++)
74     ascii_glyph[i] = UNDEFINED_GLYPH;
75   for (i = 0; i < NSMALL; i++)
76     small_number_glyph[i] = UNDEFINED_GLYPH;
77 }
78
79 character_indexer::~character_indexer()
80 {
81 }
82
83 glyph *character_indexer::ascii_char_glyph(unsigned char c)
84 {
85   if (ascii_glyph[c] == UNDEFINED_GLYPH) {
86     char buf[4+3+1];
87     memcpy(buf, "char", 4);
88     strcpy(buf + 4, i_to_a(c));
89     charinfo *ci = new charinfo;
90     ci->index = next_index++;
91     ci->number = -1;
92     ci->name = strsave(buf);
93     ascii_glyph[c] = ci;
94   }
95   return ascii_glyph[c];
96 }
97
98 inline glyph *character_indexer::named_char_glyph(const char *s)
99 {
100   // Glyphs with name `charNNN' are only stored in ascii_glyph[], not
101   // in the table.  Therefore treat them specially here.
102   if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') {
103     char *val;
104     long n = strtol(s + 4, &val, 10);
105     if (val != s + 4 && *val == '\0' && n >= 0 && n < 256)
106       return ascii_char_glyph((unsigned char)n);
107   }
108   charinfo *ci = table.lookupassoc(&s);
109   if (ci == NULL) {
110     ci = new charinfo[1];
111     ci->index = next_index++;
112     ci->number = -1;
113     ci->name = table.define(s, ci);
114   }
115   return ci;
116 }
117
118 inline glyph *character_indexer::numbered_char_glyph(int n)
119 {
120   if (n >= 0 && n < NSMALL) {
121     if (small_number_glyph[n] == UNDEFINED_GLYPH) {
122       charinfo *ci = new charinfo;
123       ci->index = next_index++;
124       ci->number = n;
125       ci->name = NULL;
126       small_number_glyph[n] = ci;
127     }
128     return small_number_glyph[n];
129   }
130   charinfo *ci = ntable.lookup(n);
131   if (ci == NULL) {
132     ci = new charinfo[1];
133     ci->index = next_index++;
134     ci->number = n;
135     ci->name = NULL;
136     ntable.define(n, ci);
137   }
138   return ci;
139 }
140
141 static character_indexer indexer;
142
143 glyph *number_to_glyph(int n)
144 {
145   return indexer.numbered_char_glyph(n);
146 }
147
148 // troff overrides this function with its own version.
149
150 glyph *name_to_glyph(const char *s)
151 {
152   assert(s != 0 && s[0] != '\0' && s[0] != ' ');
153   if (s[1] == '\0')
154     // \200 and char128 are synonyms
155     return indexer.ascii_char_glyph(s[0]);
156   return indexer.named_char_glyph(s);
157 }
158
159 const char *glyph_to_name(glyph *g)
160 {
161   charinfo *ci = (charinfo *)g; // Every glyph is actually a charinfo.
162   return ci->name;
163 }