Annotation of mandoc/ascii.c, Revision 1.3
1.3 ! kristaps 1: /* $Id: ascii.c,v 1.2 2009/03/17 13:35:46 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: assert(0 == sizeof(lines) % sizeof(struct line));
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:
1.2 kristaps 127: tab->htab = htab;
128: tab->lines = p;
129:
130: return(tab);
1.1 kristaps 131: }
132:
133:
134: const char *
1.3 ! kristaps 135: term_a2ascii(void *arg, const char *p, size_t sz, size_t *rsz)
1.1 kristaps 136: {
1.2 kristaps 137: struct asciitab *tab;
1.1 kristaps 138: struct linep *pp, *prev;
139: void **htab;
140: int hash;
141:
1.2 kristaps 142: tab = (struct asciitab *)arg;
143: htab = tab->htab;
1.1 kristaps 144:
145: assert(p);
146: assert(sz > 0);
147: assert(p[0] >= ASCII_PRINT_LO && p[0] <= ASCII_PRINT_HI);
148:
149: /*
150: * Lookup the symbol in the symbol hash. See ascii2htab for the
151: * hashtable specs. This dynamically re-orders the hash chain
152: * to optimise for repeat hits.
153: */
154:
155: hash = (int)p[0] - ASCII_PRINT_LO;
156:
157: if (NULL == (pp = ((struct linep **)htab)[hash]))
158: return(NULL);
159:
160: if (NULL == pp->next) {
161: if ( ! match(pp->line, p, sz))
162: return(NULL);
163: *rsz = pp->line->outsz;
164: return(pp->line->out);
165: }
166:
167: for (prev = NULL; pp; pp = pp->next) {
168: if ( ! match(pp->line, p, sz)) {
169: prev = pp;
170: continue;
171: }
172:
173: /* Re-order the hash chain. */
174:
175: if (prev) {
176: prev->next = pp->next;
177: pp->next = ((struct linep **)htab)[hash];
178: htab[hash] = pp;
179: }
180:
181: *rsz = pp->line->outsz;
182: return(pp->line->out);
183: }
184:
185: return(NULL);
186: }
187:
188:
189: static inline int
190: match(const struct line *line, const char *p, size_t sz)
191: {
192:
193: if (line->codesz != sz)
194: return(0);
195: return(0 == strncmp(line->code, p, sz));
196: }
CVSweb