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