xref: /minix3/usr.bin/tic/tic.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /* $NetBSD: tic.c,v 1.24 2014/07/20 20:20:16 christos Exp $ */
251e66a47SVivek Prakash 
351e66a47SVivek Prakash /*
451e66a47SVivek Prakash  * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc.
551e66a47SVivek Prakash  *
651e66a47SVivek Prakash  * This code is derived from software contributed to The NetBSD Foundation
751e66a47SVivek Prakash  * by Roy Marples.
851e66a47SVivek Prakash  *
951e66a47SVivek Prakash  * Redistribution and use in source and binary forms, with or without
1051e66a47SVivek Prakash  * modification, are permitted provided that the following conditions
1151e66a47SVivek Prakash  * are met:
1251e66a47SVivek Prakash  * 1. Redistributions of source code must retain the above copyright
1351e66a47SVivek Prakash  *    notice, this list of conditions and the following disclaimer.
1451e66a47SVivek Prakash  * 2. Redistributions in binary form must reproduce the above copyright
1551e66a47SVivek Prakash  *    notice, this list of conditions and the following disclaimer in the
1651e66a47SVivek Prakash  *    documentation and/or other materials provided with the distribution.
1751e66a47SVivek Prakash  *
1851e66a47SVivek Prakash  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1951e66a47SVivek Prakash  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2051e66a47SVivek Prakash  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2151e66a47SVivek Prakash  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2251e66a47SVivek Prakash  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2351e66a47SVivek Prakash  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2451e66a47SVivek Prakash  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2551e66a47SVivek Prakash  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2651e66a47SVivek Prakash  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2751e66a47SVivek Prakash  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2851e66a47SVivek Prakash  */
2951e66a47SVivek Prakash 
3051e66a47SVivek Prakash #if HAVE_NBTOOL_CONFIG_H
3151e66a47SVivek Prakash #include "nbtool_config.h"
3251e66a47SVivek Prakash #endif
3351e66a47SVivek Prakash 
3451e66a47SVivek Prakash #include <sys/cdefs.h>
35*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: tic.c,v 1.24 2014/07/20 20:20:16 christos Exp $");
3651e66a47SVivek Prakash 
3751e66a47SVivek Prakash #include <sys/types.h>
3886344bb5SKees Jongenburger #include <sys/queue.h>
3951e66a47SVivek Prakash 
4051e66a47SVivek Prakash #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
4151e66a47SVivek Prakash #include <sys/endian.h>
4251e66a47SVivek Prakash #endif
4351e66a47SVivek Prakash 
4484d9c625SLionel Sambuc #include <cdbw.h>
4551e66a47SVivek Prakash #include <ctype.h>
4651e66a47SVivek Prakash #include <err.h>
4751e66a47SVivek Prakash #include <errno.h>
4851e66a47SVivek Prakash #include <getopt.h>
4951e66a47SVivek Prakash #include <limits.h>
5051e66a47SVivek Prakash #include <fcntl.h>
5186344bb5SKees Jongenburger #include <search.h>
5251e66a47SVivek Prakash #include <stdarg.h>
5351e66a47SVivek Prakash #include <stdlib.h>
5451e66a47SVivek Prakash #include <stdio.h>
5551e66a47SVivek Prakash #include <string.h>
5651e66a47SVivek Prakash #include <term_private.h>
5751e66a47SVivek Prakash #include <term.h>
5886344bb5SKees Jongenburger #include <util.h>
5986344bb5SKees Jongenburger 
6086344bb5SKees Jongenburger #define	HASH_SIZE	16384	/* 2012-06-01: 3600 entries */
6151e66a47SVivek Prakash 
6251e66a47SVivek Prakash typedef struct term {
6384d9c625SLionel Sambuc 	STAILQ_ENTRY(term) next;
6451e66a47SVivek Prakash 	char *name;
6551e66a47SVivek Prakash 	TIC *tic;
6684d9c625SLionel Sambuc 	uint32_t id;
6784d9c625SLionel Sambuc 	struct term *base_term;
6851e66a47SVivek Prakash } TERM;
6984d9c625SLionel Sambuc static STAILQ_HEAD(, term) terms = STAILQ_HEAD_INITIALIZER(terms);
7051e66a47SVivek Prakash 
7151e66a47SVivek Prakash static int error_exit;
7251e66a47SVivek Prakash static int Sflag;
7386344bb5SKees Jongenburger static size_t nterm, nalias;
7451e66a47SVivek Prakash 
7586344bb5SKees Jongenburger static void __printflike(1, 2)
dowarn(const char * fmt,...)7651e66a47SVivek Prakash dowarn(const char *fmt, ...)
7751e66a47SVivek Prakash {
7851e66a47SVivek Prakash 	va_list va;
7951e66a47SVivek Prakash 
8051e66a47SVivek Prakash 	error_exit = 1;
8151e66a47SVivek Prakash 	va_start(va, fmt);
8251e66a47SVivek Prakash 	vwarnx(fmt, va);
8351e66a47SVivek Prakash 	va_end(va);
8451e66a47SVivek Prakash }
8551e66a47SVivek Prakash 
8651e66a47SVivek Prakash static char *
grow_tbuf(TBUF * tbuf,size_t len)8751e66a47SVivek Prakash grow_tbuf(TBUF *tbuf, size_t len)
8851e66a47SVivek Prakash {
8951e66a47SVivek Prakash 	char *buf;
9051e66a47SVivek Prakash 
9151e66a47SVivek Prakash 	buf = _ti_grow_tbuf(tbuf, len);
9251e66a47SVivek Prakash 	if (buf == NULL)
9351e66a47SVivek Prakash 		err(1, "_ti_grow_tbuf");
9451e66a47SVivek Prakash 	return buf;
9551e66a47SVivek Prakash }
9651e66a47SVivek Prakash 
9751e66a47SVivek Prakash static int
save_term(struct cdbw * db,TERM * term)9884d9c625SLionel Sambuc save_term(struct cdbw *db, TERM *term)
9951e66a47SVivek Prakash {
10051e66a47SVivek Prakash 	uint8_t *buf;
10151e66a47SVivek Prakash 	ssize_t len;
10284d9c625SLionel Sambuc 	size_t slen = strlen(term->name) + 1;
10384d9c625SLionel Sambuc 
10484d9c625SLionel Sambuc 	if (term->base_term != NULL) {
10584d9c625SLionel Sambuc 		len = (ssize_t)slen + 7;
10684d9c625SLionel Sambuc 		buf = emalloc(len);
10784d9c625SLionel Sambuc 		buf[0] = 2;
10884d9c625SLionel Sambuc 		le32enc(buf + 1, term->base_term->id);
10984d9c625SLionel Sambuc 		le16enc(buf + 5, slen);
11084d9c625SLionel Sambuc 		memcpy(buf + 7, term->name, slen);
11184d9c625SLionel Sambuc 		if (cdbw_put(db, term->name, slen, buf, len))
11284d9c625SLionel Sambuc 			err(1, "cdbw_put");
11384d9c625SLionel Sambuc 		return 0;
11484d9c625SLionel Sambuc 	}
11551e66a47SVivek Prakash 
11651e66a47SVivek Prakash 	len = _ti_flatten(&buf, term->tic);
11751e66a47SVivek Prakash 	if (len == -1)
11851e66a47SVivek Prakash 		return -1;
11951e66a47SVivek Prakash 
12084d9c625SLionel Sambuc 	if (cdbw_put_data(db, buf, len, &term->id))
12184d9c625SLionel Sambuc 		err(1, "cdbw_put_data");
12284d9c625SLionel Sambuc 	if (cdbw_put_key(db, term->name, slen, term->id))
12384d9c625SLionel Sambuc 		err(1, "cdbw_put_key");
12451e66a47SVivek Prakash 	free(buf);
12551e66a47SVivek Prakash 	return 0;
12651e66a47SVivek Prakash }
12751e66a47SVivek Prakash 
12851e66a47SVivek Prakash static TERM *
find_term(const char * name)12951e66a47SVivek Prakash find_term(const char *name)
13051e66a47SVivek Prakash {
13186344bb5SKees Jongenburger 	ENTRY elem, *elemp;
13251e66a47SVivek Prakash 
13386344bb5SKees Jongenburger 	elem.key = __UNCONST(name);
13486344bb5SKees Jongenburger 	elem.data = NULL;
13586344bb5SKees Jongenburger 	elemp = hsearch(elem, FIND);
13686344bb5SKees Jongenburger 	return elemp ? (TERM *)elemp->data : NULL;
13751e66a47SVivek Prakash }
13851e66a47SVivek Prakash 
13951e66a47SVivek Prakash static TERM *
store_term(const char * name,TERM * base_term)14084d9c625SLionel Sambuc store_term(const char *name, TERM *base_term)
14151e66a47SVivek Prakash {
14251e66a47SVivek Prakash 	TERM *term;
14386344bb5SKees Jongenburger 	ENTRY elem;
14451e66a47SVivek Prakash 
14586344bb5SKees Jongenburger 	term = ecalloc(1, sizeof(*term));
14686344bb5SKees Jongenburger 	term->name = estrdup(name);
14784d9c625SLionel Sambuc 	STAILQ_INSERT_TAIL(&terms, term, next);
14886344bb5SKees Jongenburger 	elem.key = estrdup(name);
14986344bb5SKees Jongenburger 	elem.data = term;
15086344bb5SKees Jongenburger 	hsearch(elem, ENTER);
15186344bb5SKees Jongenburger 
15284d9c625SLionel Sambuc 	term->base_term = base_term;
15384d9c625SLionel Sambuc 	if (base_term != NULL)
15486344bb5SKees Jongenburger 		nalias++;
15586344bb5SKees Jongenburger 	else
15686344bb5SKees Jongenburger 		nterm++;
15786344bb5SKees Jongenburger 
15851e66a47SVivek Prakash 	return term;
15951e66a47SVivek Prakash }
16051e66a47SVivek Prakash 
16151e66a47SVivek Prakash static int
process_entry(TBUF * buf,int flags)16251e66a47SVivek Prakash process_entry(TBUF *buf, int flags)
16351e66a47SVivek Prakash {
16451e66a47SVivek Prakash 	char *p, *e, *alias;
16551e66a47SVivek Prakash 	TERM *term;
16651e66a47SVivek Prakash 	TIC *tic;
16751e66a47SVivek Prakash 
16851e66a47SVivek Prakash 	if (buf->bufpos == 0)
16951e66a47SVivek Prakash 		return 0;
17051e66a47SVivek Prakash 	/* Terminate the string */
17151e66a47SVivek Prakash 	buf->buf[buf->bufpos - 1] = '\0';
17251e66a47SVivek Prakash 	/* First rewind the buffer for new entries */
17351e66a47SVivek Prakash 	buf->bufpos = 0;
17451e66a47SVivek Prakash 
17551e66a47SVivek Prakash 	if (isspace((unsigned char)*buf->buf))
17651e66a47SVivek Prakash 		return 0;
17751e66a47SVivek Prakash 
17851e66a47SVivek Prakash 	tic = _ti_compile(buf->buf, flags);
17951e66a47SVivek Prakash 	if (tic == NULL)
18051e66a47SVivek Prakash 		return 0;
18151e66a47SVivek Prakash 
18251e66a47SVivek Prakash 	if (find_term(tic->name) != NULL) {
18351e66a47SVivek Prakash 		dowarn("%s: duplicate entry", tic->name);
18451e66a47SVivek Prakash 		_ti_freetic(tic);
18551e66a47SVivek Prakash 		return 0;
18651e66a47SVivek Prakash 	}
18784d9c625SLionel Sambuc 	term = store_term(tic->name, NULL);
18851e66a47SVivek Prakash 	term->tic = tic;
18951e66a47SVivek Prakash 
19051e66a47SVivek Prakash 	/* Create aliased terms */
19151e66a47SVivek Prakash 	if (tic->alias != NULL) {
19286344bb5SKees Jongenburger 		alias = p = estrdup(tic->alias);
19351e66a47SVivek Prakash 		while (p != NULL && *p != '\0') {
19451e66a47SVivek Prakash 			e = strchr(p, '|');
19551e66a47SVivek Prakash 			if (e != NULL)
19651e66a47SVivek Prakash 				*e++ = '\0';
19751e66a47SVivek Prakash 			if (find_term(p) != NULL) {
19851e66a47SVivek Prakash 				dowarn("%s: has alias for already assigned"
19951e66a47SVivek Prakash 				    " term %s", tic->name, p);
20051e66a47SVivek Prakash 			} else {
20184d9c625SLionel Sambuc 				store_term(p, term);
20251e66a47SVivek Prakash 			}
20351e66a47SVivek Prakash 			p = e;
20451e66a47SVivek Prakash 		}
20586344bb5SKees Jongenburger 		free(alias);
20651e66a47SVivek Prakash 	}
20751e66a47SVivek Prakash 
20851e66a47SVivek Prakash 	return 0;
20951e66a47SVivek Prakash }
21051e66a47SVivek Prakash 
21151e66a47SVivek Prakash static void
merge(TIC * rtic,TIC * utic,int flags)21251e66a47SVivek Prakash merge(TIC *rtic, TIC *utic, int flags)
21351e66a47SVivek Prakash {
21451e66a47SVivek Prakash 	char *cap, flag, *code, type, *str;
21551e66a47SVivek Prakash 	short ind, num;
21651e66a47SVivek Prakash 	size_t n;
21751e66a47SVivek Prakash 
21851e66a47SVivek Prakash 	cap = utic->flags.buf;
21951e66a47SVivek Prakash 	for (n = utic->flags.entries; n > 0; n--) {
22051e66a47SVivek Prakash 		ind = le16dec(cap);
22151e66a47SVivek Prakash 		cap += sizeof(uint16_t);
22251e66a47SVivek Prakash 		flag = *cap++;
22351e66a47SVivek Prakash 		if (VALID_BOOLEAN(flag) &&
22451e66a47SVivek Prakash 		    _ti_find_cap(&rtic->flags, 'f', ind) == NULL)
22551e66a47SVivek Prakash 		{
22651e66a47SVivek Prakash 			_ti_grow_tbuf(&rtic->flags, sizeof(uint16_t) + 1);
22751e66a47SVivek Prakash 			le16enc(rtic->flags.buf + rtic->flags.bufpos, ind);
22851e66a47SVivek Prakash 			rtic->flags.bufpos += sizeof(uint16_t);
22951e66a47SVivek Prakash 			rtic->flags.buf[rtic->flags.bufpos++] = flag;
23051e66a47SVivek Prakash 			rtic->flags.entries++;
23151e66a47SVivek Prakash 		}
23251e66a47SVivek Prakash 	}
23351e66a47SVivek Prakash 
23451e66a47SVivek Prakash 	cap = utic->nums.buf;
23551e66a47SVivek Prakash 	for (n = utic->nums.entries; n > 0; n--) {
23651e66a47SVivek Prakash 		ind = le16dec(cap);
23751e66a47SVivek Prakash 		cap += sizeof(uint16_t);
23851e66a47SVivek Prakash 		num = le16dec(cap);
23951e66a47SVivek Prakash 		cap += sizeof(uint16_t);
24051e66a47SVivek Prakash 		if (VALID_NUMERIC(num) &&
24151e66a47SVivek Prakash 		    _ti_find_cap(&rtic->nums, 'n', ind) == NULL)
24251e66a47SVivek Prakash 		{
24351e66a47SVivek Prakash 			grow_tbuf(&rtic->nums, sizeof(uint16_t) * 2);
24451e66a47SVivek Prakash 			le16enc(rtic->nums.buf + rtic->nums.bufpos, ind);
24551e66a47SVivek Prakash 			rtic->nums.bufpos += sizeof(uint16_t);
24651e66a47SVivek Prakash 			le16enc(rtic->nums.buf + rtic->nums.bufpos, num);
24751e66a47SVivek Prakash 			rtic->nums.bufpos += sizeof(uint16_t);
24851e66a47SVivek Prakash 			rtic->nums.entries++;
24951e66a47SVivek Prakash 		}
25051e66a47SVivek Prakash 	}
25151e66a47SVivek Prakash 
25251e66a47SVivek Prakash 	cap = utic->strs.buf;
25351e66a47SVivek Prakash 	for (n = utic->strs.entries; n > 0; n--) {
25451e66a47SVivek Prakash 		ind = le16dec(cap);
25551e66a47SVivek Prakash 		cap += sizeof(uint16_t);
25651e66a47SVivek Prakash 		num = le16dec(cap);
25751e66a47SVivek Prakash 		cap += sizeof(uint16_t);
25851e66a47SVivek Prakash 		if (num > 0 &&
25951e66a47SVivek Prakash 		    _ti_find_cap(&rtic->strs, 's', ind) == NULL)
26051e66a47SVivek Prakash 		{
26151e66a47SVivek Prakash 			grow_tbuf(&rtic->strs, (sizeof(uint16_t) * 2) + num);
26251e66a47SVivek Prakash 			le16enc(rtic->strs.buf + rtic->strs.bufpos, ind);
26351e66a47SVivek Prakash 			rtic->strs.bufpos += sizeof(uint16_t);
26451e66a47SVivek Prakash 			le16enc(rtic->strs.buf + rtic->strs.bufpos, num);
26551e66a47SVivek Prakash 			rtic->strs.bufpos += sizeof(uint16_t);
26651e66a47SVivek Prakash 			memcpy(rtic->strs.buf + rtic->strs.bufpos,
26751e66a47SVivek Prakash 			    cap, num);
26851e66a47SVivek Prakash 			rtic->strs.bufpos += num;
26951e66a47SVivek Prakash 			rtic->strs.entries++;
27051e66a47SVivek Prakash 		}
27151e66a47SVivek Prakash 		cap += num;
27251e66a47SVivek Prakash 	}
27351e66a47SVivek Prakash 
27451e66a47SVivek Prakash 	cap = utic->extras.buf;
27551e66a47SVivek Prakash 	for (n = utic->extras.entries; n > 0; n--) {
27651e66a47SVivek Prakash 		num = le16dec(cap);
27751e66a47SVivek Prakash 		cap += sizeof(uint16_t);
27851e66a47SVivek Prakash 		code = cap;
27951e66a47SVivek Prakash 		cap += num;
28051e66a47SVivek Prakash 		type = *cap++;
28151e66a47SVivek Prakash 		flag = 0;
28251e66a47SVivek Prakash 		str = NULL;
28351e66a47SVivek Prakash 		switch (type) {
28451e66a47SVivek Prakash 		case 'f':
28551e66a47SVivek Prakash 			flag = *cap++;
28651e66a47SVivek Prakash 			if (!VALID_BOOLEAN(flag))
28751e66a47SVivek Prakash 				continue;
28851e66a47SVivek Prakash 			break;
28951e66a47SVivek Prakash 		case 'n':
29051e66a47SVivek Prakash 			num = le16dec(cap);
29151e66a47SVivek Prakash 			cap += sizeof(uint16_t);
29251e66a47SVivek Prakash 			if (!VALID_NUMERIC(num))
29351e66a47SVivek Prakash 				continue;
29451e66a47SVivek Prakash 			break;
29551e66a47SVivek Prakash 		case 's':
29651e66a47SVivek Prakash 			num = le16dec(cap);
29751e66a47SVivek Prakash 			cap += sizeof(uint16_t);
29851e66a47SVivek Prakash 			str = cap;
29951e66a47SVivek Prakash 			cap += num;
30051e66a47SVivek Prakash 			if (num == 0)
30151e66a47SVivek Prakash 				continue;
30251e66a47SVivek Prakash 			break;
30351e66a47SVivek Prakash 		}
30451e66a47SVivek Prakash 		_ti_store_extra(rtic, 0, code, type, flag, num, str, num,
30551e66a47SVivek Prakash 		    flags);
30651e66a47SVivek Prakash 	}
30751e66a47SVivek Prakash }
30851e66a47SVivek Prakash 
30951e66a47SVivek Prakash static size_t
merge_use(int flags)31051e66a47SVivek Prakash merge_use(int flags)
31151e66a47SVivek Prakash {
31251e66a47SVivek Prakash 	size_t skipped, merged, memn;
31351e66a47SVivek Prakash 	char *cap, *scap;
31451e66a47SVivek Prakash 	uint16_t num;
31551e66a47SVivek Prakash 	TIC *rtic, *utic;
31651e66a47SVivek Prakash 	TERM *term, *uterm;;
31751e66a47SVivek Prakash 
31851e66a47SVivek Prakash 	skipped = merged = 0;
31984d9c625SLionel Sambuc 	STAILQ_FOREACH(term, &terms, next) {
32084d9c625SLionel Sambuc 		if (term->base_term != NULL)
32151e66a47SVivek Prakash 			continue;
32251e66a47SVivek Prakash 		rtic = term->tic;
32351e66a47SVivek Prakash 		while ((cap = _ti_find_extra(&rtic->extras, "use")) != NULL) {
32451e66a47SVivek Prakash 			if (*cap++ != 's') {
32551e66a47SVivek Prakash 				dowarn("%s: use is not string", rtic->name);
32651e66a47SVivek Prakash 				break;
32751e66a47SVivek Prakash 			}
32851e66a47SVivek Prakash 			cap += sizeof(uint16_t);
32951e66a47SVivek Prakash 			if (strcmp(rtic->name, cap) == 0) {
33051e66a47SVivek Prakash 				dowarn("%s: uses itself", rtic->name);
33151e66a47SVivek Prakash 				goto remove;
33251e66a47SVivek Prakash 			}
33351e66a47SVivek Prakash 			uterm = find_term(cap);
33484d9c625SLionel Sambuc 			if (uterm != NULL && uterm->base_term != NULL)
33584d9c625SLionel Sambuc 				uterm = uterm->base_term;
33651e66a47SVivek Prakash 			if (uterm == NULL) {
33751e66a47SVivek Prakash 				dowarn("%s: no use record for %s",
33851e66a47SVivek Prakash 				    rtic->name, cap);
33951e66a47SVivek Prakash 				goto remove;
34051e66a47SVivek Prakash 			}
34151e66a47SVivek Prakash 			utic = uterm->tic;
34251e66a47SVivek Prakash 			if (strcmp(utic->name, rtic->name) == 0) {
34351e66a47SVivek Prakash 				dowarn("%s: uses itself", rtic->name);
34451e66a47SVivek Prakash 				goto remove;
34551e66a47SVivek Prakash 			}
34651e66a47SVivek Prakash 			if (_ti_find_extra(&utic->extras, "use") != NULL) {
34751e66a47SVivek Prakash 				skipped++;
34851e66a47SVivek Prakash 				break;
34951e66a47SVivek Prakash 			}
35051e66a47SVivek Prakash 			cap = _ti_find_extra(&rtic->extras, "use");
35151e66a47SVivek Prakash 			merge(rtic, utic, flags);
35251e66a47SVivek Prakash 	remove:
35351e66a47SVivek Prakash 			/* The pointers may have changed, find the use again */
35451e66a47SVivek Prakash 			cap = _ti_find_extra(&rtic->extras, "use");
35551e66a47SVivek Prakash 			if (cap == NULL)
35651e66a47SVivek Prakash 				dowarn("%s: use no longer exists - impossible",
35751e66a47SVivek Prakash 					rtic->name);
35851e66a47SVivek Prakash 			else {
35951e66a47SVivek Prakash 				scap = cap - (4 + sizeof(uint16_t));
36051e66a47SVivek Prakash 				cap++;
36151e66a47SVivek Prakash 				num = le16dec(cap);
36251e66a47SVivek Prakash 				cap += sizeof(uint16_t) + num;
36351e66a47SVivek Prakash 				memn = rtic->extras.bufpos -
36451e66a47SVivek Prakash 				    (cap - rtic->extras.buf);
36586344bb5SKees Jongenburger 				memmove(scap, cap, memn);
36651e66a47SVivek Prakash 				rtic->extras.bufpos -= cap - scap;
36751e66a47SVivek Prakash 				cap = scap;
36851e66a47SVivek Prakash 				rtic->extras.entries--;
36951e66a47SVivek Prakash 				merged++;
37051e66a47SVivek Prakash 			}
37151e66a47SVivek Prakash 		}
37251e66a47SVivek Prakash 	}
37351e66a47SVivek Prakash 
37451e66a47SVivek Prakash 	if (merged == 0 && skipped != 0)
37551e66a47SVivek Prakash 		dowarn("circular use detected");
37651e66a47SVivek Prakash 	return merged;
37751e66a47SVivek Prakash }
37851e66a47SVivek Prakash 
37951e66a47SVivek Prakash static int
print_dump(int argc,char ** argv)38051e66a47SVivek Prakash print_dump(int argc, char **argv)
38151e66a47SVivek Prakash {
38251e66a47SVivek Prakash 	TERM *term;
38351e66a47SVivek Prakash 	uint8_t *buf;
38451e66a47SVivek Prakash 	int i, n;
38551e66a47SVivek Prakash 	size_t j, col;
38651e66a47SVivek Prakash 	ssize_t len;
38751e66a47SVivek Prakash 
38851e66a47SVivek Prakash 	printf("struct compiled_term {\n");
38951e66a47SVivek Prakash 	printf("\tconst char *name;\n");
39051e66a47SVivek Prakash 	printf("\tconst char *cap;\n");
39151e66a47SVivek Prakash 	printf("\tsize_t caplen;\n");
39251e66a47SVivek Prakash 	printf("};\n\n");
39351e66a47SVivek Prakash 
39451e66a47SVivek Prakash 	printf("const struct compiled_term compiled_terms[] = {\n");
39551e66a47SVivek Prakash 
39651e66a47SVivek Prakash 	n = 0;
39751e66a47SVivek Prakash 	for (i = 0; i < argc; i++) {
39851e66a47SVivek Prakash 		term = find_term(argv[i]);
39951e66a47SVivek Prakash 		if (term == NULL) {
40051e66a47SVivek Prakash 			warnx("%s: no description for terminal", argv[i]);
40151e66a47SVivek Prakash 			continue;
40251e66a47SVivek Prakash 		}
40384d9c625SLionel Sambuc 		if (term->base_term != NULL) {
40451e66a47SVivek Prakash 			warnx("%s: cannot dump alias", argv[i]);
40551e66a47SVivek Prakash 			continue;
40651e66a47SVivek Prakash 		}
40751e66a47SVivek Prakash 		/* Don't compile the aliases in, save space */
40851e66a47SVivek Prakash 		free(term->tic->alias);
40951e66a47SVivek Prakash 		term->tic->alias = NULL;
41051e66a47SVivek Prakash 		len = _ti_flatten(&buf, term->tic);
41151e66a47SVivek Prakash 		if (len == 0 || len == -1)
41251e66a47SVivek Prakash 			continue;
41351e66a47SVivek Prakash 
41451e66a47SVivek Prakash 		printf("\t{\n");
41551e66a47SVivek Prakash 		printf("\t\t\"%s\",\n", argv[i]);
41651e66a47SVivek Prakash 		n++;
41751e66a47SVivek Prakash 		for (j = 0, col = 0; j < (size_t)len; j++) {
41851e66a47SVivek Prakash 			if (col == 0) {
41951e66a47SVivek Prakash 				printf("\t\t\"");
42051e66a47SVivek Prakash 				col = 16;
42151e66a47SVivek Prakash 			}
42251e66a47SVivek Prakash 
42351e66a47SVivek Prakash 			col += printf("\\%03o", (uint8_t)buf[j]);
42451e66a47SVivek Prakash 			if (col > 75) {
42551e66a47SVivek Prakash 				printf("\"%s\n",
42651e66a47SVivek Prakash 				    j + 1 == (size_t)len ? "," : "");
42751e66a47SVivek Prakash 				col = 0;
42851e66a47SVivek Prakash 			}
42951e66a47SVivek Prakash 		}
43051e66a47SVivek Prakash 		if (col != 0)
43151e66a47SVivek Prakash 			printf("\",\n");
432*0a6a1f1dSLionel Sambuc #if defined(__minix)
4335ae1a533SBen Gras 		printf("\t\t%zu\n", (size_t) len);
4345ae1a533SBen Gras #else
43551e66a47SVivek Prakash 		printf("\t\t%zu\n", len);
436*0a6a1f1dSLionel Sambuc #endif /* defined(__minix) */
43751e66a47SVivek Prakash 		printf("\t}");
43851e66a47SVivek Prakash 		if (i + 1 < argc)
43951e66a47SVivek Prakash 			printf(",");
44051e66a47SVivek Prakash 		printf("\n");
44151e66a47SVivek Prakash 		free(buf);
44251e66a47SVivek Prakash 	}
44351e66a47SVivek Prakash 	printf("};\n");
44451e66a47SVivek Prakash 
44551e66a47SVivek Prakash 	return n;
44651e66a47SVivek Prakash }
44751e66a47SVivek Prakash 
44884d9c625SLionel Sambuc static void
write_database(const char * dbname)44984d9c625SLionel Sambuc write_database(const char *dbname)
45084d9c625SLionel Sambuc {
45184d9c625SLionel Sambuc 	struct cdbw *db;
45284d9c625SLionel Sambuc 	char *tmp_dbname;
45384d9c625SLionel Sambuc 	TERM *term;
45484d9c625SLionel Sambuc 	int fd;
45584d9c625SLionel Sambuc 
45684d9c625SLionel Sambuc 	db = cdbw_open();
45784d9c625SLionel Sambuc 	if (db == NULL)
45884d9c625SLionel Sambuc 		err(1, "cdbw_open failed");
45984d9c625SLionel Sambuc 	/* Save the terms */
46084d9c625SLionel Sambuc 	STAILQ_FOREACH(term, &terms, next)
46184d9c625SLionel Sambuc 		save_term(db, term);
46284d9c625SLionel Sambuc 
46384d9c625SLionel Sambuc 	easprintf(&tmp_dbname, "%s.XXXXXX", dbname);
46484d9c625SLionel Sambuc 	fd = mkstemp(tmp_dbname);
46584d9c625SLionel Sambuc 	if (fd == -1)
46684d9c625SLionel Sambuc 		err(1, "creating temporary database %s failed", tmp_dbname);
46784d9c625SLionel Sambuc 	if (cdbw_output(db, fd, "NetBSD terminfo", cdbw_stable_seeder))
46884d9c625SLionel Sambuc 		err(1, "writing temporary database %s failed", tmp_dbname);
46984d9c625SLionel Sambuc 	if (fchmod(fd, DEFFILEMODE))
47084d9c625SLionel Sambuc 		err(1, "fchmod failed");
47184d9c625SLionel Sambuc 	if (close(fd))
47284d9c625SLionel Sambuc 		err(1, "writing temporary database %s failed", tmp_dbname);
47384d9c625SLionel Sambuc 	if (rename(tmp_dbname, dbname))
47484d9c625SLionel Sambuc 		err(1, "renaming %s to %s failed", tmp_dbname, dbname);
47584d9c625SLionel Sambuc 	free(tmp_dbname);
47684d9c625SLionel Sambuc 	cdbw_close(db);
47784d9c625SLionel Sambuc }
47884d9c625SLionel Sambuc 
47951e66a47SVivek Prakash int
main(int argc,char ** argv)48051e66a47SVivek Prakash main(int argc, char **argv)
48151e66a47SVivek Prakash {
48251e66a47SVivek Prakash 	int ch, cflag, sflag, flags;
48384d9c625SLionel Sambuc 	char *source, *dbname, *buf, *ofile;
48451e66a47SVivek Prakash 	FILE *f;
48586344bb5SKees Jongenburger 	size_t buflen;
48686344bb5SKees Jongenburger 	ssize_t len;
48751e66a47SVivek Prakash 	TBUF tbuf;
48851e66a47SVivek Prakash 
48951e66a47SVivek Prakash 	cflag = sflag = 0;
49051e66a47SVivek Prakash 	ofile = NULL;
49151e66a47SVivek Prakash 	flags = TIC_ALIAS | TIC_DESCRIPTION | TIC_WARNING;
49251e66a47SVivek Prakash 	while ((ch = getopt(argc, argv, "Saco:sx")) != -1)
49351e66a47SVivek Prakash 	    switch (ch) {
49451e66a47SVivek Prakash 	    case 'S':
49551e66a47SVivek Prakash 		    Sflag = 1;
49651e66a47SVivek Prakash 		    /* We still compile aliases so that use= works.
49751e66a47SVivek Prakash 		     * However, it's removed before we flatten to save space. */
49851e66a47SVivek Prakash 		    flags &= ~TIC_DESCRIPTION;
49951e66a47SVivek Prakash 		    break;
50051e66a47SVivek Prakash 	    case 'a':
50151e66a47SVivek Prakash 		    flags |= TIC_COMMENT;
50251e66a47SVivek Prakash 		    break;
50351e66a47SVivek Prakash 	    case 'c':
50451e66a47SVivek Prakash 		    cflag = 1;
50551e66a47SVivek Prakash 		    break;
50651e66a47SVivek Prakash 	    case 'o':
50751e66a47SVivek Prakash 		    ofile = optarg;
50851e66a47SVivek Prakash 		    break;
50951e66a47SVivek Prakash 	    case 's':
51051e66a47SVivek Prakash 		    sflag = 1;
51151e66a47SVivek Prakash 		    break;
51251e66a47SVivek Prakash 	    case 'x':
51351e66a47SVivek Prakash 		    flags |= TIC_EXTRA;
51451e66a47SVivek Prakash 		    break;
51551e66a47SVivek Prakash 	    case '?': /* FALLTHROUGH */
51651e66a47SVivek Prakash 	    default:
51751e66a47SVivek Prakash 		    fprintf(stderr, "usage: %s [-acSsx] [-o file] source\n",
51851e66a47SVivek Prakash 			getprogname());
51951e66a47SVivek Prakash 		    return EXIT_FAILURE;
52051e66a47SVivek Prakash 	    }
52151e66a47SVivek Prakash 
52251e66a47SVivek Prakash 	if (optind == argc)
52351e66a47SVivek Prakash 		errx(1, "No source file given");
52451e66a47SVivek Prakash 	source = argv[optind++];
52551e66a47SVivek Prakash 	f = fopen(source, "r");
52651e66a47SVivek Prakash 	if (f == NULL)
52751e66a47SVivek Prakash 		err(1, "fopen: %s", source);
52851e66a47SVivek Prakash 
52986344bb5SKees Jongenburger 	hcreate(HASH_SIZE);
53086344bb5SKees Jongenburger 
53186344bb5SKees Jongenburger 	buf = tbuf.buf = NULL;
53286344bb5SKees Jongenburger 	buflen = tbuf.buflen = tbuf.bufpos = 0;
53386344bb5SKees Jongenburger 	while ((len = getline(&buf, &buflen, f)) != -1) {
53451e66a47SVivek Prakash 		/* Skip comments */
53551e66a47SVivek Prakash 		if (*buf == '#')
53651e66a47SVivek Prakash 			continue;
53786344bb5SKees Jongenburger 		if (buf[len - 1] != '\n') {
53851e66a47SVivek Prakash 			process_entry(&tbuf, flags);
53951e66a47SVivek Prakash 			dowarn("last line is not a comment"
54051e66a47SVivek Prakash 			    " and does not end with a newline");
54151e66a47SVivek Prakash 			continue;
54251e66a47SVivek Prakash 		}
54351e66a47SVivek Prakash 		/*
54451e66a47SVivek Prakash 		  If the first char is space not a space then we have a
54551e66a47SVivek Prakash 		  new entry, so process it.
54651e66a47SVivek Prakash 		*/
54751e66a47SVivek Prakash 		if (!isspace((unsigned char)*buf) && tbuf.bufpos != 0)
54851e66a47SVivek Prakash 			process_entry(&tbuf, flags);
54951e66a47SVivek Prakash 
55051e66a47SVivek Prakash 		/* Grow the buffer if needed */
55186344bb5SKees Jongenburger 		grow_tbuf(&tbuf, len);
55251e66a47SVivek Prakash 		/* Append the string */
55386344bb5SKees Jongenburger 		memcpy(tbuf.buf + tbuf.bufpos, buf, len);
55486344bb5SKees Jongenburger 		tbuf.bufpos += len;
55551e66a47SVivek Prakash 	}
55686344bb5SKees Jongenburger 	free(buf);
55751e66a47SVivek Prakash 	/* Process the last entry if not done already */
55851e66a47SVivek Prakash 	process_entry(&tbuf, flags);
55986344bb5SKees Jongenburger 	free(tbuf.buf);
56051e66a47SVivek Prakash 
56151e66a47SVivek Prakash 	/* Merge use entries until we have merged all we can */
56251e66a47SVivek Prakash 	while (merge_use(flags) != 0)
56351e66a47SVivek Prakash 		;
56451e66a47SVivek Prakash 
56551e66a47SVivek Prakash 	if (Sflag) {
56651e66a47SVivek Prakash 		print_dump(argc - optind, argv + optind);
56751e66a47SVivek Prakash 		return error_exit;
56851e66a47SVivek Prakash 	}
56951e66a47SVivek Prakash 
57051e66a47SVivek Prakash 	if (cflag)
57151e66a47SVivek Prakash 		return error_exit;
57251e66a47SVivek Prakash 
57384d9c625SLionel Sambuc 	if (ofile == NULL)
57484d9c625SLionel Sambuc 		easprintf(&dbname, "%s.cdb", source);
57584d9c625SLionel Sambuc 	else
57684d9c625SLionel Sambuc 		dbname = ofile;
57784d9c625SLionel Sambuc 	write_database(dbname);
57851e66a47SVivek Prakash 
57951e66a47SVivek Prakash 	if (sflag != 0)
58051e66a47SVivek Prakash 		fprintf(stderr, "%zu entries and %zu aliases written to %s\n",
58184d9c625SLionel Sambuc 		    nterm, nalias, dbname);
58251e66a47SVivek Prakash 
58386344bb5SKees Jongenburger #ifdef __VALGRIND__
58484d9c625SLionel Sambuc 	if (ofile == NULL)
58584d9c625SLionel Sambuc 		free(dbname);
58684d9c625SLionel Sambuc 	while ((term = STAILQ_FIRST(&terms)) != NULL) {
58784d9c625SLionel Sambuc 		STAILQ_REMOVE_HEAD(&terms, next);
58886344bb5SKees Jongenburger 		_ti_freetic(term->tic);
58986344bb5SKees Jongenburger 		free(term->name);
59086344bb5SKees Jongenburger 		free(term);
59186344bb5SKees Jongenburger 	}
592*0a6a1f1dSLionel Sambuc 	hdestroy1(free, NULL);
59386344bb5SKees Jongenburger #endif
59486344bb5SKees Jongenburger 
59586344bb5SKees Jongenburger 
59651e66a47SVivek Prakash 	return EXIT_SUCCESS;
59751e66a47SVivek Prakash }
598