Imported Upstream version 1.22.4
[platform/upstream/groff.git] / src / preproc / refer / token.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989-2018 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 "refer.h"
21 #include "token.h"
22
23 #define TOKEN_TABLE_SIZE 1009
24 // I believe in Icelandic thorn sorts after z.
25 #define THORN_SORT_KEY "{"
26
27 struct token_table_entry {
28   const char *tok;
29   token_info ti;
30   token_table_entry();
31 };
32
33 token_table_entry token_table[TOKEN_TABLE_SIZE];
34 int ntokens = 0;
35
36 static void skip_name(const char **ptr, const char *end)
37 {
38   if (*ptr < end) {
39     switch (*(*ptr)++) {
40     case '(':
41       if (*ptr < end) {
42         *ptr += 1;
43         if (*ptr < end)
44           *ptr += 1;
45       }
46       break;
47     case '[':
48       while (*ptr < end)
49         if (*(*ptr)++ == ']')
50           break;
51       break;
52     }
53   }
54 }
55
56 int get_token(const char **ptr, const char *end)
57 {
58   if (*ptr >= end)
59     return 0;
60   char c = *(*ptr)++;
61   if (c == '\\' && *ptr < end) {
62     switch (**ptr) {
63     default:
64       *ptr += 1;
65       break;
66     case '(':
67     case '[':
68       skip_name(ptr, end);
69       break;
70     case '*':
71     case 'f':
72       *ptr += 1;
73       skip_name(ptr, end);
74       break;
75     }
76   }
77   return 1;
78 }
79
80 token_info::token_info()
81 : type(TOKEN_OTHER), sort_key(0), other_case(0)
82 {
83 }
84
85 void token_info::set(token_type t, const char *sk, const char *oc)
86 {
87   assert(oc == 0 || t == TOKEN_UPPER || t == TOKEN_LOWER);
88   type = t;
89   sort_key = sk;
90   other_case = oc;
91 }
92
93 void token_info::sortify(const char *start, const char *end, string &result)
94      const
95 {
96   if (sort_key)
97     result += sort_key;
98   else if (type == TOKEN_UPPER || type == TOKEN_LOWER) {
99     for (; start < end; start++)
100       if (csalpha(*start))
101         result += cmlower(*start);
102   }
103 }
104
105 int token_info::sortify_non_empty(const char *start, const char *end) const
106 {
107   if (sort_key)
108     return *sort_key != '\0';
109   if (type != TOKEN_UPPER && type != TOKEN_LOWER)
110     return 0;
111   for (; start < end; start++)
112     if (csalpha(*start))
113       return 1;
114   return 0;
115 }
116
117
118 void token_info::lower_case(const char *start, const char *end,
119                             string &result) const
120 {
121   if (type != TOKEN_UPPER) {
122     while (start < end)
123       result += *start++;
124   }
125   else if (other_case)
126     result += other_case;
127   else {
128     while (start < end)
129       result += cmlower(*start++);
130   }
131 }
132
133 void token_info::upper_case(const char *start, const char *end,
134                             string &result) const
135 {
136   if (type != TOKEN_LOWER) {
137     while (start < end)
138       result += *start++;
139   }
140   else if (other_case)
141     result += other_case;
142   else {
143     while (start < end)
144       result += cmupper(*start++);
145   }
146 }
147
148 token_table_entry::token_table_entry()
149 : tok(0)
150 {
151 }
152
153 static void store_token(const char *tok, token_type typ,
154                         const char *sk = 0, const char *oc = 0)
155 {
156   unsigned n = hash_string(tok, strlen(tok)) % TOKEN_TABLE_SIZE;
157   for (;;) {
158     if (token_table[n].tok == 0) {
159       if (++ntokens == TOKEN_TABLE_SIZE)
160         assert(0);
161       token_table[n].tok = tok;
162       break;
163     }
164     if (strcmp(tok, token_table[n].tok) == 0)
165       break;
166     if (n == 0)
167       n = TOKEN_TABLE_SIZE - 1;
168     else
169       --n;
170   }
171   token_table[n].ti.set(typ, sk, oc);
172 }
173
174
175 token_info default_token_info;
176
177 const token_info *lookup_token(const char *start, const char *end)
178 {
179   unsigned n = hash_string(start, end - start) % TOKEN_TABLE_SIZE;
180   for (;;) {
181     if (token_table[n].tok == 0)
182       break;
183     if (strlen(token_table[n].tok) == size_t(end - start)
184         && memcmp(token_table[n].tok, start, end - start) == 0)
185       return &(token_table[n].ti);
186     if (n == 0)
187       n = TOKEN_TABLE_SIZE - 1;
188     else
189       --n;
190   }
191   return &default_token_info;
192 }
193
194 static void init_ascii()
195 {
196   const char *p;
197   for (p = "abcdefghijklmnopqrstuvwxyz"; *p; p++) {
198     char buf[2];
199     buf[0] = *p;
200     buf[1] = '\0';
201     store_token(strsave(buf), TOKEN_LOWER);
202     buf[0] = cmupper(buf[0]);
203     store_token(strsave(buf), TOKEN_UPPER);
204   }
205   for (p = "0123456789"; *p; p++) {
206     char buf[2];
207     buf[0] = *p;
208     buf[1] = '\0';
209     const char *s = strsave(buf);
210     store_token(s, TOKEN_OTHER, s);
211   }
212   for (p = ".,:;?!"; *p; p++) {
213     char buf[2];
214     buf[0] = *p;
215     buf[1] = '\0';
216     store_token(strsave(buf), TOKEN_PUNCT);
217   }
218   store_token("-", TOKEN_HYPHEN);
219 }
220
221 static void store_letter(const char *lower, const char *upper,
222                   const char *sort_key = 0)
223 {
224   store_token(lower, TOKEN_LOWER, sort_key, upper);
225   store_token(upper, TOKEN_UPPER, sort_key, lower);
226 }
227
228 static void init_letter(unsigned char uc_code, unsigned char lc_code,
229                  const char *sort_key)
230 {
231   char lbuf[2];
232   lbuf[0] = lc_code;
233   lbuf[1] = 0;
234   char ubuf[2];
235   ubuf[0] = uc_code;
236   ubuf[1] = 0;
237   store_letter(strsave(lbuf), strsave(ubuf), sort_key);
238 }
239
240 static void init_latin1()
241 {
242   init_letter(0xc0, 0xe0, "a");
243   init_letter(0xc1, 0xe1, "a");
244   init_letter(0xc2, 0xe2, "a");
245   init_letter(0xc3, 0xe3, "a");
246   init_letter(0xc4, 0xe4, "a");
247   init_letter(0xc5, 0xe5, "a");
248   init_letter(0xc6, 0xe6, "ae");
249   init_letter(0xc7, 0xe7, "c");
250   init_letter(0xc8, 0xe8, "e");
251   init_letter(0xc9, 0xe9, "e");
252   init_letter(0xca, 0xea, "e");
253   init_letter(0xcb, 0xeb, "e");
254   init_letter(0xcc, 0xec, "i");
255   init_letter(0xcd, 0xed, "i");
256   init_letter(0xce, 0xee, "i");
257   init_letter(0xcf, 0xef, "i");
258
259   init_letter(0xd0, 0xf0, "d");
260   init_letter(0xd1, 0xf1, "n");
261   init_letter(0xd2, 0xf2, "o");
262   init_letter(0xd3, 0xf3, "o");
263   init_letter(0xd4, 0xf4, "o");
264   init_letter(0xd5, 0xf5, "o");
265   init_letter(0xd6, 0xf6, "o");
266   init_letter(0xd8, 0xf8, "o");
267   init_letter(0xd9, 0xf9, "u");
268   init_letter(0xda, 0xfa, "u");
269   init_letter(0xdb, 0xfb, "u");
270   init_letter(0xdc, 0xfc, "u");
271   init_letter(0xdd, 0xfd, "y");
272   init_letter(0xde, 0xfe, THORN_SORT_KEY);
273
274   store_token("\337", TOKEN_LOWER, "ss", "SS");
275   store_token("\377", TOKEN_LOWER, "y", "Y");
276 }
277
278 static void init_two_char_letter(char l1, char l2, char u1, char u2,
279                                  const char *sk = 0)
280 {
281   char buf[6];
282   buf[0] = '\\';
283   buf[1] = '(';
284   buf[2] = l1;
285   buf[3] = l2;
286   buf[4] = '\0';
287   const char *p = strsave(buf);
288   buf[2] = u1;
289   buf[3] = u2;
290   store_letter(p, strsave(buf), sk);
291   buf[1] = '[';
292   buf[4] = ']';
293   buf[5] = '\0';
294   p = strsave(buf);
295   buf[2] = l1;
296   buf[3] = l2;
297   store_letter(strsave(buf), p, sk);
298   
299 }
300
301 static void init_special_chars()
302 {
303   const char *p;
304   for (p = "':^`~"; *p; p++)
305     for (const char *q = "aeiouy"; *q; q++) {
306       // Use a variable to work around bug in gcc 2.0
307       char c = cmupper(*q);
308       init_two_char_letter(*p, *q, *p, c);
309     }
310   for (p = "/l/o~n,coeaeij"; *p; p += 2) {
311     // Use variables to work around bug in gcc 2.0
312     char c0 = cmupper(p[0]);
313     char c1 = cmupper(p[1]);
314     init_two_char_letter(p[0], p[1], c0, c1);
315   }
316   init_two_char_letter('v', 's', 'v', 'S', "s");
317   init_two_char_letter('v', 'z', 'v', 'Z', "z");
318   init_two_char_letter('o', 'a', 'o', 'A', "a");
319   init_two_char_letter('T', 'p', 'T', 'P', THORN_SORT_KEY);
320   init_two_char_letter('-', 'd', '-', 'D');
321   
322   store_token("\\(ss", TOKEN_LOWER, 0, "SS");
323   store_token("\\[ss]", TOKEN_LOWER, 0, "SS");
324
325   store_token("\\(Sd", TOKEN_LOWER, "d", "\\(-D");
326   store_token("\\[Sd]", TOKEN_LOWER, "d", "\\[-D]");
327   store_token("\\(hy", TOKEN_HYPHEN);
328   store_token("\\[hy]", TOKEN_HYPHEN);
329   store_token("\\(en", TOKEN_RANGE_SEP);
330   store_token("\\[en]", TOKEN_RANGE_SEP);
331 }
332
333 static void init_strings()
334 {
335   char buf[6];
336   buf[0] = '\\';
337   buf[1] = '*';
338   for (const char *p = "'`^^,:~v_o./;"; *p; p++) {
339     buf[2] = *p;
340     buf[3] = '\0';
341     store_token(strsave(buf), TOKEN_ACCENT);
342     buf[2] = '[';
343     buf[3] = *p;
344     buf[4] = ']';
345     buf[5] = '\0';
346     store_token(strsave(buf), TOKEN_ACCENT);
347   }
348
349   // -ms special letters
350   store_letter("\\*(th", "\\*(Th", THORN_SORT_KEY);
351   store_letter("\\*[th]", "\\*[Th]", THORN_SORT_KEY);
352   store_letter("\\*(d-", "\\*(D-");
353   store_letter("\\*[d-]", "\\*[D-]");
354   store_letter("\\*(ae", "\\*(Ae", "ae");
355   store_letter("\\*[ae]", "\\*[Ae]", "ae");
356   store_letter("\\*(oe", "\\*(Oe", "oe");
357   store_letter("\\*[oe]", "\\*[Oe]", "oe");
358
359   store_token("\\*3", TOKEN_LOWER, "y", "Y");
360   store_token("\\*8", TOKEN_LOWER, "ss", "SS");
361   store_token("\\*q", TOKEN_LOWER, "o", "O");
362 }
363
364 struct token_initer {
365   token_initer();
366 };
367
368 static token_initer the_token_initer;
369
370 token_initer::token_initer()
371 {
372   init_ascii();
373   init_latin1();
374   init_special_chars();
375   init_strings();
376   default_token_info.set(TOKEN_OTHER);
377 }