Home | History | Annotate | Line # | Download | only in tic
tic.c revision 1.5
      1  1.5  roy /* $NetBSD: tic.c,v 1.5 2010/02/11 00:24:46 roy 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.5  roy __RCSID("$NetBSD: tic.c,v 1.5 2010/02/11 00:24:46 roy Exp $");
     36  1.1  roy 
     37  1.1  roy #include <sys/types.h>
     38  1.1  roy 
     39  1.1  roy #include <ctype.h>
     40  1.1  roy #include <err.h>
     41  1.1  roy #include <errno.h>
     42  1.1  roy #include <getopt.h>
     43  1.1  roy #include <limits.h>
     44  1.1  roy #include <fcntl.h>
     45  1.1  roy #include <ndbm.h>
     46  1.1  roy #include <stdarg.h>
     47  1.1  roy #include <stdlib.h>
     48  1.1  roy #include <stdio.h>
     49  1.1  roy #include <string.h>
     50  1.1  roy #include <term_private.h>
     51  1.1  roy #include <term.h>
     52  1.1  roy 
     53  1.1  roy #define UINT16_T_MAX 0xffff
     54  1.1  roy 
     55  1.1  roy typedef struct tbuf {
     56  1.1  roy 	char *buf;
     57  1.1  roy 	size_t buflen;
     58  1.1  roy 	size_t bufpos;
     59  1.1  roy 	size_t entries;
     60  1.1  roy } TBUF;
     61  1.1  roy 
     62  1.1  roy typedef struct tic {
     63  1.1  roy 	char *name;
     64  1.2  roy 	char *alias;
     65  1.1  roy 	char *desc;
     66  1.1  roy 	TBUF flags;
     67  1.1  roy 	TBUF nums;
     68  1.1  roy 	TBUF strs;
     69  1.1  roy 	TBUF extras;
     70  1.1  roy } TIC;
     71  1.1  roy 
     72  1.1  roy /* We store the full list of terminals we have instead of iterating
     73  1.1  roy    through the database as the sequential iterator doesn't work
     74  1.1  roy    the the data size stored changes N amount which ours will. */
     75  1.1  roy typedef struct term {
     76  1.1  roy 	struct term *next;
     77  1.1  roy 	char *name;
     78  1.1  roy 	char type;
     79  1.1  roy 	TIC tic;
     80  1.1  roy } TERM;
     81  1.1  roy static TERM *terms;
     82  1.1  roy 
     83  1.1  roy static int error_exit;
     84  1.1  roy static int aflag, xflag;
     85  1.1  roy static char *dbname;
     86  1.1  roy 
     87  1.1  roy static TBUF scratch;
     88  1.1  roy 
     89  1.1  roy static void
     90  1.1  roy do_unlink(void)
     91  1.1  roy {
     92  1.1  roy 
     93  1.1  roy 	if (dbname != NULL)
     94  1.1  roy 		unlink(dbname);
     95  1.1  roy }
     96  1.1  roy 
     97  1.1  roy static void __attribute__((__format__(__printf__, 1, 2)))
     98  1.1  roy dowarn(const char *fmt, ...)
     99  1.1  roy {
    100  1.1  roy 	va_list va;
    101  1.1  roy 
    102  1.1  roy 	error_exit = 1;
    103  1.1  roy 	va_start(va, fmt);
    104  1.1  roy 	vwarnx(fmt, va);
    105  1.1  roy 	va_end(va);
    106  1.1  roy }
    107  1.1  roy 
    108  1.1  roy static char *
    109  1.1  roy grow_tbuf(TBUF *tbuf, size_t len)
    110  1.1  roy {
    111  1.1  roy 	char *buf;
    112  1.1  roy 	size_t l;
    113  1.1  roy 
    114  1.1  roy 	l = tbuf->bufpos + len;
    115  1.1  roy 	if (l > tbuf->buflen) {
    116  1.1  roy 		if (tbuf->bufpos == 0) {
    117  1.1  roy 			buf = malloc(l);
    118  1.1  roy 			if (buf == NULL)
    119  1.1  roy 				err(1, "malloc (%zu bytes)", l);
    120  1.1  roy 		} else {
    121  1.1  roy 			buf = realloc(tbuf->buf, l);
    122  1.1  roy 			if (buf == NULL)
    123  1.1  roy 				err(1, "realloc (%zu bytes)", l);
    124  1.1  roy 		}
    125  1.1  roy 		tbuf->buf = buf;
    126  1.1  roy 		tbuf->buflen = l;
    127  1.1  roy 	}
    128  1.1  roy 	return tbuf->buf;
    129  1.1  roy }
    130  1.1  roy 
    131  1.1  roy static char *
    132  1.1  roy find_cap(TBUF *tbuf, char type, short ind)
    133  1.1  roy {
    134  1.1  roy 	size_t n;
    135  1.1  roy 	short num;
    136  1.1  roy 	char *cap;
    137  1.1  roy 
    138  1.1  roy 	cap = tbuf->buf;
    139  1.1  roy 	for (n = tbuf->entries; n > 0; n--) {
    140  1.1  roy 		num = le16dec(cap);
    141  1.1  roy 		cap += sizeof(uint16_t);
    142  1.1  roy 		if (num == ind)
    143  1.1  roy 			return cap;
    144  1.1  roy 		switch (type) {
    145  1.1  roy 		case 'f':
    146  1.1  roy 			cap++;
    147  1.1  roy 			break;
    148  1.1  roy 		case 'n':
    149  1.1  roy 			cap += sizeof(uint16_t);
    150  1.1  roy 			break;
    151  1.1  roy 		case 's':
    152  1.1  roy 			num = le16dec(cap);
    153  1.1  roy 			cap += sizeof(uint16_t);
    154  1.1  roy 			cap += num;
    155  1.1  roy 			break;
    156  1.1  roy 		}
    157  1.1  roy 	}
    158  1.1  roy 	return NULL;
    159  1.1  roy }
    160  1.1  roy 
    161  1.1  roy static char *
    162  1.1  roy find_extra(TBUF *tbuf, const char *code)
    163  1.1  roy {
    164  1.1  roy 	size_t n;
    165  1.1  roy 	short num;
    166  1.1  roy 	char *cap;
    167  1.1  roy 
    168  1.1  roy 	cap = tbuf->buf;
    169  1.1  roy 	for (n = tbuf->entries; n > 0; n--) {
    170  1.1  roy 		num = le16dec(cap);
    171  1.1  roy 		cap += sizeof(uint16_t);
    172  1.1  roy 		if (strcmp(cap, code) == 0)
    173  1.1  roy 			return cap + num;
    174  1.1  roy 		cap += num;
    175  1.1  roy 		switch (*cap++) {
    176  1.1  roy 		case 'f':
    177  1.1  roy 			cap++;
    178  1.1  roy 			break;
    179  1.1  roy 		case 'n':
    180  1.1  roy 			cap += sizeof(uint16_t);
    181  1.1  roy 			break;
    182  1.1  roy 		case 's':
    183  1.1  roy 			num = le16dec(cap);
    184  1.1  roy 			cap += sizeof(uint16_t);
    185  1.1  roy 			cap += num;
    186  1.1  roy 			break;
    187  1.1  roy 		}
    188  1.1  roy 	}
    189  1.1  roy 	return NULL;
    190  1.1  roy }
    191  1.1  roy 
    192  1.1  roy static size_t
    193  1.1  roy store_extra(TIC *tic, int wrn, char *id, char type, char flag, short num,
    194  1.1  roy     char *str, size_t strl)
    195  1.1  roy {
    196  1.1  roy 	size_t l;
    197  1.1  roy 
    198  1.1  roy 	if (strcmp(id, "use") != 0) {
    199  1.1  roy 		if (find_extra(&tic->extras, id) != NULL)
    200  1.1  roy 			return 0;
    201  1.1  roy 		if (xflag == 0) {
    202  1.1  roy 			if (wrn != 0)
    203  1.1  roy 				dowarn("%s: %s: unknown capability",
    204  1.1  roy 				    tic->name, id);
    205  1.1  roy 			return 0;
    206  1.1  roy 		}
    207  1.1  roy 	}
    208  1.1  roy 
    209  1.1  roy 	l = strlen(id) + 1;
    210  1.1  roy 	if (l > UINT16_T_MAX) {
    211  1.1  roy 		dowarn("%s: %s: cap name is too long", tic->name, id);
    212  1.1  roy 		return 0;
    213  1.1  roy 	}
    214  1.1  roy 
    215  1.1  roy 	grow_tbuf(&tic->extras, l + strl + (sizeof(uint16_t) * 2) + 1);
    216  1.1  roy 	le16enc(tic->extras.buf + tic->extras.bufpos, l);
    217  1.1  roy 	tic->extras.bufpos += sizeof(uint16_t);
    218  1.1  roy 	memcpy(tic->extras.buf + tic->extras.bufpos, id, l);
    219  1.1  roy 	tic->extras.bufpos += l;
    220  1.1  roy 	tic->extras.buf[tic->extras.bufpos++] = type;
    221  1.1  roy 	switch (type) {
    222  1.1  roy 	case 'f':
    223  1.1  roy 		tic->extras.buf[tic->extras.bufpos++] = flag;
    224  1.1  roy 		break;
    225  1.1  roy 	case 'n':
    226  1.1  roy 		le16enc(tic->extras.buf + tic->extras.bufpos, num);
    227  1.1  roy 		tic->extras.bufpos += sizeof(uint16_t);
    228  1.1  roy 		break;
    229  1.1  roy 	case 's':
    230  1.1  roy 		le16enc(tic->extras.buf + tic->extras.bufpos, strl);
    231  1.1  roy 		tic->extras.bufpos += sizeof(uint16_t);
    232  1.1  roy 		memcpy(tic->extras.buf + tic->extras.bufpos, str, strl);
    233  1.1  roy 		tic->extras.bufpos += strl;
    234  1.1  roy 		break;
    235  1.1  roy 	}
    236  1.1  roy 	tic->extras.entries++;
    237  1.1  roy 	return 1;
    238  1.1  roy }
    239  1.1  roy 
    240  1.5  roy static TBUF *
    241  1.5  roy flatten_term(TERM *term)
    242  1.1  roy {
    243  1.2  roy 	size_t buflen, len, alen, dlen;
    244  1.1  roy 	char *cap;
    245  1.1  roy 	TIC *tic;
    246  1.1  roy 
    247  1.1  roy 	scratch.bufpos = 0;
    248  1.1  roy 	tic = &term->tic;
    249  1.1  roy 	len = strlen(tic->name) + 1;
    250  1.2  roy 	if (tic->alias == NULL)
    251  1.2  roy 		alen = 0;
    252  1.2  roy 	else
    253  1.2  roy 		alen = strlen(tic->alias) + 1;
    254  1.1  roy 	if (tic->desc == NULL)
    255  1.1  roy 		dlen = 0;
    256  1.1  roy 	else
    257  1.1  roy 		dlen = strlen(tic->desc) + 1;
    258  1.1  roy 	buflen = sizeof(char) +
    259  1.1  roy 	    sizeof(uint16_t) + len +
    260  1.5  roy 	    sizeof(uint16_t) + alen +
    261  1.1  roy 	    sizeof(uint16_t) + dlen +
    262  1.1  roy 	    (sizeof(uint16_t) * 2) + tic->flags.bufpos +
    263  1.1  roy 	    (sizeof(uint16_t) * 2) + tic->nums.bufpos +
    264  1.1  roy 	    (sizeof(uint16_t) * 2) + tic->strs.bufpos +
    265  1.1  roy 	    (sizeof(uint16_t) * 2) + tic->extras.bufpos;
    266  1.1  roy 	grow_tbuf(&scratch, buflen);
    267  1.1  roy 	cap = scratch.buf;
    268  1.1  roy 	if (term->type == 'a')
    269  1.1  roy 		*cap++ = 0;
    270  1.1  roy 	else
    271  1.2  roy 		*cap++ = 2; /* version */
    272  1.1  roy 	le16enc(cap, len);
    273  1.1  roy 	cap += sizeof(uint16_t);
    274  1.1  roy 	memcpy(cap, tic->name, len);
    275  1.1  roy 	cap += len;
    276  1.1  roy 	if (term->type != 'a') {
    277  1.2  roy 		le16enc(cap, alen);
    278  1.2  roy 		cap += sizeof(uint16_t);
    279  1.2  roy 		if (tic->alias != NULL) {
    280  1.2  roy 			memcpy(cap, tic->alias, alen);
    281  1.2  roy 			cap += alen;
    282  1.2  roy 		}
    283  1.1  roy 		le16enc(cap, dlen);
    284  1.1  roy 		cap += sizeof(uint16_t);
    285  1.1  roy 		if (tic->desc != NULL) {
    286  1.1  roy 			memcpy(cap, tic->desc, dlen);
    287  1.1  roy 			cap += dlen;
    288  1.1  roy 		}
    289  1.1  roy 
    290  1.1  roy 		if (tic->flags.entries == 0) {
    291  1.1  roy 			le16enc(cap, 0);
    292  1.1  roy 			cap += sizeof(uint16_t);
    293  1.1  roy 		} else {
    294  1.1  roy 			le16enc(cap, (tic->flags.bufpos + sizeof(uint16_t)));
    295  1.1  roy 			cap += sizeof(uint16_t);
    296  1.1  roy 			le16enc(cap, tic->flags.entries);
    297  1.1  roy 			cap += sizeof(uint16_t);
    298  1.1  roy 			memcpy(cap, tic->flags.buf, tic->flags.bufpos);
    299  1.1  roy 			cap += tic->flags.bufpos;
    300  1.1  roy 		}
    301  1.1  roy 
    302  1.1  roy 		if (tic->nums.entries == 0) {
    303  1.1  roy 			le16enc(cap, 0);
    304  1.1  roy 			cap += sizeof(uint16_t);
    305  1.1  roy 		} else {
    306  1.1  roy 			le16enc(cap, (tic->nums.bufpos + sizeof(uint16_t)));
    307  1.1  roy 			cap += sizeof(uint16_t);
    308  1.1  roy 			le16enc(cap, tic->nums.entries);
    309  1.1  roy 			cap += sizeof(uint16_t);
    310  1.1  roy 			memcpy(cap, tic->nums.buf, tic->nums.bufpos);
    311  1.1  roy 			cap += tic->nums.bufpos;
    312  1.1  roy 		}
    313  1.1  roy 
    314  1.1  roy 		if (tic->strs.entries == 0) {
    315  1.1  roy 			le16enc(cap, 0);
    316  1.1  roy 			cap += sizeof(uint16_t);
    317  1.1  roy 		} else {
    318  1.1  roy 			le16enc(cap, (tic->strs.bufpos + sizeof(uint16_t)));
    319  1.1  roy 			cap += sizeof(uint16_t);
    320  1.1  roy 			le16enc(cap, tic->strs.entries);
    321  1.1  roy 			cap += sizeof(uint16_t);
    322  1.1  roy 			memcpy(cap, tic->strs.buf, tic->strs.bufpos);
    323  1.1  roy 			cap += tic->strs.bufpos;
    324  1.1  roy 		}
    325  1.1  roy 
    326  1.1  roy 		if (tic->extras.entries == 0) {
    327  1.1  roy 			le16enc(cap, 0);
    328  1.1  roy 			cap += sizeof(uint16_t);
    329  1.1  roy 		} else {
    330  1.1  roy 			le16enc(cap, (tic->extras.bufpos + sizeof(uint16_t)));
    331  1.1  roy 			cap += sizeof(uint16_t);
    332  1.1  roy 			le16enc(cap, tic->extras.entries);
    333  1.1  roy 			cap += sizeof(uint16_t);
    334  1.1  roy 			memcpy(cap, tic->extras.buf, tic->extras.bufpos);
    335  1.1  roy 			cap += tic->extras.bufpos;
    336  1.1  roy 		}
    337  1.1  roy 	}
    338  1.5  roy 	scratch.bufpos = cap - scratch.buf;
    339  1.5  roy 
    340  1.5  roy 	return &scratch;
    341  1.5  roy }
    342  1.5  roy 
    343  1.5  roy static int
    344  1.5  roy save_term(DBM *db, TERM *term)
    345  1.5  roy {
    346  1.5  roy 	TBUF *buf;
    347  1.5  roy 	datum key, value;
    348  1.5  roy 
    349  1.5  roy 	buf = flatten_term(term);
    350  1.5  roy 	if (buf == NULL)
    351  1.5  roy 		return -1;
    352  1.1  roy 
    353  1.1  roy 	key.dptr = term->name;
    354  1.1  roy 	key.dsize = strlen(term->name);
    355  1.1  roy 	value.dptr = scratch.buf;
    356  1.5  roy 	value.dsize = scratch.bufpos;
    357  1.1  roy 	if (dbm_store(db, key, value, DBM_REPLACE) == -1)
    358  1.1  roy 		err(1, "dbm_store");
    359  1.1  roy 	return 0;
    360  1.1  roy }
    361  1.1  roy 
    362  1.1  roy static TERM *
    363  1.1  roy find_term(const char *name)
    364  1.1  roy {
    365  1.1  roy 	TERM *term;
    366  1.1  roy 
    367  1.1  roy 	for (term = terms; term != NULL; term = term->next)
    368  1.1  roy 		if (strcmp(term->name, name) == 0)
    369  1.1  roy 			return term;
    370  1.1  roy 	return NULL;
    371  1.1  roy }
    372  1.1  roy 
    373  1.1  roy static TERM *
    374  1.1  roy store_term(const char *name, char type)
    375  1.1  roy {
    376  1.1  roy 	TERM *term;
    377  1.1  roy 
    378  1.1  roy 	term = calloc(1, sizeof(*term));
    379  1.1  roy 	if (term == NULL)
    380  1.1  roy 		errx(1, "malloc");
    381  1.1  roy 	term->name = strdup(name);
    382  1.1  roy 	term->type = type;
    383  1.1  roy 	if (term->name == NULL)
    384  1.1  roy 		errx(1, "malloc");
    385  1.1  roy 	term->next = terms;
    386  1.1  roy 	terms = term;
    387  1.1  roy 	return term;
    388  1.1  roy }
    389  1.1  roy 
    390  1.1  roy static void
    391  1.1  roy encode_string(const char *term, const char *cap, TBUF *tbuf, const char *str)
    392  1.1  roy {
    393  1.1  roy 	int slash, i, num;
    394  1.1  roy 	char ch, *p, *s, last;
    395  1.1  roy 
    396  1.1  roy 	grow_tbuf(tbuf, strlen(str) + 1);
    397  1.1  roy 	p = s = tbuf->buf + tbuf->bufpos;
    398  1.1  roy 	slash = 0;
    399  1.1  roy 	last = '\0';
    400  1.1  roy 	/* Convert escape codes */
    401  1.1  roy 	while ((ch = *str++) != '\0') {
    402  1.1  roy 		if (slash == 0 && ch == '\\') {
    403  1.1  roy 			slash = 1;
    404  1.1  roy 			continue;
    405  1.1  roy 		}
    406  1.1  roy 		if (slash == 0) {
    407  1.1  roy 			if (last != '%' && ch == '^') {
    408  1.1  roy 				ch = *str++;
    409  1.1  roy 				if (((unsigned char)ch) >= 128)
    410  1.1  roy 					dowarn("%s: %s: illegal ^ character",
    411  1.1  roy 					    term, cap);
    412  1.1  roy 				if (ch == '\0')
    413  1.1  roy 					break;
    414  1.1  roy 				if (ch == '?')
    415  1.1  roy 					ch = '\177';
    416  1.1  roy 				else if ((ch &= 037) == 0)
    417  1.1  roy 					ch = 128;
    418  1.1  roy 			}
    419  1.1  roy 			*p++ = ch;
    420  1.1  roy 			last = ch;
    421  1.1  roy 			continue;
    422  1.1  roy 		}
    423  1.1  roy 		slash = 0;
    424  1.1  roy 		if (ch >= '0' && ch <= '7') {
    425  1.1  roy 			num = ch - '0';
    426  1.1  roy 			for (i = 0; i < 2; i++) {
    427  1.1  roy 				if (*str < '0' || *str > '7') {
    428  1.1  roy 					if (isdigit((unsigned char)*str))
    429  1.1  roy 						dowarn("%s: %s: non octal"
    430  1.1  roy 						    " digit", term, cap);
    431  1.1  roy 					else
    432  1.1  roy 						break;
    433  1.1  roy 				}
    434  1.1  roy 				num = num * 8 + *str++ - '0';
    435  1.1  roy 			}
    436  1.1  roy 			if (num == 0)
    437  1.1  roy 				num = 0200;
    438  1.1  roy 			*p++ = (char)num;
    439  1.1  roy 			continue;
    440  1.1  roy 		}
    441  1.1  roy 		switch (ch) {
    442  1.1  roy 		case 'a':
    443  1.1  roy 			*p++ = '\a';
    444  1.1  roy 			break;
    445  1.1  roy 		case 'b':
    446  1.1  roy 			*p++ = '\b';
    447  1.1  roy 			break;
    448  1.1  roy 		case 'e': /* FALLTHROUGH */
    449  1.1  roy 		case 'E':
    450  1.1  roy 			*p++ = '\033';
    451  1.1  roy 			break;
    452  1.1  roy 		case 'f':
    453  1.1  roy 			*p++ = '\014';
    454  1.1  roy 			break;
    455  1.1  roy 		case 'l': /* FALLTHROUGH */
    456  1.1  roy 		case 'n':
    457  1.1  roy 			*p++ = '\n';
    458  1.1  roy 			break;
    459  1.1  roy 		case 'r':
    460  1.1  roy 			*p++ = '\r';
    461  1.1  roy 			break;
    462  1.1  roy 		case 's':
    463  1.1  roy 			*p++ = ' ';
    464  1.1  roy 			break;
    465  1.1  roy 		case 't':
    466  1.1  roy 			*p++ = '\t';
    467  1.1  roy 			break;
    468  1.1  roy 		default:
    469  1.1  roy 
    470  1.1  roy 			/* We should warn here */
    471  1.1  roy 		case '^':
    472  1.1  roy 		case ',':
    473  1.1  roy 		case ':':
    474  1.1  roy 		case '|':
    475  1.1  roy 			*p++ = ch;
    476  1.1  roy 			break;
    477  1.1  roy 		}
    478  1.1  roy 		last = ch;
    479  1.1  roy 	}
    480  1.1  roy 	*p++ = '\0';
    481  1.1  roy 	tbuf->bufpos += p - s;
    482  1.1  roy }
    483  1.1  roy 
    484  1.1  roy static int
    485  1.1  roy process_entry(TBUF *buf)
    486  1.1  roy {
    487  1.3   he 	char *cap, *capstart, *p, *e, *name, *desc, *alias;
    488  1.3   he 	signed char flag;
    489  1.1  roy 	long num;
    490  1.1  roy 	int slash;
    491  1.1  roy 	ssize_t ind;
    492  1.1  roy 	size_t len;
    493  1.1  roy 	TERM *term;
    494  1.1  roy 	TIC *tic;
    495  1.1  roy 
    496  1.1  roy 	if (buf->bufpos == 0)
    497  1.1  roy 		return 0;
    498  1.1  roy 	/* Terminate the string */
    499  1.1  roy 	buf->buf[buf->bufpos - 1] = '\0';
    500  1.1  roy 	/* First rewind the buffer for new entries */
    501  1.1  roy 	buf->bufpos = 0;
    502  1.1  roy 
    503  1.1  roy 	if (isspace((unsigned char)*buf->buf))
    504  1.1  roy 		return 0;
    505  1.1  roy 
    506  1.1  roy 	cap = strchr(buf->buf, '\n');
    507  1.1  roy 	if (cap == NULL)
    508  1.1  roy 		return 0;
    509  1.1  roy 	e = cap - 1;
    510  1.1  roy 	if (*e == ',')
    511  1.1  roy 		*e = '\0';
    512  1.1  roy 	*cap++ = '\0';
    513  1.1  roy 
    514  1.1  roy 	name = buf->buf;
    515  1.1  roy 	desc = strrchr(buf->buf, '|');
    516  1.1  roy 	if (desc != NULL)
    517  1.1  roy 		*desc++ = '\0';
    518  1.1  roy 	alias = strchr(buf->buf, '|');
    519  1.1  roy 	if (alias != NULL)
    520  1.1  roy 		*alias++ = '\0';
    521  1.1  roy 
    522  1.1  roy 	if (*e != '\0')
    523  1.1  roy 		dowarn("%s: description missing separator", buf->buf);
    524  1.1  roy 
    525  1.1  roy 	/* If we already have this term, abort */
    526  1.1  roy 	if (find_term(name) != NULL) {
    527  1.1  roy 		dowarn("%s: duplicate entry", name);
    528  1.1  roy 		return 0;
    529  1.1  roy 	}
    530  1.1  roy 	term = store_term(name, 't');
    531  1.1  roy 	tic = &term->tic;
    532  1.1  roy 	tic->name = strdup(name);
    533  1.1  roy 	if (tic->name == NULL)
    534  1.1  roy 		err(1, "malloc");
    535  1.2  roy 	if (alias != NULL) {
    536  1.2  roy 		tic->alias = strdup(alias);
    537  1.2  roy 		if (tic->alias == NULL)
    538  1.2  roy 			err(1, "malloc");
    539  1.2  roy 	}
    540  1.1  roy 	if (desc != NULL) {
    541  1.1  roy 		tic->desc = strdup(desc);
    542  1.1  roy 		if (tic->desc == NULL)
    543  1.1  roy 			err(1, "malloc");
    544  1.1  roy 	}
    545  1.1  roy 
    546  1.1  roy 	do {
    547  1.1  roy 		while (isspace((unsigned char)*cap))
    548  1.1  roy 			cap++;
    549  1.1  roy 		if (*cap == '\0')
    550  1.1  roy 			break;
    551  1.1  roy 		slash = 0;
    552  1.1  roy 		for (capstart = cap;
    553  1.1  roy 		     *cap != '\0' && (slash == 1 || *cap != ',');
    554  1.1  roy 		     cap++)
    555  1.1  roy 		{
    556  1.1  roy 			if (slash == 0) {
    557  1.1  roy 				if (*cap == '\\')
    558  1.1  roy 					slash = 1;
    559  1.1  roy 			} else
    560  1.1  roy 				slash = 0;
    561  1.1  roy 			continue;
    562  1.1  roy 		}
    563  1.1  roy 		*cap++ = '\0';
    564  1.1  roy 
    565  1.1  roy 		/* Skip commented caps */
    566  1.1  roy 		if (aflag == 0 && capstart[0] == '.')
    567  1.1  roy 			continue;
    568  1.1  roy 
    569  1.1  roy 		/* Obsolete entries */
    570  1.1  roy 		if (capstart[0] == 'O' && capstart[1] == 'T') {
    571  1.1  roy 			if (xflag == 0)
    572  1.1  roy 				continue;
    573  1.1  roy 			capstart += 2;
    574  1.1  roy 		}
    575  1.1  roy 
    576  1.1  roy 		/* str cap */
    577  1.1  roy 		p = strchr(capstart, '=');
    578  1.1  roy 		if (p != NULL) {
    579  1.1  roy 			*p++ = '\0';
    580  1.1  roy 			/* Don't use the string if we already have it */
    581  1.1  roy 			ind = _ti_strindex(capstart);
    582  1.1  roy 			if (ind != -1 &&
    583  1.1  roy 			    find_cap(&tic->strs, 's', ind) != NULL)
    584  1.1  roy 				continue;
    585  1.1  roy 
    586  1.1  roy 			/* Encode the string to our scratch buffer */
    587  1.1  roy 			scratch.bufpos = 0;
    588  1.1  roy 			encode_string(tic->name, capstart, &scratch, p);
    589  1.1  roy 			if (scratch.bufpos > UINT16_T_MAX) {
    590  1.1  roy 				dowarn("%s: %s: string is too long",
    591  1.1  roy 				    tic->name, capstart);
    592  1.1  roy 				continue;
    593  1.1  roy 			}
    594  1.1  roy 			if (!VALID_STRING(scratch.buf)) {
    595  1.1  roy 				dowarn("%s: %s: invalid string",
    596  1.1  roy 				    tic->name, capstart);
    597  1.1  roy 				continue;
    598  1.1  roy 			}
    599  1.1  roy 
    600  1.1  roy 			if (ind == -1)
    601  1.1  roy 				store_extra(tic, 1, capstart, 's', -1, -2,
    602  1.1  roy 				    scratch.buf, scratch.bufpos);
    603  1.1  roy 			else {
    604  1.1  roy 				grow_tbuf(&tic->strs, (sizeof(uint16_t) * 2) +
    605  1.1  roy 				    scratch.bufpos);
    606  1.1  roy 				le16enc(tic->strs.buf + tic->strs.bufpos, ind);
    607  1.1  roy 				tic->strs.bufpos += sizeof(uint16_t);
    608  1.1  roy 				le16enc(tic->strs.buf + tic->strs.bufpos,
    609  1.1  roy 				    scratch.bufpos);
    610  1.1  roy 				tic->strs.bufpos += sizeof(uint16_t);
    611  1.1  roy 				memcpy(tic->strs.buf + tic->strs.bufpos,
    612  1.1  roy 				    scratch.buf, scratch.bufpos);
    613  1.1  roy 				tic->strs.bufpos += scratch.bufpos;
    614  1.1  roy 				tic->strs.entries++;
    615  1.1  roy 			}
    616  1.1  roy 			continue;
    617  1.1  roy 		}
    618  1.1  roy 
    619  1.1  roy 		/* num cap */
    620  1.1  roy 		p = strchr(capstart, '#');
    621  1.1  roy 		if (p != NULL) {
    622  1.1  roy 			*p++ = '\0';
    623  1.1  roy 			/* Don't use the number if we already have it */
    624  1.1  roy 			ind = _ti_numindex(capstart);
    625  1.1  roy 			if (ind != -1 &&
    626  1.1  roy 			    find_cap(&tic->nums, 'n', ind) != NULL)
    627  1.1  roy 				continue;
    628  1.1  roy 
    629  1.1  roy 			num = strtol(p, &e, 0);
    630  1.1  roy 			if (*e != '\0') {
    631  1.1  roy 				dowarn("%s: %s: not a number",
    632  1.1  roy 				    tic->name, capstart);
    633  1.1  roy 				continue;
    634  1.1  roy 			}
    635  1.1  roy 			if (!VALID_NUMERIC(num)) {
    636  1.1  roy 				dowarn("%s: %s: number out of range",
    637  1.1  roy 				    tic->name, capstart);
    638  1.1  roy 				continue;
    639  1.1  roy 			}
    640  1.1  roy 			if (ind == -1)
    641  1.1  roy 				store_extra(tic, 1, capstart, 'n', -1,
    642  1.1  roy 				    num, NULL, 0);
    643  1.1  roy 			else {
    644  1.1  roy 				grow_tbuf(&tic->nums, sizeof(uint16_t) * 2);
    645  1.1  roy 				le16enc(tic->nums.buf + tic->nums.bufpos, ind);
    646  1.1  roy 				tic->nums.bufpos += sizeof(uint16_t);
    647  1.1  roy 				le16enc(tic->nums.buf + tic->nums.bufpos, num);
    648  1.1  roy 				tic->nums.bufpos += sizeof(uint16_t);
    649  1.1  roy 				tic->nums.entries++;
    650  1.1  roy 			}
    651  1.1  roy 			continue;
    652  1.1  roy 		}
    653  1.1  roy 
    654  1.1  roy 		flag = 1;
    655  1.1  roy 		len = strlen(capstart) - 1;
    656  1.1  roy 		if (capstart[len] == '@') {
    657  1.1  roy 			flag = CANCELLED_BOOLEAN;
    658  1.1  roy 			capstart[len] = '\0';
    659  1.1  roy 		}
    660  1.1  roy 		ind = _ti_flagindex(capstart);
    661  1.1  roy 		if (ind == -1 && flag == CANCELLED_BOOLEAN) {
    662  1.1  roy 			if ((ind = _ti_numindex(capstart)) != -1) {
    663  1.1  roy 				if (find_cap(&tic->nums, 'n', ind) != NULL)
    664  1.1  roy 					continue;
    665  1.1  roy 				grow_tbuf(&tic->nums, sizeof(uint16_t) * 2);
    666  1.1  roy 				le16enc(tic->nums.buf + tic->nums.bufpos, ind);
    667  1.1  roy 				tic->nums.bufpos += sizeof(uint16_t);
    668  1.1  roy 				le16enc(tic->nums.buf + tic->nums.bufpos,
    669  1.1  roy 					CANCELLED_NUMERIC);
    670  1.1  roy 				tic->nums.bufpos += sizeof(uint16_t);
    671  1.1  roy 				tic->nums.entries++;
    672  1.1  roy 				continue;
    673  1.1  roy 			} else if ((ind = _ti_strindex(capstart)) != -1) {
    674  1.1  roy 				if (find_cap(&tic->strs, 's', ind) != NULL)
    675  1.1  roy 					continue;
    676  1.1  roy 				grow_tbuf(&tic->strs,
    677  1.1  roy 				    (sizeof(uint16_t) * 2) + 1);
    678  1.1  roy 				le16enc(tic->strs.buf + tic->strs.bufpos, ind);
    679  1.1  roy 				tic->strs.bufpos += sizeof(uint16_t);
    680  1.1  roy 				le16enc(tic->strs.buf + tic->strs.bufpos, 0);
    681  1.1  roy 				tic->strs.bufpos += sizeof(uint16_t);
    682  1.1  roy 				tic->strs.entries++;
    683  1.1  roy 				continue;
    684  1.1  roy 			}
    685  1.1  roy 		}
    686  1.1  roy 		if (ind == -1)
    687  1.1  roy 			store_extra(tic, 1, capstart, 'f', flag, 0, NULL, 0);
    688  1.1  roy 		else if (find_cap(&tic->flags, 'f', ind) == NULL) {
    689  1.1  roy 			grow_tbuf(&tic->flags, sizeof(uint16_t) + 1);
    690  1.1  roy 			le16enc(tic->flags.buf + tic->flags.bufpos, ind);
    691  1.1  roy 			tic->flags.bufpos += sizeof(uint16_t);
    692  1.1  roy 			tic->flags.buf[tic->flags.bufpos++] = flag;
    693  1.1  roy 			tic->flags.entries++;
    694  1.1  roy 		}
    695  1.1  roy 	} while (*cap == ',' || isspace((unsigned char)*cap));
    696  1.1  roy 
    697  1.1  roy 	/* Create aliased terms */
    698  1.1  roy 	if (alias != NULL) {
    699  1.1  roy 		while (alias != NULL && *alias != '\0') {
    700  1.1  roy 			desc = strchr(alias, '|');
    701  1.1  roy 			if (desc != NULL)
    702  1.1  roy 				*desc++ = '\0';
    703  1.1  roy 			if (find_term(alias) != NULL) {
    704  1.1  roy 				dowarn("%s: has alias for already assigned"
    705  1.1  roy 				    " term %s", tic->name, alias);
    706  1.1  roy 			} else {
    707  1.1  roy 				term = store_term(alias, 'a');
    708  1.1  roy 				term->tic.name = strdup(tic->name);
    709  1.1  roy 				if (term->tic.name == NULL)
    710  1.1  roy 					err(1, "malloc");
    711  1.1  roy 			}
    712  1.1  roy 			alias = desc;
    713  1.1  roy 		}
    714  1.1  roy 	}
    715  1.1  roy 
    716  1.1  roy 	return 0;
    717  1.1  roy }
    718  1.1  roy 
    719  1.1  roy static void
    720  1.1  roy merge(TIC *rtic, TIC *utic)
    721  1.1  roy {
    722  1.1  roy 	char *cap, flag, *code, type, *str;
    723  1.1  roy 	short ind, num;
    724  1.1  roy 	size_t n;
    725  1.1  roy 
    726  1.1  roy 	cap = utic->flags.buf;
    727  1.1  roy 	for (n = utic->flags.entries; n > 0; n--) {
    728  1.1  roy 		ind = le16dec(cap);
    729  1.1  roy 		cap += sizeof(uint16_t);
    730  1.1  roy 		flag = *cap++;
    731  1.1  roy 		if (VALID_BOOLEAN(flag) &&
    732  1.1  roy 		    find_cap(&rtic->flags, 'f', ind) == NULL)
    733  1.1  roy 		{
    734  1.1  roy 			grow_tbuf(&rtic->flags, sizeof(uint16_t) + 1);
    735  1.1  roy 			le16enc(rtic->flags.buf + rtic->flags.bufpos, ind);
    736  1.1  roy 			rtic->flags.bufpos += sizeof(uint16_t);
    737  1.1  roy 			rtic->flags.buf[rtic->flags.bufpos++] = flag;
    738  1.1  roy 			rtic->flags.entries++;
    739  1.1  roy 		}
    740  1.1  roy 	}
    741  1.1  roy 
    742  1.1  roy 	cap = utic->nums.buf;
    743  1.1  roy 	for (n = utic->nums.entries; n > 0; n--) {
    744  1.1  roy 		ind = le16dec(cap);
    745  1.1  roy 		cap += sizeof(uint16_t);
    746  1.1  roy 		num = le16dec(cap);
    747  1.1  roy 		cap += sizeof(uint16_t);
    748  1.1  roy 		if (VALID_NUMERIC(num) &&
    749  1.1  roy 		    find_cap(&rtic->nums, 'n', ind) == NULL)
    750  1.1  roy 		{
    751  1.1  roy 			grow_tbuf(&rtic->nums, sizeof(uint16_t) * 2);
    752  1.1  roy 			le16enc(rtic->nums.buf + rtic->nums.bufpos, ind);
    753  1.1  roy 			rtic->nums.bufpos += sizeof(uint16_t);
    754  1.1  roy 			le16enc(rtic->nums.buf + rtic->nums.bufpos, num);
    755  1.1  roy 			rtic->nums.bufpos += sizeof(uint16_t);
    756  1.1  roy 			rtic->nums.entries++;
    757  1.1  roy 		}
    758  1.1  roy 	}
    759  1.1  roy 
    760  1.1  roy 	cap = utic->strs.buf;
    761  1.1  roy 	for (n = utic->strs.entries; n > 0; n--) {
    762  1.1  roy 		ind = le16dec(cap);
    763  1.1  roy 		cap += sizeof(uint16_t);
    764  1.1  roy 		num = le16dec(cap);
    765  1.1  roy 		cap += sizeof(uint16_t);
    766  1.1  roy 		if (num > 0 &&
    767  1.1  roy 		    find_cap(&rtic->strs, 's', ind) == NULL)
    768  1.1  roy 		{
    769  1.1  roy 			grow_tbuf(&rtic->strs, (sizeof(uint16_t) * 2) + num);
    770  1.1  roy 			le16enc(rtic->strs.buf + rtic->strs.bufpos, ind);
    771  1.1  roy 			rtic->strs.bufpos += sizeof(uint16_t);
    772  1.1  roy 			le16enc(rtic->strs.buf + rtic->strs.bufpos, num);
    773  1.1  roy 			rtic->strs.bufpos += sizeof(uint16_t);
    774  1.1  roy 			memcpy(rtic->strs.buf + rtic->strs.bufpos,
    775  1.1  roy 			    cap, num);
    776  1.1  roy 			rtic->strs.bufpos += num;
    777  1.1  roy 			rtic->strs.entries++;
    778  1.1  roy 		}
    779  1.1  roy 		cap += num;
    780  1.1  roy 	}
    781  1.1  roy 
    782  1.1  roy 	cap = utic->extras.buf;
    783  1.1  roy 	for (n = utic->extras.entries; n > 0; n--) {
    784  1.1  roy 		num = le16dec(cap);
    785  1.1  roy 		cap += sizeof(uint16_t);
    786  1.1  roy 		code = cap;
    787  1.1  roy 		cap += num;
    788  1.1  roy 		type = *cap++;
    789  1.1  roy 		flag = 0;
    790  1.1  roy 		str = NULL;
    791  1.1  roy 		switch (type) {
    792  1.1  roy 		case 'f':
    793  1.1  roy 			flag = *cap++;
    794  1.1  roy 			if (!VALID_BOOLEAN(flag))
    795  1.1  roy 				continue;
    796  1.1  roy 			break;
    797  1.1  roy 		case 'n':
    798  1.1  roy 			num = le16dec(cap);
    799  1.1  roy 			cap += sizeof(uint16_t);
    800  1.1  roy 			if (!VALID_NUMERIC(num))
    801  1.1  roy 				continue;
    802  1.1  roy 			break;
    803  1.1  roy 		case 's':
    804  1.1  roy 			num = le16dec(cap);
    805  1.1  roy 			cap += sizeof(uint16_t);
    806  1.1  roy 			str = cap;
    807  1.1  roy 			cap += num;
    808  1.1  roy 			if (num == 0)
    809  1.1  roy 				continue;
    810  1.1  roy 			break;
    811  1.1  roy 		}
    812  1.1  roy 		store_extra(rtic, 0, code, type, flag, num, str, num);
    813  1.1  roy 	}
    814  1.1  roy }
    815  1.1  roy 
    816  1.1  roy static size_t
    817  1.1  roy merge_use(void)
    818  1.1  roy {
    819  1.1  roy 	size_t skipped, merged, memn;
    820  1.1  roy 	char *cap, *scap;
    821  1.1  roy 	uint16_t num;
    822  1.1  roy 	TIC *rtic, *utic;
    823  1.1  roy 	TERM *term, *uterm;;
    824  1.1  roy 
    825  1.1  roy 	skipped = merged = 0;
    826  1.1  roy 	for (term = terms; term != NULL; term = term->next) {
    827  1.1  roy 		if (term->type == 'a')
    828  1.1  roy 			continue;
    829  1.1  roy 		rtic = &term->tic;
    830  1.1  roy 		while ((cap = find_extra(&rtic->extras, "use")) != NULL) {
    831  1.1  roy 			if (*cap++ != 's') {
    832  1.1  roy 				dowarn("%s: use is not string", rtic->name);
    833  1.1  roy 				break;
    834  1.1  roy 			}
    835  1.1  roy 			cap += sizeof(uint16_t);
    836  1.1  roy 			if (strcmp(rtic->name, cap) == 0) {
    837  1.1  roy 				dowarn("%s: uses itself", rtic->name);
    838  1.1  roy 				goto remove;
    839  1.1  roy 			}
    840  1.1  roy 			uterm = find_term(cap);
    841  1.1  roy 			if (uterm != NULL && uterm->type == 'a')
    842  1.1  roy 				uterm = find_term(uterm->tic.name);
    843  1.1  roy 			if (uterm == NULL) {
    844  1.1  roy 				dowarn("%s: no use record for %s",
    845  1.1  roy 				    rtic->name, cap);
    846  1.1  roy 				goto remove;
    847  1.1  roy 			}
    848  1.1  roy 			utic = &uterm->tic;
    849  1.1  roy 			if (strcmp(utic->name, rtic->name) == 0) {
    850  1.1  roy 				dowarn("%s: uses itself", rtic->name);
    851  1.1  roy 				goto remove;
    852  1.1  roy 			}
    853  1.1  roy 			if (find_extra(&utic->extras, "use") != NULL) {
    854  1.1  roy 				skipped++;
    855  1.1  roy 				break;
    856  1.1  roy 			}
    857  1.1  roy 			cap = find_extra(&rtic->extras, "use");
    858  1.1  roy 			merge(rtic, utic);
    859  1.1  roy 	remove:
    860  1.1  roy 			/* The pointers may have changed, find the use again */
    861  1.1  roy 			cap = find_extra(&rtic->extras, "use");
    862  1.1  roy 			if (cap == NULL)
    863  1.1  roy 				dowarn("%s: use no longer exists - impossible",
    864  1.1  roy 					rtic->name);
    865  1.1  roy 			else {
    866  1.1  roy 				scap = cap - (4 + sizeof(uint16_t));
    867  1.1  roy 				cap++;
    868  1.1  roy 				num = le16dec(cap);
    869  1.1  roy 				cap += sizeof(uint16_t) + num;
    870  1.1  roy 				memn = rtic->extras.bufpos -
    871  1.1  roy 				    (cap - rtic->extras.buf);
    872  1.1  roy 				memcpy(scap, cap, memn);
    873  1.1  roy 				rtic->extras.bufpos -= cap - scap;
    874  1.1  roy 				cap = scap;
    875  1.1  roy 				rtic->extras.entries--;
    876  1.1  roy 				merged++;
    877  1.1  roy 			}
    878  1.1  roy 		}
    879  1.1  roy 	}
    880  1.1  roy 
    881  1.1  roy 	if (merged == 0 && skipped != 0)
    882  1.1  roy 		dowarn("circular use detected");
    883  1.1  roy 	return merged;
    884  1.1  roy }
    885  1.1  roy 
    886  1.5  roy static int
    887  1.5  roy print_dump(int argc, char **argv)
    888  1.5  roy {
    889  1.5  roy 	TERM *term;
    890  1.5  roy 	TBUF *buf;
    891  1.5  roy 	int i, n;
    892  1.5  roy 	size_t j, col;
    893  1.5  roy 
    894  1.5  roy 	n = 0;
    895  1.5  roy 
    896  1.5  roy 	for (i = 0; i < argc; i++) {
    897  1.5  roy 		term = find_term(argv[i]);
    898  1.5  roy 		if (term == NULL) {
    899  1.5  roy 			warnx("%s: no description for terminal", argv[i]);
    900  1.5  roy 			continue;
    901  1.5  roy 		}
    902  1.5  roy 		if (term->type == 'a') {
    903  1.5  roy 			warnx("%s: cannot dump alias", argv[i]);
    904  1.5  roy 			continue;
    905  1.5  roy 		}
    906  1.5  roy 		buf = flatten_term(term);
    907  1.5  roy 		if (buf == NULL)
    908  1.5  roy 			continue;
    909  1.5  roy 
    910  1.5  roy 		printf("\t\"%s\",\n", argv[i]);
    911  1.5  roy 		n++;
    912  1.5  roy 		for (j = 0, col = 0; j < buf->bufpos; j++) {
    913  1.5  roy 			if (col == 0) {
    914  1.5  roy 				printf("\t\"");
    915  1.5  roy 				col = 8;
    916  1.5  roy 			}
    917  1.5  roy 
    918  1.5  roy 			col += printf("\\%03o", (uint8_t)buf->buf[j]);
    919  1.5  roy 			if (col > 75) {
    920  1.5  roy 				printf("\"%s\n",
    921  1.5  roy 				    j + 1 == buf->bufpos ? "," : "");
    922  1.5  roy 				col = 0;
    923  1.5  roy 			}
    924  1.5  roy 		}
    925  1.5  roy 		if (col != 0)
    926  1.5  roy 		    printf("\",\n");
    927  1.5  roy 	}
    928  1.5  roy 
    929  1.5  roy 	return n;
    930  1.5  roy }
    931  1.5  roy 
    932  1.1  roy int
    933  1.1  roy main(int argc, char **argv)
    934  1.1  roy {
    935  1.5  roy 	int ch, Sflag, cflag, sflag;
    936  1.1  roy 	char *source, *p, *buf, *ofile;
    937  1.1  roy 	FILE *f;
    938  1.1  roy 	DBM *db;
    939  1.1  roy 	size_t len, buflen, nterm, nalias;
    940  1.1  roy 	TBUF tbuf;
    941  1.1  roy 	TERM *term;
    942  1.1  roy 
    943  1.1  roy 	cflag = sflag = 0;
    944  1.1  roy 	ofile = NULL;
    945  1.5  roy 	while ((ch = getopt(argc, argv, "Saco:sx")) != -1)
    946  1.1  roy 	    switch (ch) {
    947  1.5  roy 	    case 'S':
    948  1.5  roy 		    Sflag = 1;
    949  1.5  roy 		    break;
    950  1.1  roy 	    case 'a':
    951  1.4  roy 		    aflag = 1;
    952  1.1  roy 		    break;
    953  1.1  roy 	    case 'c':
    954  1.4  roy 		    cflag = 1;
    955  1.1  roy 		    break;
    956  1.1  roy 	    case 'o':
    957  1.1  roy 		    ofile = optarg;
    958  1.1  roy 		    break;
    959  1.1  roy 	    case 's':
    960  1.4  roy 		    sflag = 1;
    961  1.1  roy 		    break;
    962  1.1  roy 	    case 'x':
    963  1.4  roy 		    xflag = 1;
    964  1.1  roy 		    break;
    965  1.1  roy 	    case '?': /* FALLTHROUGH */
    966  1.1  roy 	    default:
    967  1.5  roy 		    fprintf(stderr, "usage: %s [-Sacsx] [-o file] source\n",
    968  1.1  roy 			getprogname());
    969  1.1  roy 		    return EXIT_FAILURE;
    970  1.1  roy 	    }
    971  1.1  roy 
    972  1.1  roy 	if (optind == argc)
    973  1.1  roy 		errx(1, "No source file given");
    974  1.1  roy 	source = argv[optind++];
    975  1.1  roy 	f = fopen(source, "r");
    976  1.1  roy 	if (f == NULL)
    977  1.1  roy 		err(1, "fopen: %s", source);
    978  1.5  roy 	if (cflag == 0 && Sflag == 0) {
    979  1.1  roy 		if (ofile == NULL)
    980  1.1  roy 			ofile = source;
    981  1.1  roy 		len = strlen(ofile) + 9;
    982  1.1  roy 		dbname = malloc(len + 4); /* For adding .db after open */
    983  1.1  roy 		if (dbname == NULL)
    984  1.1  roy 			err(1, "malloc");
    985  1.1  roy 		snprintf(dbname, len, "%s.tmp", ofile);
    986  1.1  roy 		db = dbm_open(dbname, O_CREAT | O_RDWR | O_TRUNC, DEFFILEMODE);
    987  1.1  roy 		if (db == NULL)
    988  1.1  roy 			err(1, "dbopen: %s", source);
    989  1.1  roy 		p = dbname + strlen(dbname);
    990  1.1  roy 		*p++ = '.';
    991  1.1  roy 		*p++ = 'd';
    992  1.1  roy 		*p++ = 'b';
    993  1.1  roy 		*p++ = '\0';
    994  1.1  roy 		atexit(do_unlink);
    995  1.1  roy 	} else
    996  1.1  roy 		db = NULL; /* satisfy gcc warning */
    997  1.1  roy 
    998  1.1  roy 	tbuf.buflen = tbuf.bufpos = 0;
    999  1.1  roy 	while ((buf = fgetln(f, &buflen)) != NULL) {
   1000  1.1  roy 		/* Skip comments */
   1001  1.1  roy 		if (*buf == '#')
   1002  1.1  roy 			continue;
   1003  1.1  roy 		if (buf[buflen - 1] != '\n') {
   1004  1.1  roy 			process_entry(&tbuf);
   1005  1.1  roy 			dowarn("last line is not a comment"
   1006  1.1  roy 			    " and does not end with a newline");
   1007  1.1  roy 			continue;
   1008  1.1  roy 		}
   1009  1.1  roy 		/*
   1010  1.1  roy 		  If the first char is space not a space then we have a
   1011  1.1  roy 		  new entry, so process it.
   1012  1.1  roy 		*/
   1013  1.1  roy 		if (!isspace((unsigned char)*buf) && tbuf.bufpos != 0)
   1014  1.1  roy 			process_entry(&tbuf);
   1015  1.1  roy 
   1016  1.1  roy 		/* Grow the buffer if needed */
   1017  1.1  roy 		grow_tbuf(&tbuf, buflen);
   1018  1.1  roy 		/* Append the string */
   1019  1.1  roy 		memcpy(tbuf.buf + tbuf.bufpos, buf, buflen);
   1020  1.1  roy 		tbuf.bufpos += buflen;
   1021  1.1  roy 	}
   1022  1.1  roy 	/* Process the last entry if not done already */
   1023  1.1  roy 	process_entry(&tbuf);
   1024  1.1  roy 
   1025  1.1  roy 	/* Merge use entries until we have merged all we can */
   1026  1.1  roy 	while (merge_use() != 0)
   1027  1.1  roy 		;
   1028  1.1  roy 
   1029  1.5  roy 	if (Sflag != 0) {
   1030  1.5  roy 		print_dump(argc - optind, argv + optind);
   1031  1.5  roy 		return error_exit;
   1032  1.5  roy 	}
   1033  1.5  roy 
   1034  1.1  roy 	if (cflag != 0)
   1035  1.1  roy 		return error_exit;
   1036  1.1  roy 
   1037  1.1  roy 	/* Save the terms */
   1038  1.1  roy 	nterm = nalias = 0;
   1039  1.1  roy 	for (term = terms; term != NULL; term = term->next) {
   1040  1.1  roy 		save_term(db, term);
   1041  1.1  roy 		if (term->type == 'a')
   1042  1.1  roy 			nalias++;
   1043  1.1  roy 		else
   1044  1.1  roy 			nterm++;
   1045  1.1  roy 	}
   1046  1.1  roy 
   1047  1.1  roy 	/* done! */
   1048  1.1  roy 	dbm_close(db);
   1049  1.1  roy 
   1050  1.1  roy 	/* Rename the tmp db to the real one now */
   1051  1.1  roy 	len = strlen(ofile) + 4;
   1052  1.1  roy 	p = malloc(len);
   1053  1.1  roy 	if (p == NULL)
   1054  1.1  roy 		err(1, "malloc");
   1055  1.1  roy 	snprintf(p, len, "%s.db", ofile);
   1056  1.1  roy 	if (rename(dbname, p) == -1)
   1057  1.1  roy 		err(1, "rename");
   1058  1.1  roy 	free(dbname);
   1059  1.1  roy 	dbname = NULL;
   1060  1.1  roy 
   1061  1.1  roy 	if (sflag != 0)
   1062  1.1  roy 		fprintf(stderr, "%zu entries and %zu aliases written to %s\n",
   1063  1.1  roy 		    nterm, nalias, p);
   1064  1.1  roy 
   1065  1.1  roy 	return EXIT_SUCCESS;
   1066  1.1  roy }
   1067