1 /* $OpenBSD: chars.c,v 1.36 2015/02/17 20:33:44 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4 * Copyright (c) 2011, 2014 Ingo Schwarze <schwarze@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 #include <sys/types.h> 19 20 #include <assert.h> 21 #include <ctype.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include "mandoc.h" 26 #include "mandoc_aux.h" 27 #include "libmandoc.h" 28 29 #define PRINT_HI 126 30 #define PRINT_LO 32 31 32 struct ln { 33 struct ln *next; 34 const char *code; 35 const char *ascii; 36 int unicode; 37 }; 38 39 #define LINES_MAX 332 40 41 #define CHAR(in, ch, code) \ 42 { NULL, (in), (ch), (code) }, 43 44 #define CHAR_TBL_START static struct ln lines[LINES_MAX] = { 45 #define CHAR_TBL_END }; 46 47 #include "chars.in" 48 49 struct mchars { 50 struct ln **htab; 51 }; 52 53 static const struct ln *find(const struct mchars *, 54 const char *, size_t); 55 56 57 void 58 mchars_free(struct mchars *arg) 59 { 60 61 free(arg->htab); 62 free(arg); 63 } 64 65 struct mchars * 66 mchars_alloc(void) 67 { 68 struct mchars *tab; 69 struct ln **htab; 70 struct ln *pp; 71 int i, hash; 72 73 /* 74 * Constructs a very basic chaining hashtable. The hash routine 75 * is simply the integral value of the first character. 76 * Subsequent entries are chained in the order they're processed. 77 */ 78 79 tab = mandoc_malloc(sizeof(struct mchars)); 80 htab = mandoc_calloc(PRINT_HI - PRINT_LO + 1, sizeof(struct ln *)); 81 82 for (i = 0; i < LINES_MAX; i++) { 83 hash = (int)lines[i].code[0] - PRINT_LO; 84 85 if (NULL == (pp = htab[hash])) { 86 htab[hash] = &lines[i]; 87 continue; 88 } 89 90 for ( ; pp->next; pp = pp->next) 91 /* Scan ahead. */ ; 92 pp->next = &lines[i]; 93 } 94 95 tab->htab = htab; 96 return(tab); 97 } 98 99 int 100 mchars_spec2cp(const struct mchars *arg, const char *p, size_t sz) 101 { 102 const struct ln *ln; 103 104 ln = find(arg, p, sz); 105 return(ln != NULL ? ln->unicode : sz == 1 ? (unsigned char)*p : -1); 106 } 107 108 int 109 mchars_num2char(const char *p, size_t sz) 110 { 111 int i; 112 113 i = mandoc_strntoi(p, sz, 10); 114 return(i >= 0 && i < 256 ? i : -1); 115 } 116 117 int 118 mchars_num2uc(const char *p, size_t sz) 119 { 120 int i; 121 122 i = mandoc_strntoi(p, sz, 16); 123 assert(i >= 0 && i <= 0x10FFFF); 124 return(i); 125 } 126 127 const char * 128 mchars_spec2str(const struct mchars *arg, 129 const char *p, size_t sz, size_t *rsz) 130 { 131 const struct ln *ln; 132 133 ln = find(arg, p, sz); 134 if (ln == NULL) { 135 *rsz = 1; 136 return(sz == 1 ? p : NULL); 137 } 138 139 *rsz = strlen(ln->ascii); 140 return(ln->ascii); 141 } 142 143 const char * 144 mchars_uc2str(int uc) 145 { 146 int i; 147 148 for (i = 0; i < LINES_MAX; i++) 149 if (uc == lines[i].unicode) 150 return(lines[i].ascii); 151 return("<?>"); 152 } 153 154 static const struct ln * 155 find(const struct mchars *tab, const char *p, size_t sz) 156 { 157 const struct ln *pp; 158 int hash; 159 160 assert(p); 161 162 if (0 == sz || p[0] < PRINT_LO || p[0] > PRINT_HI) 163 return(NULL); 164 165 hash = (int)p[0] - PRINT_LO; 166 167 for (pp = tab->htab[hash]; pp; pp = pp->next) 168 if (0 == strncmp(pp->code, p, sz) && 169 '\0' == pp->code[(int)sz]) 170 return(pp); 171 172 return(NULL); 173 } 174