1/*	$Id: chars.c,v 1.52 2011/11/08 00:15:23 kristaps 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(const struct mchars *,
55				const char *, size_t);
56
57void
58mchars_free(struct mchars *arg)
59{
60
61	free(arg->htab);
62	free(arg);
63}
64
65struct mchars *
66mchars_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
99int
100mchars_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	if (NULL == ln)
106		return(-1);
107	return(ln->unicode);
108}
109
110char
111mchars_num2char(const char *p, size_t sz)
112{
113	int		  i;
114
115	if ((i = mandoc_strntoi(p, sz, 10)) < 0)
116		return('\0');
117	return(i > 0 && i < 256 && isprint(i) ?
118			/* LINTED */ i : '\0');
119}
120
121int
122mchars_num2uc(const char *p, size_t sz)
123{
124	int               i;
125
126	if ((i = mandoc_strntoi(p, sz, 16)) < 0)
127		return('\0');
128	/* FIXME: make sure we're not in a bogus range. */
129	return(i > 0x80 && i <= 0x10FFFF ? i : '\0');
130}
131
132const char *
133mchars_spec2str(const struct mchars *arg,
134		const char *p, size_t sz, size_t *rsz)
135{
136	const struct ln	*ln;
137
138	ln = find(arg, p, sz);
139	if (NULL == ln) {
140		*rsz = 1;
141		return(NULL);
142	}
143
144	*rsz = strlen(ln->ascii);
145	return(ln->ascii);
146}
147
148static const struct ln *
149find(const struct mchars *tab, const char *p, size_t sz)
150{
151	const struct ln	 *pp;
152	int		  hash;
153
154	assert(p);
155
156	if (0 == sz || p[0] < PRINT_LO || p[0] > PRINT_HI)
157		return(NULL);
158
159	hash = (int)p[0] - PRINT_LO;
160
161	for (pp = tab->htab[hash]; pp; pp = pp->next)
162		if (0 == strncmp(pp->code, p, sz) &&
163				'\0' == pp->code[(int)sz])
164			return(pp);
165
166	return(NULL);
167}
168