Annotation of src/usr.bin/mandoc/ascii.c, Revision 1.1
1.1 ! kristaps 1: /* $Id: ascii.c,v 1.5 2009/04/05 16:34:22 kristaps Exp $ */
! 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 {
! 30: const char *code;
! 31: const char *out;
! 32: /* 32- and 64-bit alignment safe. */
! 33: size_t codesz;
! 34: size_t outsz;
! 35: };
! 36:
! 37: struct linep {
! 38: const struct line *line;
! 39: struct linep *next;
! 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:
! 48: struct asciitab {
! 49: struct linep *lines;
! 50: void **htab;
! 51: };
! 52:
! 53:
! 54: static inline int match(const struct line *,
! 55: const char *, size_t);
! 56:
! 57:
! 58: void
! 59: term_asciifree(void *arg)
! 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:
! 71: void *
! 72: term_ascii2htab(void)
! 73: {
! 74: struct asciitab *tab;
! 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:
! 86: if (NULL == (tab = malloc(sizeof(struct asciitab))))
! 87: err(1, "malloc");
! 88:
! 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:
! 120: tab->htab = htab;
! 121: tab->lines = p;
! 122:
! 123: return(tab);
! 124: }
! 125:
! 126:
! 127: const char *
! 128: term_a2ascii(void *arg, const char *p, size_t sz, size_t *rsz)
! 129: {
! 130: struct asciitab *tab;
! 131: struct linep *pp, *prev;
! 132: void **htab;
! 133: int hash;
! 134:
! 135: tab = (struct asciitab *)arg;
! 136: htab = tab->htab;
! 137:
! 138: assert(p);
! 139: assert(sz > 0);
! 140:
! 141: if (p[0] < ASCII_PRINT_LO || p[0] > ASCII_PRINT_HI)
! 142: return(NULL);
! 143:
! 144: /*
! 145: * Lookup the symbol in the symbol hash. See ascii2htab for the
! 146: * hashtable specs. This dynamically re-orders the hash chain
! 147: * to optimise for repeat hits.
! 148: */
! 149:
! 150: hash = (int)p[0] - ASCII_PRINT_LO;
! 151:
! 152: if (NULL == (pp = ((struct linep **)htab)[hash]))
! 153: return(NULL);
! 154:
! 155: if (NULL == pp->next) {
! 156: if ( ! match(pp->line, p, sz))
! 157: return(NULL);
! 158: *rsz = pp->line->outsz;
! 159: return(pp->line->out);
! 160: }
! 161:
! 162: for (prev = NULL; pp; pp = pp->next) {
! 163: if ( ! match(pp->line, p, sz)) {
! 164: prev = pp;
! 165: continue;
! 166: }
! 167:
! 168: /* Re-order the hash chain. */
! 169:
! 170: if (prev) {
! 171: prev->next = pp->next;
! 172: pp->next = ((struct linep **)htab)[hash];
! 173: htab[hash] = pp;
! 174: }
! 175:
! 176: *rsz = pp->line->outsz;
! 177: return(pp->line->out);
! 178: }
! 179:
! 180: return(NULL);
! 181: }
! 182:
! 183:
! 184: static inline int
! 185: match(const struct line *line, const char *p, size_t sz)
! 186: {
! 187:
! 188: if (line->codesz != sz)
! 189: return(0);
! 190: return(0 == strncmp(line->code, p, sz));
! 191: }