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