chars.c revision 275432
1/*	$Id: chars.c,v 1.65 2014/10/29 00:17:43 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 "config.h"
19
20#include <sys/types.h>
21
22#include <assert.h>
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include "mandoc.h"
28#include "mandoc_aux.h"
29#include "libmandoc.h"
30
31#define	PRINT_HI	 126
32#define	PRINT_LO	 32
33
34struct	ln {
35	struct ln	 *next;
36	const char	 *code;
37	const char	 *ascii;
38	int		  unicode;
39};
40
41#define	LINES_MAX	  330
42
43#define CHAR(in, ch, code) \
44	{ NULL, (in), (ch), (code) },
45
46#define	CHAR_TBL_START	  static struct ln lines[LINES_MAX] = {
47#define	CHAR_TBL_END	  };
48
49#include "chars.in"
50
51struct	mchars {
52	struct ln	**htab;
53};
54
55static	const struct ln	 *find(const struct mchars *,
56				const char *, size_t);
57
58
59void
60mchars_free(struct mchars *arg)
61{
62
63	free(arg->htab);
64	free(arg);
65}
66
67struct mchars *
68mchars_alloc(void)
69{
70	struct mchars	 *tab;
71	struct ln	**htab;
72	struct ln	 *pp;
73	int		  i, hash;
74
75	/*
76	 * Constructs a very basic chaining hashtable.  The hash routine
77	 * is simply the integral value of the first character.
78	 * Subsequent entries are chained in the order they're processed.
79	 */
80
81	tab = mandoc_malloc(sizeof(struct mchars));
82	htab = mandoc_calloc(PRINT_HI - PRINT_LO + 1, sizeof(struct ln *));
83
84	for (i = 0; i < LINES_MAX; i++) {
85		hash = (int)lines[i].code[0] - PRINT_LO;
86
87		if (NULL == (pp = htab[hash])) {
88			htab[hash] = &lines[i];
89			continue;
90		}
91
92		for ( ; pp->next; pp = pp->next)
93			/* Scan ahead. */ ;
94		pp->next = &lines[i];
95	}
96
97	tab->htab = htab;
98	return(tab);
99}
100
101int
102mchars_spec2cp(const struct mchars *arg, const char *p, size_t sz)
103{
104	const struct ln	*ln;
105
106	ln = find(arg, p, sz);
107	return(ln != NULL ? ln->unicode : sz == 1 ? (unsigned char)*p : -1);
108}
109
110int
111mchars_num2char(const char *p, size_t sz)
112{
113	int	  i;
114
115	i = mandoc_strntoi(p, sz, 10);
116	return(i >= 0 && i < 256 ? i : -1);
117}
118
119int
120mchars_num2uc(const char *p, size_t sz)
121{
122	int	 i;
123
124	i = mandoc_strntoi(p, sz, 16);
125	assert(i >= 0 && i <= 0x10FFFF);
126	return(i);
127}
128
129const char *
130mchars_spec2str(const struct mchars *arg,
131		const char *p, size_t sz, size_t *rsz)
132{
133	const struct ln	*ln;
134
135	ln = find(arg, p, sz);
136	if (ln == NULL) {
137		*rsz = 1;
138		return(sz == 1 ? p : NULL);
139	}
140
141	*rsz = strlen(ln->ascii);
142	return(ln->ascii);
143}
144
145const char *
146mchars_uc2str(int uc)
147{
148	int	 i;
149
150	for (i = 0; i < LINES_MAX; i++)
151		if (uc == lines[i].unicode)
152			return(lines[i].ascii);
153	return("<?>");
154}
155
156static const struct ln *
157find(const struct mchars *tab, const char *p, size_t sz)
158{
159	const struct ln	 *pp;
160	int		  hash;
161
162	assert(p);
163
164	if (0 == sz || p[0] < PRINT_LO || p[0] > PRINT_HI)
165		return(NULL);
166
167	hash = (int)p[0] - PRINT_LO;
168
169	for (pp = tab->htab[hash]; pp; pp = pp->next)
170		if (0 == strncmp(pp->code, p, sz) &&
171		    '\0' == pp->code[(int)sz])
172			return(pp);
173
174	return(NULL);
175}
176