xref: /minix3/usr.bin/tic/tic.c (revision 51e66a47d88f32e577d34ec883630a1acb2fb223)
1*51e66a47SVivek Prakash /* $NetBSD: tic.c,v 1.10 2010/02/22 23:05:39 roy Exp $ */
2*51e66a47SVivek Prakash 
3*51e66a47SVivek Prakash /*
4*51e66a47SVivek Prakash  * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc.
5*51e66a47SVivek Prakash  *
6*51e66a47SVivek Prakash  * This code is derived from software contributed to The NetBSD Foundation
7*51e66a47SVivek Prakash  * by Roy Marples.
8*51e66a47SVivek Prakash  *
9*51e66a47SVivek Prakash  * Redistribution and use in source and binary forms, with or without
10*51e66a47SVivek Prakash  * modification, are permitted provided that the following conditions
11*51e66a47SVivek Prakash  * are met:
12*51e66a47SVivek Prakash  * 1. Redistributions of source code must retain the above copyright
13*51e66a47SVivek Prakash  *    notice, this list of conditions and the following disclaimer.
14*51e66a47SVivek Prakash  * 2. Redistributions in binary form must reproduce the above copyright
15*51e66a47SVivek Prakash  *    notice, this list of conditions and the following disclaimer in the
16*51e66a47SVivek Prakash  *    documentation and/or other materials provided with the distribution.
17*51e66a47SVivek Prakash  *
18*51e66a47SVivek Prakash  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19*51e66a47SVivek Prakash  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20*51e66a47SVivek Prakash  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21*51e66a47SVivek Prakash  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22*51e66a47SVivek Prakash  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23*51e66a47SVivek Prakash  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*51e66a47SVivek Prakash  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*51e66a47SVivek Prakash  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*51e66a47SVivek Prakash  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27*51e66a47SVivek Prakash  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*51e66a47SVivek Prakash  */
29*51e66a47SVivek Prakash 
30*51e66a47SVivek Prakash #if HAVE_NBTOOL_CONFIG_H
31*51e66a47SVivek Prakash #include "nbtool_config.h"
32*51e66a47SVivek Prakash #endif
33*51e66a47SVivek Prakash 
34*51e66a47SVivek Prakash #include <sys/cdefs.h>
35*51e66a47SVivek Prakash __RCSID("$NetBSD: tic.c,v 1.10 2010/02/22 23:05:39 roy Exp $");
36*51e66a47SVivek Prakash 
37*51e66a47SVivek Prakash #include <sys/types.h>
38*51e66a47SVivek Prakash 
39*51e66a47SVivek Prakash #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
40*51e66a47SVivek Prakash #include <sys/endian.h>
41*51e66a47SVivek Prakash #endif
42*51e66a47SVivek Prakash 
43*51e66a47SVivek Prakash #include <ctype.h>
44*51e66a47SVivek Prakash #include <err.h>
45*51e66a47SVivek Prakash #include <errno.h>
46*51e66a47SVivek Prakash #include <getopt.h>
47*51e66a47SVivek Prakash #include <limits.h>
48*51e66a47SVivek Prakash #include <fcntl.h>
49*51e66a47SVivek Prakash #include <ndbm.h>
50*51e66a47SVivek Prakash #include <stdarg.h>
51*51e66a47SVivek Prakash #include <stdlib.h>
52*51e66a47SVivek Prakash #include <stdio.h>
53*51e66a47SVivek Prakash #include <string.h>
54*51e66a47SVivek Prakash #include <term_private.h>
55*51e66a47SVivek Prakash #include <term.h>
56*51e66a47SVivek Prakash 
57*51e66a47SVivek Prakash /* We store the full list of terminals we have instead of iterating
58*51e66a47SVivek Prakash    through the database as the sequential iterator doesn't work
59*51e66a47SVivek Prakash    the the data size stored changes N amount which ours will. */
60*51e66a47SVivek Prakash typedef struct term {
61*51e66a47SVivek Prakash 	struct term *next;
62*51e66a47SVivek Prakash 	char *name;
63*51e66a47SVivek Prakash 	char type;
64*51e66a47SVivek Prakash 	TIC *tic;
65*51e66a47SVivek Prakash } TERM;
66*51e66a47SVivek Prakash static TERM *terms;
67*51e66a47SVivek Prakash 
68*51e66a47SVivek Prakash static int error_exit;
69*51e66a47SVivek Prakash static int Sflag;
70*51e66a47SVivek Prakash static char *dbname;
71*51e66a47SVivek Prakash 
72*51e66a47SVivek Prakash static void
73*51e66a47SVivek Prakash do_unlink(void)
74*51e66a47SVivek Prakash {
75*51e66a47SVivek Prakash 
76*51e66a47SVivek Prakash 	if (dbname != NULL)
77*51e66a47SVivek Prakash 		unlink(dbname);
78*51e66a47SVivek Prakash }
79*51e66a47SVivek Prakash 
80*51e66a47SVivek Prakash static void __attribute__((__format__(__printf__, 1, 2)))
81*51e66a47SVivek Prakash dowarn(const char *fmt, ...)
82*51e66a47SVivek Prakash {
83*51e66a47SVivek Prakash 	va_list va;
84*51e66a47SVivek Prakash 
85*51e66a47SVivek Prakash 	error_exit = 1;
86*51e66a47SVivek Prakash 	va_start(va, fmt);
87*51e66a47SVivek Prakash 	vwarnx(fmt, va);
88*51e66a47SVivek Prakash 	va_end(va);
89*51e66a47SVivek Prakash }
90*51e66a47SVivek Prakash 
91*51e66a47SVivek Prakash static char *
92*51e66a47SVivek Prakash grow_tbuf(TBUF *tbuf, size_t len)
93*51e66a47SVivek Prakash {
94*51e66a47SVivek Prakash 	char *buf;
95*51e66a47SVivek Prakash 
96*51e66a47SVivek Prakash 	buf = _ti_grow_tbuf(tbuf, len);
97*51e66a47SVivek Prakash 	if (buf == NULL)
98*51e66a47SVivek Prakash 		err(1, "_ti_grow_tbuf");
99*51e66a47SVivek Prakash 	return buf;
100*51e66a47SVivek Prakash }
101*51e66a47SVivek Prakash 
102*51e66a47SVivek Prakash static int
103*51e66a47SVivek Prakash save_term(DBM *db, TERM *term)
104*51e66a47SVivek Prakash {
105*51e66a47SVivek Prakash 	uint8_t *buf;
106*51e66a47SVivek Prakash 	ssize_t len;
107*51e66a47SVivek Prakash 	datum key, value;
108*51e66a47SVivek Prakash 
109*51e66a47SVivek Prakash 	len = _ti_flatten(&buf, term->tic);
110*51e66a47SVivek Prakash 	if (len == -1)
111*51e66a47SVivek Prakash 		return -1;
112*51e66a47SVivek Prakash 
113*51e66a47SVivek Prakash 	key.dptr = term->name;
114*51e66a47SVivek Prakash 	key.dsize = strlen(term->name);
115*51e66a47SVivek Prakash 	value.dptr = buf;
116*51e66a47SVivek Prakash 	value.dsize = len;
117*51e66a47SVivek Prakash 	if (dbm_store(db, key, value, DBM_REPLACE) == -1)
118*51e66a47SVivek Prakash 		err(1, "dbm_store");
119*51e66a47SVivek Prakash 	free(buf);
120*51e66a47SVivek Prakash 	return 0;
121*51e66a47SVivek Prakash }
122*51e66a47SVivek Prakash 
123*51e66a47SVivek Prakash static TERM *
124*51e66a47SVivek Prakash find_term(const char *name)
125*51e66a47SVivek Prakash {
126*51e66a47SVivek Prakash 	TERM *term;
127*51e66a47SVivek Prakash 
128*51e66a47SVivek Prakash 	for (term = terms; term != NULL; term = term->next)
129*51e66a47SVivek Prakash 		if (strcmp(term->name, name) == 0)
130*51e66a47SVivek Prakash 			return term;
131*51e66a47SVivek Prakash 	return NULL;
132*51e66a47SVivek Prakash }
133*51e66a47SVivek Prakash 
134*51e66a47SVivek Prakash static TERM *
135*51e66a47SVivek Prakash store_term(const char *name, char type)
136*51e66a47SVivek Prakash {
137*51e66a47SVivek Prakash 	TERM *term;
138*51e66a47SVivek Prakash 
139*51e66a47SVivek Prakash 	term = calloc(1, sizeof(*term));
140*51e66a47SVivek Prakash 	if (term == NULL)
141*51e66a47SVivek Prakash 		errx(1, "malloc");
142*51e66a47SVivek Prakash 	term->name = strdup(name);
143*51e66a47SVivek Prakash 	term->type = type;
144*51e66a47SVivek Prakash 	if (term->name == NULL)
145*51e66a47SVivek Prakash 		errx(1, "malloc");
146*51e66a47SVivek Prakash 	term->next = terms;
147*51e66a47SVivek Prakash 	terms = term;
148*51e66a47SVivek Prakash 	return term;
149*51e66a47SVivek Prakash }
150*51e66a47SVivek Prakash 
151*51e66a47SVivek Prakash static int
152*51e66a47SVivek Prakash process_entry(TBUF *buf, int flags)
153*51e66a47SVivek Prakash {
154*51e66a47SVivek Prakash 	char *p, *e, *alias;
155*51e66a47SVivek Prakash 	TERM *term;
156*51e66a47SVivek Prakash 	TIC *tic;
157*51e66a47SVivek Prakash 
158*51e66a47SVivek Prakash 	if (buf->bufpos == 0)
159*51e66a47SVivek Prakash 		return 0;
160*51e66a47SVivek Prakash 	/* Terminate the string */
161*51e66a47SVivek Prakash 	buf->buf[buf->bufpos - 1] = '\0';
162*51e66a47SVivek Prakash 	/* First rewind the buffer for new entries */
163*51e66a47SVivek Prakash 	buf->bufpos = 0;
164*51e66a47SVivek Prakash 
165*51e66a47SVivek Prakash 	if (isspace((unsigned char)*buf->buf))
166*51e66a47SVivek Prakash 		return 0;
167*51e66a47SVivek Prakash 
168*51e66a47SVivek Prakash 	tic = _ti_compile(buf->buf, flags);
169*51e66a47SVivek Prakash 	if (tic == NULL)
170*51e66a47SVivek Prakash 		return 0;
171*51e66a47SVivek Prakash 
172*51e66a47SVivek Prakash 	if (find_term(tic->name) != NULL) {
173*51e66a47SVivek Prakash 		dowarn("%s: duplicate entry", tic->name);
174*51e66a47SVivek Prakash 		_ti_freetic(tic);
175*51e66a47SVivek Prakash 		return 0;
176*51e66a47SVivek Prakash 	}
177*51e66a47SVivek Prakash 	term = store_term(tic->name, 't');
178*51e66a47SVivek Prakash 	term->tic = tic;
179*51e66a47SVivek Prakash 
180*51e66a47SVivek Prakash 	/* Create aliased terms */
181*51e66a47SVivek Prakash 	if (tic->alias != NULL) {
182*51e66a47SVivek Prakash 		alias = p = strdup(tic->alias);
183*51e66a47SVivek Prakash 		while (p != NULL && *p != '\0') {
184*51e66a47SVivek Prakash 			e = strchr(p, '|');
185*51e66a47SVivek Prakash 			if (e != NULL)
186*51e66a47SVivek Prakash 				*e++ = '\0';
187*51e66a47SVivek Prakash 			if (find_term(p) != NULL) {
188*51e66a47SVivek Prakash 				dowarn("%s: has alias for already assigned"
189*51e66a47SVivek Prakash 				    " term %s", tic->name, p);
190*51e66a47SVivek Prakash 			} else {
191*51e66a47SVivek Prakash 				term = store_term(p, 'a');
192*51e66a47SVivek Prakash 				term->tic = calloc(sizeof(*term->tic), 1);
193*51e66a47SVivek Prakash 				if (term->tic == NULL)
194*51e66a47SVivek Prakash 					err(1, "malloc");
195*51e66a47SVivek Prakash 				term->tic->name = strdup(tic->name);
196*51e66a47SVivek Prakash 				if (term->tic->name == NULL)
197*51e66a47SVivek Prakash 					err(1, "malloc");
198*51e66a47SVivek Prakash 			}
199*51e66a47SVivek Prakash 			p = e;
200*51e66a47SVivek Prakash 		}
201*51e66a47SVivek Prakash 	}
202*51e66a47SVivek Prakash 
203*51e66a47SVivek Prakash 	return 0;
204*51e66a47SVivek Prakash }
205*51e66a47SVivek Prakash 
206*51e66a47SVivek Prakash static void
207*51e66a47SVivek Prakash merge(TIC *rtic, TIC *utic, int flags)
208*51e66a47SVivek Prakash {
209*51e66a47SVivek Prakash 	char *cap, flag, *code, type, *str;
210*51e66a47SVivek Prakash 	short ind, num;
211*51e66a47SVivek Prakash 	size_t n;
212*51e66a47SVivek Prakash 
213*51e66a47SVivek Prakash 	cap = utic->flags.buf;
214*51e66a47SVivek Prakash 	for (n = utic->flags.entries; n > 0; n--) {
215*51e66a47SVivek Prakash 		ind = le16dec(cap);
216*51e66a47SVivek Prakash 		cap += sizeof(uint16_t);
217*51e66a47SVivek Prakash 		flag = *cap++;
218*51e66a47SVivek Prakash 		if (VALID_BOOLEAN(flag) &&
219*51e66a47SVivek Prakash 		    _ti_find_cap(&rtic->flags, 'f', ind) == NULL)
220*51e66a47SVivek Prakash 		{
221*51e66a47SVivek Prakash 			_ti_grow_tbuf(&rtic->flags, sizeof(uint16_t) + 1);
222*51e66a47SVivek Prakash 			le16enc(rtic->flags.buf + rtic->flags.bufpos, ind);
223*51e66a47SVivek Prakash 			rtic->flags.bufpos += sizeof(uint16_t);
224*51e66a47SVivek Prakash 			rtic->flags.buf[rtic->flags.bufpos++] = flag;
225*51e66a47SVivek Prakash 			rtic->flags.entries++;
226*51e66a47SVivek Prakash 		}
227*51e66a47SVivek Prakash 	}
228*51e66a47SVivek Prakash 
229*51e66a47SVivek Prakash 	cap = utic->nums.buf;
230*51e66a47SVivek Prakash 	for (n = utic->nums.entries; n > 0; n--) {
231*51e66a47SVivek Prakash 		ind = le16dec(cap);
232*51e66a47SVivek Prakash 		cap += sizeof(uint16_t);
233*51e66a47SVivek Prakash 		num = le16dec(cap);
234*51e66a47SVivek Prakash 		cap += sizeof(uint16_t);
235*51e66a47SVivek Prakash 		if (VALID_NUMERIC(num) &&
236*51e66a47SVivek Prakash 		    _ti_find_cap(&rtic->nums, 'n', ind) == NULL)
237*51e66a47SVivek Prakash 		{
238*51e66a47SVivek Prakash 			grow_tbuf(&rtic->nums, sizeof(uint16_t) * 2);
239*51e66a47SVivek Prakash 			le16enc(rtic->nums.buf + rtic->nums.bufpos, ind);
240*51e66a47SVivek Prakash 			rtic->nums.bufpos += sizeof(uint16_t);
241*51e66a47SVivek Prakash 			le16enc(rtic->nums.buf + rtic->nums.bufpos, num);
242*51e66a47SVivek Prakash 			rtic->nums.bufpos += sizeof(uint16_t);
243*51e66a47SVivek Prakash 			rtic->nums.entries++;
244*51e66a47SVivek Prakash 		}
245*51e66a47SVivek Prakash 	}
246*51e66a47SVivek Prakash 
247*51e66a47SVivek Prakash 	cap = utic->strs.buf;
248*51e66a47SVivek Prakash 	for (n = utic->strs.entries; n > 0; n--) {
249*51e66a47SVivek Prakash 		ind = le16dec(cap);
250*51e66a47SVivek Prakash 		cap += sizeof(uint16_t);
251*51e66a47SVivek Prakash 		num = le16dec(cap);
252*51e66a47SVivek Prakash 		cap += sizeof(uint16_t);
253*51e66a47SVivek Prakash 		if (num > 0 &&
254*51e66a47SVivek Prakash 		    _ti_find_cap(&rtic->strs, 's', ind) == NULL)
255*51e66a47SVivek Prakash 		{
256*51e66a47SVivek Prakash 			grow_tbuf(&rtic->strs, (sizeof(uint16_t) * 2) + num);
257*51e66a47SVivek Prakash 			le16enc(rtic->strs.buf + rtic->strs.bufpos, ind);
258*51e66a47SVivek Prakash 			rtic->strs.bufpos += sizeof(uint16_t);
259*51e66a47SVivek Prakash 			le16enc(rtic->strs.buf + rtic->strs.bufpos, num);
260*51e66a47SVivek Prakash 			rtic->strs.bufpos += sizeof(uint16_t);
261*51e66a47SVivek Prakash 			memcpy(rtic->strs.buf + rtic->strs.bufpos,
262*51e66a47SVivek Prakash 			    cap, num);
263*51e66a47SVivek Prakash 			rtic->strs.bufpos += num;
264*51e66a47SVivek Prakash 			rtic->strs.entries++;
265*51e66a47SVivek Prakash 		}
266*51e66a47SVivek Prakash 		cap += num;
267*51e66a47SVivek Prakash 	}
268*51e66a47SVivek Prakash 
269*51e66a47SVivek Prakash 	cap = utic->extras.buf;
270*51e66a47SVivek Prakash 	for (n = utic->extras.entries; n > 0; n--) {
271*51e66a47SVivek Prakash 		num = le16dec(cap);
272*51e66a47SVivek Prakash 		cap += sizeof(uint16_t);
273*51e66a47SVivek Prakash 		code = cap;
274*51e66a47SVivek Prakash 		cap += num;
275*51e66a47SVivek Prakash 		type = *cap++;
276*51e66a47SVivek Prakash 		flag = 0;
277*51e66a47SVivek Prakash 		str = NULL;
278*51e66a47SVivek Prakash 		switch (type) {
279*51e66a47SVivek Prakash 		case 'f':
280*51e66a47SVivek Prakash 			flag = *cap++;
281*51e66a47SVivek Prakash 			if (!VALID_BOOLEAN(flag))
282*51e66a47SVivek Prakash 				continue;
283*51e66a47SVivek Prakash 			break;
284*51e66a47SVivek Prakash 		case 'n':
285*51e66a47SVivek Prakash 			num = le16dec(cap);
286*51e66a47SVivek Prakash 			cap += sizeof(uint16_t);
287*51e66a47SVivek Prakash 			if (!VALID_NUMERIC(num))
288*51e66a47SVivek Prakash 				continue;
289*51e66a47SVivek Prakash 			break;
290*51e66a47SVivek Prakash 		case 's':
291*51e66a47SVivek Prakash 			num = le16dec(cap);
292*51e66a47SVivek Prakash 			cap += sizeof(uint16_t);
293*51e66a47SVivek Prakash 			str = cap;
294*51e66a47SVivek Prakash 			cap += num;
295*51e66a47SVivek Prakash 			if (num == 0)
296*51e66a47SVivek Prakash 				continue;
297*51e66a47SVivek Prakash 			break;
298*51e66a47SVivek Prakash 		}
299*51e66a47SVivek Prakash 		_ti_store_extra(rtic, 0, code, type, flag, num, str, num,
300*51e66a47SVivek Prakash 		    flags);
301*51e66a47SVivek Prakash 	}
302*51e66a47SVivek Prakash }
303*51e66a47SVivek Prakash 
304*51e66a47SVivek Prakash static size_t
305*51e66a47SVivek Prakash merge_use(int flags)
306*51e66a47SVivek Prakash {
307*51e66a47SVivek Prakash 	size_t skipped, merged, memn;
308*51e66a47SVivek Prakash 	char *cap, *scap;
309*51e66a47SVivek Prakash 	uint16_t num;
310*51e66a47SVivek Prakash 	TIC *rtic, *utic;
311*51e66a47SVivek Prakash 	TERM *term, *uterm;;
312*51e66a47SVivek Prakash 
313*51e66a47SVivek Prakash 	skipped = merged = 0;
314*51e66a47SVivek Prakash 	for (term = terms; term != NULL; term = term->next) {
315*51e66a47SVivek Prakash 		if (term->type == 'a')
316*51e66a47SVivek Prakash 			continue;
317*51e66a47SVivek Prakash 		rtic = term->tic;
318*51e66a47SVivek Prakash 		while ((cap = _ti_find_extra(&rtic->extras, "use")) != NULL) {
319*51e66a47SVivek Prakash 			if (*cap++ != 's') {
320*51e66a47SVivek Prakash 				dowarn("%s: use is not string", rtic->name);
321*51e66a47SVivek Prakash 				break;
322*51e66a47SVivek Prakash 			}
323*51e66a47SVivek Prakash 			cap += sizeof(uint16_t);
324*51e66a47SVivek Prakash 			if (strcmp(rtic->name, cap) == 0) {
325*51e66a47SVivek Prakash 				dowarn("%s: uses itself", rtic->name);
326*51e66a47SVivek Prakash 				goto remove;
327*51e66a47SVivek Prakash 			}
328*51e66a47SVivek Prakash 			uterm = find_term(cap);
329*51e66a47SVivek Prakash 			if (uterm != NULL && uterm->type == 'a')
330*51e66a47SVivek Prakash 				uterm = find_term(uterm->tic->name);
331*51e66a47SVivek Prakash 			if (uterm == NULL) {
332*51e66a47SVivek Prakash 				dowarn("%s: no use record for %s",
333*51e66a47SVivek Prakash 				    rtic->name, cap);
334*51e66a47SVivek Prakash 				goto remove;
335*51e66a47SVivek Prakash 			}
336*51e66a47SVivek Prakash 			utic = uterm->tic;
337*51e66a47SVivek Prakash 			if (strcmp(utic->name, rtic->name) == 0) {
338*51e66a47SVivek Prakash 				dowarn("%s: uses itself", rtic->name);
339*51e66a47SVivek Prakash 				goto remove;
340*51e66a47SVivek Prakash 			}
341*51e66a47SVivek Prakash 			if (_ti_find_extra(&utic->extras, "use") != NULL) {
342*51e66a47SVivek Prakash 				skipped++;
343*51e66a47SVivek Prakash 				break;
344*51e66a47SVivek Prakash 			}
345*51e66a47SVivek Prakash 			cap = _ti_find_extra(&rtic->extras, "use");
346*51e66a47SVivek Prakash 			merge(rtic, utic, flags);
347*51e66a47SVivek Prakash 	remove:
348*51e66a47SVivek Prakash 			/* The pointers may have changed, find the use again */
349*51e66a47SVivek Prakash 			cap = _ti_find_extra(&rtic->extras, "use");
350*51e66a47SVivek Prakash 			if (cap == NULL)
351*51e66a47SVivek Prakash 				dowarn("%s: use no longer exists - impossible",
352*51e66a47SVivek Prakash 					rtic->name);
353*51e66a47SVivek Prakash 			else {
354*51e66a47SVivek Prakash 				scap = cap - (4 + sizeof(uint16_t));
355*51e66a47SVivek Prakash 				cap++;
356*51e66a47SVivek Prakash 				num = le16dec(cap);
357*51e66a47SVivek Prakash 				cap += sizeof(uint16_t) + num;
358*51e66a47SVivek Prakash 				memn = rtic->extras.bufpos -
359*51e66a47SVivek Prakash 				    (cap - rtic->extras.buf);
360*51e66a47SVivek Prakash 				memcpy(scap, cap, memn);
361*51e66a47SVivek Prakash 				rtic->extras.bufpos -= cap - scap;
362*51e66a47SVivek Prakash 				cap = scap;
363*51e66a47SVivek Prakash 				rtic->extras.entries--;
364*51e66a47SVivek Prakash 				merged++;
365*51e66a47SVivek Prakash 			}
366*51e66a47SVivek Prakash 		}
367*51e66a47SVivek Prakash 	}
368*51e66a47SVivek Prakash 
369*51e66a47SVivek Prakash 	if (merged == 0 && skipped != 0)
370*51e66a47SVivek Prakash 		dowarn("circular use detected");
371*51e66a47SVivek Prakash 	return merged;
372*51e66a47SVivek Prakash }
373*51e66a47SVivek Prakash 
374*51e66a47SVivek Prakash static int
375*51e66a47SVivek Prakash print_dump(int argc, char **argv)
376*51e66a47SVivek Prakash {
377*51e66a47SVivek Prakash 	TERM *term;
378*51e66a47SVivek Prakash 	uint8_t *buf;
379*51e66a47SVivek Prakash 	int i, n;
380*51e66a47SVivek Prakash 	size_t j, col;
381*51e66a47SVivek Prakash 	ssize_t len;
382*51e66a47SVivek Prakash 
383*51e66a47SVivek Prakash 	printf("struct compiled_term {\n");
384*51e66a47SVivek Prakash 	printf("\tconst char *name;\n");
385*51e66a47SVivek Prakash 	printf("\tconst char *cap;\n");
386*51e66a47SVivek Prakash 	printf("\tsize_t caplen;\n");
387*51e66a47SVivek Prakash 	printf("};\n\n");
388*51e66a47SVivek Prakash 
389*51e66a47SVivek Prakash 	printf("const struct compiled_term compiled_terms[] = {\n");
390*51e66a47SVivek Prakash 
391*51e66a47SVivek Prakash 	n = 0;
392*51e66a47SVivek Prakash 	for (i = 0; i < argc; i++) {
393*51e66a47SVivek Prakash 		term = find_term(argv[i]);
394*51e66a47SVivek Prakash 		if (term == NULL) {
395*51e66a47SVivek Prakash 			warnx("%s: no description for terminal", argv[i]);
396*51e66a47SVivek Prakash 			continue;
397*51e66a47SVivek Prakash 		}
398*51e66a47SVivek Prakash 		if (term->type == 'a') {
399*51e66a47SVivek Prakash 			warnx("%s: cannot dump alias", argv[i]);
400*51e66a47SVivek Prakash 			continue;
401*51e66a47SVivek Prakash 		}
402*51e66a47SVivek Prakash 		/* Don't compile the aliases in, save space */
403*51e66a47SVivek Prakash 		free(term->tic->alias);
404*51e66a47SVivek Prakash 		term->tic->alias = NULL;
405*51e66a47SVivek Prakash 		len = _ti_flatten(&buf, term->tic);
406*51e66a47SVivek Prakash 		if (len == 0 || len == -1)
407*51e66a47SVivek Prakash 			continue;
408*51e66a47SVivek Prakash 
409*51e66a47SVivek Prakash 		printf("\t{\n");
410*51e66a47SVivek Prakash 		printf("\t\t\"%s\",\n", argv[i]);
411*51e66a47SVivek Prakash 		n++;
412*51e66a47SVivek Prakash 		for (j = 0, col = 0; j < (size_t)len; j++) {
413*51e66a47SVivek Prakash 			if (col == 0) {
414*51e66a47SVivek Prakash 				printf("\t\t\"");
415*51e66a47SVivek Prakash 				col = 16;
416*51e66a47SVivek Prakash 			}
417*51e66a47SVivek Prakash 
418*51e66a47SVivek Prakash 			col += printf("\\%03o", (uint8_t)buf[j]);
419*51e66a47SVivek Prakash 			if (col > 75) {
420*51e66a47SVivek Prakash 				printf("\"%s\n",
421*51e66a47SVivek Prakash 				    j + 1 == (size_t)len ? "," : "");
422*51e66a47SVivek Prakash 				col = 0;
423*51e66a47SVivek Prakash 			}
424*51e66a47SVivek Prakash 		}
425*51e66a47SVivek Prakash 		if (col != 0)
426*51e66a47SVivek Prakash 			printf("\",\n");
427*51e66a47SVivek Prakash 		printf("\t\t%zu\n", len);
428*51e66a47SVivek Prakash 		printf("\t}");
429*51e66a47SVivek Prakash 		if (i + 1 < argc)
430*51e66a47SVivek Prakash 			printf(",");
431*51e66a47SVivek Prakash 		printf("\n");
432*51e66a47SVivek Prakash 		free(buf);
433*51e66a47SVivek Prakash 	}
434*51e66a47SVivek Prakash 	printf("};\n");
435*51e66a47SVivek Prakash 
436*51e66a47SVivek Prakash 	return n;
437*51e66a47SVivek Prakash }
438*51e66a47SVivek Prakash 
439*51e66a47SVivek Prakash int
440*51e66a47SVivek Prakash main(int argc, char **argv)
441*51e66a47SVivek Prakash {
442*51e66a47SVivek Prakash 	int ch, cflag, sflag, flags;
443*51e66a47SVivek Prakash 	char *source, *p, *buf, *ofile;
444*51e66a47SVivek Prakash 	FILE *f;
445*51e66a47SVivek Prakash 	DBM *db;
446*51e66a47SVivek Prakash 	size_t len, buflen, nterm, nalias;
447*51e66a47SVivek Prakash 	TBUF tbuf;
448*51e66a47SVivek Prakash 	TERM *term;
449*51e66a47SVivek Prakash 
450*51e66a47SVivek Prakash 	cflag = sflag = 0;
451*51e66a47SVivek Prakash 	ofile = NULL;
452*51e66a47SVivek Prakash 	flags = TIC_ALIAS | TIC_DESCRIPTION | TIC_WARNING;
453*51e66a47SVivek Prakash 	while ((ch = getopt(argc, argv, "Saco:sx")) != -1)
454*51e66a47SVivek Prakash 	    switch (ch) {
455*51e66a47SVivek Prakash 	    case 'S':
456*51e66a47SVivek Prakash 		    Sflag = 1;
457*51e66a47SVivek Prakash 		    /* We still compile aliases so that use= works.
458*51e66a47SVivek Prakash 		     * However, it's removed before we flatten to save space. */
459*51e66a47SVivek Prakash 		    flags &= ~TIC_DESCRIPTION;
460*51e66a47SVivek Prakash 		    break;
461*51e66a47SVivek Prakash 	    case 'a':
462*51e66a47SVivek Prakash 		    flags |= TIC_COMMENT;
463*51e66a47SVivek Prakash 		    break;
464*51e66a47SVivek Prakash 	    case 'c':
465*51e66a47SVivek Prakash 		    cflag = 1;
466*51e66a47SVivek Prakash 		    break;
467*51e66a47SVivek Prakash 	    case 'o':
468*51e66a47SVivek Prakash 		    ofile = optarg;
469*51e66a47SVivek Prakash 		    break;
470*51e66a47SVivek Prakash 	    case 's':
471*51e66a47SVivek Prakash 		    sflag = 1;
472*51e66a47SVivek Prakash 		    break;
473*51e66a47SVivek Prakash 	    case 'x':
474*51e66a47SVivek Prakash 		    flags |= TIC_EXTRA;
475*51e66a47SVivek Prakash 		    break;
476*51e66a47SVivek Prakash 	    case '?': /* FALLTHROUGH */
477*51e66a47SVivek Prakash 	    default:
478*51e66a47SVivek Prakash 		    fprintf(stderr, "usage: %s [-acSsx] [-o file] source\n",
479*51e66a47SVivek Prakash 			getprogname());
480*51e66a47SVivek Prakash 		    return EXIT_FAILURE;
481*51e66a47SVivek Prakash 	    }
482*51e66a47SVivek Prakash 
483*51e66a47SVivek Prakash 	if (optind == argc)
484*51e66a47SVivek Prakash 		errx(1, "No source file given");
485*51e66a47SVivek Prakash 	source = argv[optind++];
486*51e66a47SVivek Prakash 	f = fopen(source, "r");
487*51e66a47SVivek Prakash 	if (f == NULL)
488*51e66a47SVivek Prakash 		err(1, "fopen: %s", source);
489*51e66a47SVivek Prakash 	if (!cflag && !Sflag) {
490*51e66a47SVivek Prakash 		if (ofile == NULL)
491*51e66a47SVivek Prakash 			ofile = source;
492*51e66a47SVivek Prakash 		len = strlen(ofile) + 9;
493*51e66a47SVivek Prakash 		dbname = malloc(len + 4); /* For adding .db after open */
494*51e66a47SVivek Prakash 		if (dbname == NULL)
495*51e66a47SVivek Prakash 			err(1, "malloc");
496*51e66a47SVivek Prakash 		snprintf(dbname, len, "%s.tmp", ofile);
497*51e66a47SVivek Prakash 		db = dbm_open(dbname, O_CREAT | O_RDWR | O_TRUNC, DEFFILEMODE);
498*51e66a47SVivek Prakash 		if (db == NULL)
499*51e66a47SVivek Prakash 			err(1, "dbopen: %s", source);
500*51e66a47SVivek Prakash 		p = dbname + strlen(dbname);
501*51e66a47SVivek Prakash 		*p++ = '.';
502*51e66a47SVivek Prakash 		*p++ = 'd';
503*51e66a47SVivek Prakash 		*p++ = 'b';
504*51e66a47SVivek Prakash 		*p++ = '\0';
505*51e66a47SVivek Prakash 		atexit(do_unlink);
506*51e66a47SVivek Prakash 	} else
507*51e66a47SVivek Prakash 		db = NULL; /* satisfy gcc warning */
508*51e66a47SVivek Prakash 
509*51e66a47SVivek Prakash 	tbuf.buflen = tbuf.bufpos = 0;
510*51e66a47SVivek Prakash 	while ((buf = fgetln(f, &buflen)) != NULL) {
511*51e66a47SVivek Prakash 		/* Skip comments */
512*51e66a47SVivek Prakash 		if (*buf == '#')
513*51e66a47SVivek Prakash 			continue;
514*51e66a47SVivek Prakash 		if (buf[buflen - 1] != '\n') {
515*51e66a47SVivek Prakash 			process_entry(&tbuf, flags);
516*51e66a47SVivek Prakash 			dowarn("last line is not a comment"
517*51e66a47SVivek Prakash 			    " and does not end with a newline");
518*51e66a47SVivek Prakash 			continue;
519*51e66a47SVivek Prakash 		}
520*51e66a47SVivek Prakash 		/*
521*51e66a47SVivek Prakash 		  If the first char is space not a space then we have a
522*51e66a47SVivek Prakash 		  new entry, so process it.
523*51e66a47SVivek Prakash 		*/
524*51e66a47SVivek Prakash 		if (!isspace((unsigned char)*buf) && tbuf.bufpos != 0)
525*51e66a47SVivek Prakash 			process_entry(&tbuf, flags);
526*51e66a47SVivek Prakash 
527*51e66a47SVivek Prakash 		/* Grow the buffer if needed */
528*51e66a47SVivek Prakash 		grow_tbuf(&tbuf, buflen);
529*51e66a47SVivek Prakash 		/* Append the string */
530*51e66a47SVivek Prakash 		memcpy(tbuf.buf + tbuf.bufpos, buf, buflen);
531*51e66a47SVivek Prakash 		tbuf.bufpos += buflen;
532*51e66a47SVivek Prakash 	}
533*51e66a47SVivek Prakash 	/* Process the last entry if not done already */
534*51e66a47SVivek Prakash 	process_entry(&tbuf, flags);
535*51e66a47SVivek Prakash 
536*51e66a47SVivek Prakash 	/* Merge use entries until we have merged all we can */
537*51e66a47SVivek Prakash 	while (merge_use(flags) != 0)
538*51e66a47SVivek Prakash 		;
539*51e66a47SVivek Prakash 
540*51e66a47SVivek Prakash 	if (Sflag) {
541*51e66a47SVivek Prakash 		print_dump(argc - optind, argv + optind);
542*51e66a47SVivek Prakash 		return error_exit;
543*51e66a47SVivek Prakash 	}
544*51e66a47SVivek Prakash 
545*51e66a47SVivek Prakash 	if (cflag)
546*51e66a47SVivek Prakash 		return error_exit;
547*51e66a47SVivek Prakash 
548*51e66a47SVivek Prakash 	/* Save the terms */
549*51e66a47SVivek Prakash 	nterm = nalias = 0;
550*51e66a47SVivek Prakash 	for (term = terms; term != NULL; term = term->next) {
551*51e66a47SVivek Prakash 		save_term(db, term);
552*51e66a47SVivek Prakash 		if (term->type == 'a')
553*51e66a47SVivek Prakash 			nalias++;
554*51e66a47SVivek Prakash 		else
555*51e66a47SVivek Prakash 			nterm++;
556*51e66a47SVivek Prakash 	}
557*51e66a47SVivek Prakash 
558*51e66a47SVivek Prakash 	/* done! */
559*51e66a47SVivek Prakash 	dbm_close(db);
560*51e66a47SVivek Prakash 
561*51e66a47SVivek Prakash 	/* Rename the tmp db to the real one now */
562*51e66a47SVivek Prakash 	len = strlen(ofile) + 4;
563*51e66a47SVivek Prakash 	p = malloc(len);
564*51e66a47SVivek Prakash 	if (p == NULL)
565*51e66a47SVivek Prakash 		err(1, "malloc");
566*51e66a47SVivek Prakash 	snprintf(p, len, "%s.db", ofile);
567*51e66a47SVivek Prakash 	if (rename(dbname, p) == -1)
568*51e66a47SVivek Prakash 		err(1, "rename");
569*51e66a47SVivek Prakash 	free(dbname);
570*51e66a47SVivek Prakash 	dbname = NULL;
571*51e66a47SVivek Prakash 
572*51e66a47SVivek Prakash 	if (sflag != 0)
573*51e66a47SVivek Prakash 		fprintf(stderr, "%zu entries and %zu aliases written to %s\n",
574*51e66a47SVivek Prakash 		    nterm, nalias, p);
575*51e66a47SVivek Prakash 
576*51e66a47SVivek Prakash 	return EXIT_SUCCESS;
577*51e66a47SVivek Prakash }
578