1#ifndef lint
2static char *rcsid = "$Id: filechecker.c,v 1.1 2003/06/04 00:25:52 marka Exp $";
3#endif
4
5/*
6 * Copyright (c) 2001,2002 Japan Network Information Center.
7 * All rights reserved.
8 *
9 * By using this file, you agree to the terms and conditions set forth bellow.
10 *
11 * 			LICENSE TERMS AND CONDITIONS
12 *
13 * The following License Terms and Conditions apply, unless a different
14 * license is obtained from Japan Network Information Center ("JPNIC"),
15 * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
16 * Chiyoda-ku, Tokyo 101-0047, Japan.
17 *
18 * 1. Use, Modification and Redistribution (including distribution of any
19 *    modified or derived work) in source and/or binary forms is permitted
20 *    under this License Terms and Conditions.
21 *
22 * 2. Redistribution of source code must retain the copyright notices as they
23 *    appear in each source code file, this License Terms and Conditions.
24 *
25 * 3. Redistribution in binary form must reproduce the Copyright Notice,
26 *    this License Terms and Conditions, in the documentation and/or other
27 *    materials provided with the distribution.  For the purposes of binary
28 *    distribution the "Copyright Notice" refers to the following language:
29 *    "Copyright (c) 2000-2002 Japan Network Information Center.  All rights reserved."
30 *
31 * 4. The name of JPNIC may not be used to endorse or promote products
32 *    derived from this Software without specific prior written approval of
33 *    JPNIC.
34 *
35 * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
36 *    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 *    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
38 *    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL JPNIC BE LIABLE
39 *    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40 *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41 *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42 *    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
43 *    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
44 *    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
45 *    ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
46 */
47
48#include <config.h>
49
50#include <stdlib.h>
51#include <stdio.h>
52#include <string.h>
53#include <ctype.h>
54
55#include <idn/result.h>
56#include <idn/assert.h>
57#include <idn/log.h>
58#include <idn/logmacro.h>
59#include <idn/ucsset.h>
60#include <idn/filechecker.h>
61#include <idn/debug.h>
62
63#define SUPPORT_VERSIONING
64
65struct idn__filechecker {
66	idn_ucsset_t set;
67};
68
69static idn_result_t	read_file(const char *file, FILE *fp,
70				  idn_ucsset_t set);
71static int		get_range(char *s, unsigned long *ucs1,
72				  unsigned long *ucs2);
73static char		*get_ucs(char *p, unsigned long *vp);
74
75
76idn_result_t
77idn__filechecker_create(const char *file, idn__filechecker_t *ctxp) {
78	FILE *fp;
79	idn__filechecker_t ctx;
80	idn_result_t r;
81
82	assert(file != NULL && ctxp != NULL);
83
84	TRACE(("idn__filechecker_create(file=\"%-.100s\")\n", file));
85
86	if ((fp = fopen(file, "r")) == NULL) {
87		WARNING(("idn__filechecker_create: cannot open %-.100s\n",
88			 file));
89		return (idn_nofile);
90	}
91
92	if ((ctx = malloc(sizeof(struct idn__filechecker))) == NULL)
93		return (idn_nomemory);
94
95	if ((r = idn_ucsset_create(&ctx->set)) != idn_success) {
96		free(ctx);
97		return (r);
98	}
99
100	r = read_file(file, fp, ctx->set);
101	fclose(fp);
102
103	if (r == idn_success) {
104		idn_ucsset_fix(ctx->set);
105		*ctxp = ctx;
106	} else {
107		idn_ucsset_destroy(ctx->set);
108		free(ctx);
109	}
110	return (r);
111}
112
113void
114idn__filechecker_destroy(idn__filechecker_t ctx) {
115	assert(ctx != NULL);
116
117	TRACE(("idn__filechecker_destroy()\n"));
118
119	idn_ucsset_destroy(ctx->set);
120	free(ctx);
121}
122
123idn_result_t
124idn__filechecker_lookup(idn__filechecker_t ctx, const unsigned long *str,
125			const unsigned long **found) {
126	idn_result_t r = idn_success;
127
128	assert(ctx != NULL && str != NULL);
129
130	TRACE(("idn__filechecker_lookup(str=\"%s\")\n",
131	       idn__debug_ucs4xstring(str, 50)));
132
133	while (*str != '\0') {
134		int exists;
135
136		r = idn_ucsset_lookup(ctx->set, *str, &exists);
137
138		if (r != idn_success) {
139			return (r);
140		} else if (exists) {
141			/* Found. */
142			*found = str;
143			return (idn_success);
144		}
145		str++;
146	}
147	*found = NULL;
148	return (idn_success);
149}
150
151static idn_result_t
152read_file(const char *file, FILE *fp, idn_ucsset_t set) {
153	char line[256];
154	idn_result_t r;
155	int lineno = 0;
156
157	while (fgets(line, sizeof(line), fp) != NULL) {
158		char *p = line;
159		unsigned long ucs1, ucs2;
160
161		lineno++;
162		while (isspace((unsigned char)*p))
163			p++;
164		if (*p == '\0' || *p == '#')
165			continue;
166
167#ifdef SUPPORT_VERSIONING
168		/* Skip version tag. */
169		if (lineno == 1 && strncmp("version=", line, 8) == 0)
170			continue;
171#endif
172		if (!get_range(p, &ucs1, &ucs2)) {
173			WARNING(("syntax error in file \"%-.100s\" line %d: "
174				 "%-.100s", file, lineno, line));
175			return (idn_invalid_syntax);
176		}
177		if ((r = idn_ucsset_addrange(set, ucs1, ucs2)) != idn_success)
178			return (r);
179	}
180	return (idn_success);
181}
182
183static int
184get_range(char *s, unsigned long *ucs1, unsigned long *ucs2) {
185	if ((s = get_ucs(s, ucs1)) == NULL)
186		return (0);
187	*ucs2 = *ucs1;
188
189	switch (s[0]) {
190	case '\0':
191	case '\n':
192	case '#':
193	case ';':
194		return (1);
195	case '-':
196		break;
197	default:
198		return (0);
199	}
200
201	if ((s = get_ucs(s + 1, ucs2)) == NULL)
202		return (0);
203
204	if (*ucs1 > *ucs2) {
205		INFO(("idn__filechecker_create: invalid range spec "
206		      "U+%X-U+%X\n", *ucs1, *ucs2));
207		return (0);
208	}
209
210	switch (s[0]) {
211	case '\0':
212	case '\n':
213	case '#':
214	case ';':
215		return (1);
216	default:
217		return (0);
218	}
219}
220
221
222static char *
223get_ucs(char *p, unsigned long *vp) {
224	char *end;
225
226	/* Skip leading space */
227	while (isspace((unsigned char)*p))
228		p++;
229
230	/* Skip optional 'U+' */
231	if (strncmp(p, "U+", 2) == 0)
232		p += 2;
233
234	*vp = strtoul(p, &end, 16);
235	if (end == p) {
236		INFO(("idn__filechecker_create: UCS code point expected\n"));
237		return (NULL);
238	}
239	p = end;
240
241	/* Skip trailing space */
242	while (isspace((unsigned char)*p))
243		p++;
244	return p;
245}
246
247idn_result_t
248idn__filechecker_createproc(const char *parameter, void **ctxp) {
249	return idn__filechecker_create(parameter, (idn__filechecker_t *)ctxp);
250}
251
252void
253idn__filechecker_destroyproc(void *ctxp) {
254	idn__filechecker_destroy((idn__filechecker_t)ctxp);
255}
256
257idn_result_t
258idn__filechecker_lookupproc(void *ctx, const unsigned long *str,
259			    const unsigned long **found) {
260	return idn__filechecker_lookup((idn__filechecker_t)ctx, str, found);
261}
262