Annotation of mandoc/ascii.c, Revision 1.5
1.5 ! kristaps 1: /* $Id: ascii.c,v 1.4 2009/03/20 21:58:38 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: struct line {
1.2 kristaps 30: const char *code;
31: const char *out;
1.1 kristaps 32: /* 32- and 64-bit alignment safe. */
1.2 kristaps 33: size_t codesz;
34: size_t outsz;
1.1 kristaps 35: };
36:
37: struct linep {
38: const struct line *line;
1.2 kristaps 39: struct linep *next;
1.1 kristaps 40: };
41:
42: #define LINE(w, x, y, z) \
43: { (w), (y), (x), (z) },
44: static const struct line lines[] = {
45: #include "ascii.in"
46: };
47:
1.2 kristaps 48: struct asciitab {
49: struct linep *lines;
50: void **htab;
51: };
52:
1.1 kristaps 53:
1.2 kristaps 54: static inline int match(const struct line *,
1.1 kristaps 55: const char *, size_t);
56:
57:
1.2 kristaps 58: void
1.3 kristaps 59: term_asciifree(void *arg)
1.2 kristaps 60: {
61: struct asciitab *tab;
62:
63: tab = (struct asciitab *)arg;
64:
65: free(tab->lines);
66: free(tab->htab);
67: free(tab);
68: }
69:
70:
1.1 kristaps 71: void *
1.3 kristaps 72: term_ascii2htab(void)
1.1 kristaps 73: {
1.2 kristaps 74: struct asciitab *tab;
1.1 kristaps 75: void **htab;
76: struct linep *pp, *p;
77: int i, len, hash;
78:
79: /*
80: * Constructs a very basic chaining hashtable. The hash routine
81: * is simply the integral value of the first character.
82: * Subsequent entries are chained in the order they're processed
83: * (they're in-line re-ordered during lookup).
84: */
85:
1.2 kristaps 86: if (NULL == (tab = malloc(sizeof(struct asciitab))))
87: err(1, "malloc");
88:
1.1 kristaps 89: len = sizeof(lines) / sizeof(struct line);
90:
91: if (NULL == (p = calloc((size_t)len, sizeof(struct linep))))
92: err(1, "malloc");
93:
94: htab = calloc(ASCII_PRINT_HI - ASCII_PRINT_LO + 1,
95: sizeof(struct linep **));
96:
97: if (NULL == htab)
98: err(1, "malloc");
99:
100: for (i = 0; i < len; i++) {
101: assert(lines[i].codesz > 0);
102: assert(lines[i].code);
103: assert(lines[i].out);
104:
105: p[i].line = &lines[i];
106:
107: hash = (int)lines[i].code[0] - ASCII_PRINT_LO;
108:
109: if (NULL == (pp = ((struct linep **)htab)[hash])) {
110: htab[hash] = &p[i];
111: continue;
112: }
113:
114: for ( ; pp->next; pp = pp->next)
115: /* Scan ahead. */ ;
116:
117: pp->next = &p[i];
118: }
119:
1.2 kristaps 120: tab->htab = htab;
121: tab->lines = p;
122:
123: return(tab);
1.1 kristaps 124: }
125:
126:
127: const char *
1.3 kristaps 128: term_a2ascii(void *arg, const char *p, size_t sz, size_t *rsz)
1.1 kristaps 129: {
1.2 kristaps 130: struct asciitab *tab;
1.1 kristaps 131: struct linep *pp, *prev;
132: void **htab;
133: int hash;
134:
1.2 kristaps 135: tab = (struct asciitab *)arg;
136: htab = tab->htab;
1.1 kristaps 137:
138: assert(p);
139: assert(sz > 0);
140: assert(p[0] >= ASCII_PRINT_LO && p[0] <= ASCII_PRINT_HI);
141:
142: /*
143: * Lookup the symbol in the symbol hash. See ascii2htab for the
144: * hashtable specs. This dynamically re-orders the hash chain
145: * to optimise for repeat hits.
146: */
147:
148: hash = (int)p[0] - ASCII_PRINT_LO;
149:
150: if (NULL == (pp = ((struct linep **)htab)[hash]))
151: return(NULL);
152:
153: if (NULL == pp->next) {
154: if ( ! match(pp->line, p, sz))
155: return(NULL);
156: *rsz = pp->line->outsz;
157: return(pp->line->out);
158: }
159:
160: for (prev = NULL; pp; pp = pp->next) {
161: if ( ! match(pp->line, p, sz)) {
162: prev = pp;
163: continue;
164: }
165:
166: /* Re-order the hash chain. */
167:
168: if (prev) {
169: prev->next = pp->next;
170: pp->next = ((struct linep **)htab)[hash];
171: htab[hash] = pp;
172: }
173:
174: *rsz = pp->line->outsz;
175: return(pp->line->out);
176: }
177:
178: return(NULL);
179: }
180:
181:
182: static inline int
183: match(const struct line *line, const char *p, size_t sz)
184: {
185:
186: if (line->codesz != sz)
187: return(0);
188: return(0 == strncmp(line->code, p, sz));
189: }
CVSweb