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