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