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