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