Home | History | Annotate | Line # | Download | only in tic
tic.c revision 1.31.6.1
      1  1.31.6.1    martin /* $NetBSD: tic.c,v 1.31.6.1 2024/10/14 16:29:22 martin 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.31.6.1    martin __RCSID("$NetBSD: tic.c,v 1.31.6.1 2024/10/14 16:29:22 martin Exp $");
     36       1.1       roy 
     37       1.1       roy #include <sys/types.h>
     38      1.14     joerg #include <sys/queue.h>
     39      1.27  christos #include <sys/stat.h>
     40       1.8  pgoyette 
     41       1.9  pgoyette #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
     42       1.7  pgoyette #include <sys/endian.h>
     43       1.8  pgoyette #endif
     44       1.1       roy 
     45      1.20     joerg #include <cdbw.h>
     46       1.1       roy #include <ctype.h>
     47       1.1       roy #include <err.h>
     48       1.1       roy #include <errno.h>
     49       1.1       roy #include <getopt.h>
     50       1.1       roy #include <limits.h>
     51       1.1       roy #include <fcntl.h>
     52      1.15     joerg #include <search.h>
     53       1.1       roy #include <stdarg.h>
     54       1.1       roy #include <stdlib.h>
     55       1.1       roy #include <stdio.h>
     56       1.1       roy #include <string.h>
     57       1.1       roy #include <term_private.h>
     58       1.1       roy #include <term.h>
     59      1.31     joerg #include <unistd.h>
     60      1.23     joerg #include <util.h>
     61      1.15     joerg 
     62      1.15     joerg #define	HASH_SIZE	16384	/* 2012-06-01: 3600 entries */
     63       1.1       roy 
     64       1.1       roy typedef struct term {
     65      1.20     joerg 	STAILQ_ENTRY(term) next;
     66       1.1       roy 	char *name;
     67      1.10       roy 	TIC *tic;
     68      1.20     joerg 	uint32_t id;
     69      1.20     joerg 	struct term *base_term;
     70       1.1       roy } TERM;
     71      1.20     joerg static STAILQ_HEAD(, term) terms = STAILQ_HEAD_INITIALIZER(terms);
     72       1.1       roy 
     73       1.1       roy static int error_exit;
     74      1.10       roy static int Sflag;
     75      1.18     joerg static size_t nterm, nalias;
     76       1.1       roy 
     77      1.13     joerg static void __printflike(1, 2)
     78       1.1       roy dowarn(const char *fmt, ...)
     79       1.1       roy {
     80       1.1       roy 	va_list va;
     81       1.1       roy 
     82       1.1       roy 	error_exit = 1;
     83       1.1       roy 	va_start(va, fmt);
     84       1.1       roy 	vwarnx(fmt, va);
     85       1.1       roy 	va_end(va);
     86       1.1       roy }
     87       1.1       roy 
     88       1.1       roy static char *
     89       1.1       roy grow_tbuf(TBUF *tbuf, size_t len)
     90       1.1       roy {
     91       1.1       roy 	char *buf;
     92       1.1       roy 
     93      1.10       roy 	buf = _ti_grow_tbuf(tbuf, len);
     94      1.10       roy 	if (buf == NULL)
     95      1.10       roy 		err(1, "_ti_grow_tbuf");
     96      1.10       roy 	return buf;
     97       1.5       roy }
     98       1.5       roy 
     99       1.5       roy static int
    100      1.20     joerg save_term(struct cdbw *db, TERM *term)
    101       1.5       roy {
    102      1.10       roy 	uint8_t *buf;
    103      1.10       roy 	ssize_t len;
    104      1.20     joerg 	size_t slen = strlen(term->name) + 1;
    105      1.20     joerg 
    106      1.20     joerg 	if (term->base_term != NULL) {
    107      1.20     joerg 		len = (ssize_t)slen + 7;
    108      1.20     joerg 		buf = emalloc(len);
    109      1.20     joerg 		buf[0] = 2;
    110      1.20     joerg 		le32enc(buf + 1, term->base_term->id);
    111      1.20     joerg 		le16enc(buf + 5, slen);
    112      1.20     joerg 		memcpy(buf + 7, term->name, slen);
    113      1.20     joerg 		if (cdbw_put(db, term->name, slen, buf, len))
    114      1.20     joerg 			err(1, "cdbw_put");
    115      1.26  christos 		free(buf);
    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.25       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.25       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.25       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.31.6.1    martin 	mode_t m;
    455      1.20     joerg 
    456      1.20     joerg 	db = cdbw_open();
    457      1.20     joerg 	if (db == NULL)
    458      1.20     joerg 		err(1, "cdbw_open failed");
    459      1.20     joerg 	/* Save the terms */
    460      1.20     joerg 	STAILQ_FOREACH(term, &terms, next)
    461      1.20     joerg 		save_term(db, term);
    462      1.20     joerg 
    463      1.20     joerg 	easprintf(&tmp_dbname, "%s.XXXXXX", dbname);
    464      1.20     joerg 	fd = mkstemp(tmp_dbname);
    465      1.20     joerg 	if (fd == -1)
    466      1.20     joerg 		err(1, "creating temporary database %s failed", tmp_dbname);
    467      1.20     joerg 	if (cdbw_output(db, fd, "NetBSD terminfo", cdbw_stable_seeder))
    468      1.20     joerg 		err(1, "writing temporary database %s failed", tmp_dbname);
    469  1.31.6.1    martin 	m = umask(0);
    470  1.31.6.1    martin 	(void)umask(m);
    471  1.31.6.1    martin 	if (fchmod(fd, DEFFILEMODE & ~m))
    472      1.20     joerg 		err(1, "fchmod failed");
    473      1.20     joerg 	if (close(fd))
    474      1.20     joerg 		err(1, "writing temporary database %s failed", tmp_dbname);
    475      1.20     joerg 	if (rename(tmp_dbname, dbname))
    476      1.20     joerg 		err(1, "renaming %s to %s failed", tmp_dbname, dbname);
    477      1.20     joerg 	free(tmp_dbname);
    478      1.20     joerg 	cdbw_close(db);
    479      1.20     joerg }
    480      1.20     joerg 
    481       1.1       roy int
    482       1.1       roy main(int argc, char **argv)
    483       1.1       roy {
    484      1.10       roy 	int ch, cflag, sflag, flags;
    485      1.20     joerg 	char *source, *dbname, *buf, *ofile;
    486       1.1       roy 	FILE *f;
    487      1.18     joerg 	size_t buflen;
    488      1.12       roy 	ssize_t len;
    489       1.1       roy 	TBUF tbuf;
    490      1.29       roy 	struct term *term;
    491       1.1       roy 
    492       1.1       roy 	cflag = sflag = 0;
    493       1.1       roy 	ofile = NULL;
    494      1.10       roy 	flags = TIC_ALIAS | TIC_DESCRIPTION | TIC_WARNING;
    495       1.5       roy 	while ((ch = getopt(argc, argv, "Saco:sx")) != -1)
    496       1.1       roy 	    switch (ch) {
    497       1.5       roy 	    case 'S':
    498       1.5       roy 		    Sflag = 1;
    499      1.10       roy 		    /* We still compile aliases so that use= works.
    500      1.10       roy 		     * However, it's removed before we flatten to save space. */
    501      1.10       roy 		    flags &= ~TIC_DESCRIPTION;
    502       1.5       roy 		    break;
    503       1.1       roy 	    case 'a':
    504      1.10       roy 		    flags |= TIC_COMMENT;
    505       1.1       roy 		    break;
    506       1.1       roy 	    case 'c':
    507       1.4       roy 		    cflag = 1;
    508       1.1       roy 		    break;
    509       1.1       roy 	    case 'o':
    510       1.1       roy 		    ofile = optarg;
    511       1.1       roy 		    break;
    512       1.1       roy 	    case 's':
    513       1.4       roy 		    sflag = 1;
    514       1.1       roy 		    break;
    515       1.1       roy 	    case 'x':
    516      1.10       roy 		    flags |= TIC_EXTRA;
    517       1.1       roy 		    break;
    518       1.1       roy 	    case '?': /* FALLTHROUGH */
    519       1.1       roy 	    default:
    520       1.6       roy 		    fprintf(stderr, "usage: %s [-acSsx] [-o file] source\n",
    521       1.1       roy 			getprogname());
    522       1.1       roy 		    return EXIT_FAILURE;
    523       1.1       roy 	    }
    524       1.1       roy 
    525       1.1       roy 	if (optind == argc)
    526       1.1       roy 		errx(1, "No source file given");
    527       1.1       roy 	source = argv[optind++];
    528       1.1       roy 	f = fopen(source, "r");
    529       1.1       roy 	if (f == NULL)
    530       1.1       roy 		err(1, "fopen: %s", source);
    531       1.1       roy 
    532      1.15     joerg 	hcreate(HASH_SIZE);
    533      1.15     joerg 
    534      1.19     joerg 	buf = tbuf.buf = NULL;
    535      1.28       roy 	buflen = tbuf.buflen = tbuf.bufpos = 0;
    536      1.12       roy 	while ((len = getline(&buf, &buflen, f)) != -1) {
    537       1.1       roy 		/* Skip comments */
    538       1.1       roy 		if (*buf == '#')
    539       1.1       roy 			continue;
    540      1.12       roy 		if (buf[len - 1] != '\n') {
    541      1.10       roy 			process_entry(&tbuf, flags);
    542       1.1       roy 			dowarn("last line is not a comment"
    543       1.1       roy 			    " and does not end with a newline");
    544       1.1       roy 			continue;
    545       1.1       roy 		}
    546       1.1       roy 		/*
    547      1.28       roy 		 * If the first char is space not a space then we have a
    548      1.28       roy 		 * new entry, so process it.
    549      1.28       roy 		 */
    550       1.1       roy 		if (!isspace((unsigned char)*buf) && tbuf.bufpos != 0)
    551      1.10       roy 			process_entry(&tbuf, flags);
    552      1.25       roy 
    553       1.1       roy 		/* Grow the buffer if needed */
    554      1.12       roy 		grow_tbuf(&tbuf, len);
    555       1.1       roy 		/* Append the string */
    556      1.12       roy 		memcpy(tbuf.buf + tbuf.bufpos, buf, len);
    557      1.12       roy 		tbuf.bufpos += len;
    558       1.1       roy 	}
    559      1.19     joerg 	free(buf);
    560       1.1       roy 	/* Process the last entry if not done already */
    561      1.10       roy 	process_entry(&tbuf, flags);
    562      1.19     joerg 	free(tbuf.buf);
    563       1.1       roy 
    564       1.1       roy 	/* Merge use entries until we have merged all we can */
    565      1.10       roy 	while (merge_use(flags) != 0)
    566       1.1       roy 		;
    567       1.1       roy 
    568       1.6       roy 	if (Sflag) {
    569       1.5       roy 		print_dump(argc - optind, argv + optind);
    570       1.5       roy 		return error_exit;
    571       1.5       roy 	}
    572       1.5       roy 
    573       1.6       roy 	if (cflag)
    574       1.1       roy 		return error_exit;
    575      1.18     joerg 
    576      1.20     joerg 	if (ofile == NULL)
    577      1.20     joerg 		easprintf(&dbname, "%s.cdb", source);
    578      1.20     joerg 	else
    579      1.20     joerg 		dbname = ofile;
    580      1.20     joerg 	write_database(dbname);
    581       1.1       roy 
    582       1.1       roy 	if (sflag != 0)
    583       1.1       roy 		fprintf(stderr, "%zu entries and %zu aliases written to %s\n",
    584      1.20     joerg 		    nterm, nalias, dbname);
    585      1.19     joerg 
    586      1.20     joerg 	if (ofile == NULL)
    587      1.20     joerg 		free(dbname);
    588      1.20     joerg 	while ((term = STAILQ_FIRST(&terms)) != NULL) {
    589      1.20     joerg 		STAILQ_REMOVE_HEAD(&terms, next);
    590      1.19     joerg 		_ti_freetic(term->tic);
    591      1.19     joerg 		free(term->name);
    592      1.19     joerg 		free(term);
    593      1.19     joerg 	}
    594      1.30  christos #ifndef HAVE_NBTOOL_CONFIG_H
    595      1.30  christos 	/*
    596      1.30  christos 	 * hdestroy1 is not standard but we don't really care if we
    597      1.30  christos 	 * leak in the tools version
    598      1.30  christos 	 */
    599      1.24  christos 	hdestroy1(free, NULL);
    600      1.30  christos #endif
    601       1.1       roy 
    602       1.1       roy 	return EXIT_SUCCESS;
    603       1.1       roy }
    604