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