]> git.cameronkatri.com Git - mandoc.git/blob - ascii.c
Moved CALLABLE check to lookup_raw().
[mandoc.git] / ascii.c
1 /* $Id: ascii.c,v 1.9 2009/07/27 12:02:49 kristaps Exp $ */
2 /*
3 * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 #include <assert.h>
18 #include <err.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include "term.h"
23
24 #define ASCII_PRINT_HI 126
25 #define ASCII_PRINT_LO 32
26
27 struct line {
28 const char *code;
29 const char *out;
30 size_t codesz;
31 size_t outsz;
32 int type;
33 #define ASCII_CHAR (1 << 0)
34 #define ASCII_STRING (1 << 1)
35 #define ASCII_BOTH (0x03)
36 };
37
38 struct linep {
39 const struct line *line;
40 struct linep *next;
41 };
42
43 #define CHAR(w, x, y, z) \
44 { (w), (y), (x), (z), ASCII_CHAR },
45 #define STRING(w, x, y, z) \
46 { (w), (y), (x), (z), ASCII_STRING },
47 #define BOTH(w, x, y, z) \
48 { (w), (y), (x), (z), ASCII_BOTH },
49 static const struct line lines[] = {
50 #include "ascii.in"
51 };
52
53 struct asciitab {
54 struct linep *lines;
55 void **htab;
56 };
57
58
59 static inline int match(const struct line *,
60 const char *, size_t, int);
61 static const char * lookup(struct asciitab *, const char *,
62 size_t, size_t *, int);
63
64
65 void
66 term_asciifree(void *arg)
67 {
68 struct asciitab *tab;
69
70 tab = (struct asciitab *)arg;
71
72 free(tab->lines);
73 free(tab->htab);
74 free(tab);
75 }
76
77
78 void *
79 term_ascii2htab(void)
80 {
81 struct asciitab *tab;
82 void **htab;
83 struct linep *pp, *p;
84 int i, len, hash;
85
86 /*
87 * Constructs a very basic chaining hashtable. The hash routine
88 * is simply the integral value of the first character.
89 * Subsequent entries are chained in the order they're processed
90 * (they're in-line re-ordered during lookup).
91 */
92
93 if (NULL == (tab = malloc(sizeof(struct asciitab))))
94 err(1, "malloc");
95
96 len = sizeof(lines) / sizeof(struct line);
97
98 if (NULL == (p = calloc((size_t)len, sizeof(struct linep))))
99 err(1, "malloc");
100
101 htab = calloc(ASCII_PRINT_HI - ASCII_PRINT_LO + 1,
102 sizeof(struct linep **));
103
104 if (NULL == htab)
105 err(1, "malloc");
106
107 for (i = 0; i < len; i++) {
108 assert(lines[i].codesz > 0);
109 assert(lines[i].code);
110 assert(lines[i].out);
111
112 p[i].line = &lines[i];
113
114 hash = (int)lines[i].code[0] - ASCII_PRINT_LO;
115
116 if (NULL == (pp = ((struct linep **)htab)[hash])) {
117 htab[hash] = &p[i];
118 continue;
119 }
120
121 for ( ; pp->next; pp = pp->next)
122 /* Scan ahead. */ ;
123
124 pp->next = &p[i];
125 }
126
127 tab->htab = htab;
128 tab->lines = p;
129
130 return(tab);
131 }
132
133
134 const char *
135 term_a2ascii(void *arg, const char *p, size_t sz, size_t *rsz)
136 {
137
138 return(lookup((struct asciitab *)arg, p,
139 sz, rsz, ASCII_CHAR));
140 }
141
142
143 const char *
144 term_a2res(void *arg, const char *p, size_t sz, size_t *rsz)
145 {
146
147 return(lookup((struct asciitab *)arg, p,
148 sz, rsz, ASCII_STRING));
149 }
150
151
152 static const char *
153 lookup(struct asciitab *tab, const char *p,
154 size_t sz, size_t *rsz, int type)
155 {
156 struct linep *pp, *prev;
157 void **htab;
158 int hash;
159
160 assert(p);
161 assert(sz > 0);
162
163 if (p[0] < ASCII_PRINT_LO || p[0] > ASCII_PRINT_HI)
164 return(NULL);
165
166
167 /*
168 * Lookup the symbol in the symbol hash. See ascii2htab for the
169 * hashtable specs. This dynamically re-orders the hash chain
170 * to optimise for repeat hits.
171 */
172
173 hash = (int)p[0] - ASCII_PRINT_LO;
174 htab = tab->htab;
175
176 if (NULL == (pp = ((struct linep **)htab)[hash]))
177 return(NULL);
178
179 if (NULL == pp->next) {
180 if ( ! match(pp->line, p, sz, type))
181 return(NULL);
182 *rsz = pp->line->outsz;
183 return(pp->line->out);
184 }
185
186 for (prev = NULL; pp; pp = pp->next) {
187 if ( ! match(pp->line, p, sz, type)) {
188 prev = pp;
189 continue;
190 }
191
192 /* Re-order the hash chain. */
193
194 if (prev) {
195 prev->next = pp->next;
196 pp->next = ((struct linep **)htab)[hash];
197 htab[hash] = pp;
198 }
199
200 *rsz = pp->line->outsz;
201 return(pp->line->out);
202 }
203
204 return(NULL);
205 }
206
207
208 static inline int
209 match(const struct line *line, const char *p, size_t sz, int type)
210 {
211
212 if ( ! (line->type & type))
213 return(0);
214 if (line->codesz != sz)
215 return(0);
216 return(0 == strncmp(line->code, p, sz));
217 }