chars.c revision 1.1.1.8
1/* $Vendor-Id: chars.c,v 1.20 2010/06/19 20:46:27 kristaps Exp $ */ 2/* 3 * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> 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 above 7 * copyright notice and this permission notice appear in all copies. 8 * 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. 16 */ 17#ifdef HAVE_CONFIG_H 18#include "config.h" 19#endif 20 21#include <assert.h> 22#include <stdio.h> 23#include <stdlib.h> 24#include <string.h> 25 26#include "mandoc.h" 27#include "chars.h" 28 29#define PRINT_HI 126 30#define PRINT_LO 32 31 32struct ln { 33 struct ln *next; 34 const char *code; 35 const char *ascii; 36 const char *html; 37 size_t codesz; 38 size_t asciisz; 39 size_t htmlsz; 40 int type; 41#define CHARS_CHAR (1 << 0) 42#define CHARS_STRING (1 << 1) 43#define CHARS_BOTH (CHARS_CHAR | CHARS_STRING) 44}; 45 46#define LINES_MAX 370 47 48#define CHAR(w, x, y, z, a, b) \ 49 { NULL, (w), (y), (a), (x), (z), (b), CHARS_CHAR }, 50#define STRING(w, x, y, z, a, b) \ 51 { NULL, (w), (y), (a), (x), (z), (b), CHARS_STRING }, 52#define BOTH(w, x, y, z, a, b) \ 53 { NULL, (w), (y), (a), (x), (z), (b), CHARS_BOTH }, 54 55#define CHAR_TBL_START static struct ln lines[LINES_MAX] = { 56#define CHAR_TBL_END }; 57 58#include "chars.in" 59 60struct tbl { 61 enum chars type; 62 struct ln **htab; 63}; 64 65static inline int match(const struct ln *, 66 const char *, size_t, int); 67static const char *find(struct tbl *, const char *, 68 size_t, size_t *, int); 69 70 71void 72chars_free(void *arg) 73{ 74 struct tbl *tab; 75 76 tab = (struct tbl *)arg; 77 78 free(tab->htab); 79 free(tab); 80} 81 82 83void * 84chars_init(enum chars type) 85{ 86 struct tbl *tab; 87 struct ln **htab; 88 struct ln *pp; 89 int i, hash; 90 91 /* 92 * Constructs a very basic chaining hashtable. The hash routine 93 * is simply the integral value of the first character. 94 * Subsequent entries are chained in the order they're processed 95 * (they're in-line re-ordered during lookup). 96 */ 97 98 tab = malloc(sizeof(struct tbl)); 99 if (NULL == tab) { 100 perror(NULL); 101 exit(EXIT_FAILURE); 102 } 103 104 htab = calloc(PRINT_HI - PRINT_LO + 1, sizeof(struct ln **)); 105 if (NULL == htab) { 106 perror(NULL); 107 exit(EXIT_FAILURE); 108 } 109 110 for (i = 0; i < LINES_MAX; i++) { 111 hash = (int)lines[i].code[0] - PRINT_LO; 112 113 if (NULL == (pp = htab[hash])) { 114 htab[hash] = &lines[i]; 115 continue; 116 } 117 118 for ( ; pp->next; pp = pp->next) 119 /* Scan ahead. */ ; 120 pp->next = &lines[i]; 121 } 122 123 tab->htab = htab; 124 tab->type = type; 125 return(tab); 126} 127 128 129const char * 130chars_a2ascii(void *arg, const char *p, size_t sz, size_t *rsz) 131{ 132 133 return(find((struct tbl *)arg, p, sz, rsz, CHARS_CHAR)); 134} 135 136 137const char * 138chars_a2res(void *arg, const char *p, size_t sz, size_t *rsz) 139{ 140 141 return(find((struct tbl *)arg, p, sz, rsz, CHARS_STRING)); 142} 143 144 145static const char * 146find(struct tbl *tab, const char *p, size_t sz, size_t *rsz, int type) 147{ 148 struct ln *pp, *prev; 149 struct ln **htab; 150 int hash; 151 152 assert(p); 153 assert(sz > 0); 154 155 if (p[0] < PRINT_LO || p[0] > PRINT_HI) 156 return(NULL); 157 158 /* 159 * Lookup the symbol in the symbol hash. See ascii2htab for the 160 * hashtable specs. This dynamically re-orders the hash chain 161 * to optimise for repeat hits. 162 */ 163 164 hash = (int)p[0] - PRINT_LO; 165 htab = tab->htab; 166 167 if (NULL == (pp = htab[hash])) 168 return(NULL); 169 170 for (prev = NULL; pp; pp = pp->next) { 171 if ( ! match(pp, p, sz, type)) { 172 prev = pp; 173 continue; 174 } 175 176 if (prev) { 177 prev->next = pp->next; 178 pp->next = htab[hash]; 179 htab[hash] = pp; 180 } 181 182 if (CHARS_HTML == tab->type) { 183 *rsz = pp->htmlsz; 184 return(pp->html); 185 } 186 *rsz = pp->asciisz; 187 return(pp->ascii); 188 } 189 190 return(NULL); 191} 192 193 194static inline int 195match(const struct ln *ln, const char *p, size_t sz, int type) 196{ 197 198 if ( ! (ln->type & type)) 199 return(0); 200 if (ln->codesz != sz) 201 return(0); 202 return(0 == strncmp(ln->code, p, sz)); 203} 204