Annotation of mandoc/ascii.c, Revision 1.9
1.9 ! kristaps 1: /* $Id: ascii.c,v 1.8 2009/06/10 20:18:43 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;
30: size_t codesz;
31: size_t outsz;
1.9 ! kristaps 32: int type;
! 33: #define ASCII_CHAR (1 << 0)
! 34: #define ASCII_STRING (1 << 1)
! 35: #define ASCII_BOTH (0x03)
1.1 kristaps 36: };
37:
38: struct linep {
39: const struct line *line;
1.2 kristaps 40: struct linep *next;
1.1 kristaps 41: };
42:
1.9 ! kristaps 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 },
1.1 kristaps 49: static const struct line lines[] = {
50: #include "ascii.in"
51: };
52:
1.2 kristaps 53: struct asciitab {
54: struct linep *lines;
55: void **htab;
56: };
57:
1.1 kristaps 58:
1.2 kristaps 59: static inline int match(const struct line *,
1.9 ! kristaps 60: const char *, size_t, int);
! 61: static const char * lookup(struct asciitab *, const char *,
! 62: size_t, size_t *, int);
1.1 kristaps 63:
64:
1.2 kristaps 65: void
1.3 kristaps 66: term_asciifree(void *arg)
1.2 kristaps 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:
1.1 kristaps 78: void *
1.3 kristaps 79: term_ascii2htab(void)
1.1 kristaps 80: {
1.2 kristaps 81: struct asciitab *tab;
1.1 kristaps 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:
1.2 kristaps 93: if (NULL == (tab = malloc(sizeof(struct asciitab))))
94: err(1, "malloc");
95:
1.1 kristaps 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.9 ! kristaps 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: {
1.1 kristaps 156: struct linep *pp, *prev;
157: void **htab;
158: int hash;
159:
160: assert(p);
161: assert(sz > 0);
1.6 kristaps 162:
163: if (p[0] < ASCII_PRINT_LO || p[0] > ASCII_PRINT_HI)
164: return(NULL);
165:
1.1 kristaps 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;
1.9 ! kristaps 174: htab = tab->htab;
1.1 kristaps 175:
176: if (NULL == (pp = ((struct linep **)htab)[hash]))
177: return(NULL);
178:
179: if (NULL == pp->next) {
1.9 ! kristaps 180: if ( ! match(pp->line, p, sz, type))
1.1 kristaps 181: return(NULL);
182: *rsz = pp->line->outsz;
183: return(pp->line->out);
184: }
185:
186: for (prev = NULL; pp; pp = pp->next) {
1.9 ! kristaps 187: if ( ! match(pp->line, p, sz, type)) {
1.1 kristaps 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
1.9 ! kristaps 209: match(const struct line *line, const char *p, size_t sz, int type)
1.1 kristaps 210: {
211:
1.9 ! kristaps 212: if ( ! (line->type & type))
! 213: return(0);
1.1 kristaps 214: if (line->codesz != sz)
215: return(0);
216: return(0 == strncmp(line->code, p, sz));
217: }
CVSweb