1*98b34193Schristos /* $NetBSD: tic.c,v 1.42 2024/05/20 14:41:37 christos Exp $ */
24ca00e00Sroy
34ca00e00Sroy /*
4aadfdb11Sroy * Copyright (c) 2009, 2010, 2020 The NetBSD Foundation, Inc.
54ca00e00Sroy *
64ca00e00Sroy * This code is derived from software contributed to The NetBSD Foundation
74ca00e00Sroy * by Roy Marples.
84ca00e00Sroy *
94ca00e00Sroy * Redistribution and use in source and binary forms, with or without
104ca00e00Sroy * modification, are permitted provided that the following conditions
114ca00e00Sroy * are met:
124ca00e00Sroy * 1. Redistributions of source code must retain the above copyright
134ca00e00Sroy * notice, this list of conditions and the following disclaimer.
144ca00e00Sroy * 2. Redistributions in binary form must reproduce the above copyright
154ca00e00Sroy * notice, this list of conditions and the following disclaimer in the
164ca00e00Sroy * documentation and/or other materials provided with the distribution.
174ca00e00Sroy *
184ca00e00Sroy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
194ca00e00Sroy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
204ca00e00Sroy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
214ca00e00Sroy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
224ca00e00Sroy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
234ca00e00Sroy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
244ca00e00Sroy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
254ca00e00Sroy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
264ca00e00Sroy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
274ca00e00Sroy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
284ca00e00Sroy */
294ca00e00Sroy
304ca00e00Sroy #if HAVE_NBTOOL_CONFIG_H
314ca00e00Sroy #include "nbtool_config.h"
324ca00e00Sroy #endif
334ca00e00Sroy
344ca00e00Sroy #include <sys/cdefs.h>
35*98b34193Schristos __RCSID("$NetBSD: tic.c,v 1.42 2024/05/20 14:41:37 christos Exp $");
364ca00e00Sroy
374ca00e00Sroy #include <sys/types.h>
38974fdf37Sjoerg #include <sys/queue.h>
396dbf86bcSchristos #include <sys/stat.h>
404b2f1808Spgoyette
413360c946Spgoyette #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
42237e56a5Spgoyette #include <sys/endian.h>
434b2f1808Spgoyette #endif
444ca00e00Sroy
45fc67b0cdSjoerg #include <cdbw.h>
464ca00e00Sroy #include <ctype.h>
474ca00e00Sroy #include <err.h>
484ca00e00Sroy #include <errno.h>
494ca00e00Sroy #include <getopt.h>
504ca00e00Sroy #include <limits.h>
514ca00e00Sroy #include <fcntl.h>
522b5ab407Sjoerg #include <search.h>
534ca00e00Sroy #include <stdarg.h>
547acb5614Sroy #include <stdbool.h>
554ca00e00Sroy #include <stdlib.h>
564ca00e00Sroy #include <stdio.h>
574ca00e00Sroy #include <string.h>
584ca00e00Sroy #include <term_private.h>
594ca00e00Sroy #include <term.h>
602b691b87Sjoerg #include <unistd.h>
61d6b0aba1Sjoerg #include <util.h>
622b5ab407Sjoerg
632b5ab407Sjoerg #define HASH_SIZE 16384 /* 2012-06-01: 3600 entries */
644ca00e00Sroy
654ca00e00Sroy typedef struct term {
66fc67b0cdSjoerg STAILQ_ENTRY(term) next;
674ca00e00Sroy char *name;
68fde317d2Sroy TIC *tic;
69fc67b0cdSjoerg uint32_t id;
70fc67b0cdSjoerg struct term *base_term;
714ca00e00Sroy } TERM;
72fc67b0cdSjoerg static STAILQ_HEAD(, term) terms = STAILQ_HEAD_INITIALIZER(terms);
734ca00e00Sroy
744ca00e00Sroy static int error_exit;
75fde317d2Sroy static int Sflag;
767b1c18b0Sjoerg static size_t nterm, nalias;
774ca00e00Sroy
78968a666eSjoerg static void __printflike(1, 2)
dowarn(const char * fmt,...)794ca00e00Sroy dowarn(const char *fmt, ...)
804ca00e00Sroy {
814ca00e00Sroy va_list va;
824ca00e00Sroy
834ca00e00Sroy error_exit = 1;
844ca00e00Sroy va_start(va, fmt);
854ca00e00Sroy vwarnx(fmt, va);
864ca00e00Sroy va_end(va);
874ca00e00Sroy }
884ca00e00Sroy
894ca00e00Sroy static char *
grow_tbuf(TBUF * tbuf,size_t len)904ca00e00Sroy grow_tbuf(TBUF *tbuf, size_t len)
914ca00e00Sroy {
924ca00e00Sroy char *buf;
934ca00e00Sroy
94fde317d2Sroy buf = _ti_grow_tbuf(tbuf, len);
954ca00e00Sroy if (buf == NULL)
96d58481dbSroy err(EXIT_FAILURE, "_ti_grow_tbuf");
97fde317d2Sroy return buf;
9855a396b9Sroy }
9955a396b9Sroy
10055a396b9Sroy static int
save_term(struct cdbw * db,TERM * term)101fc67b0cdSjoerg save_term(struct cdbw *db, TERM *term)
10255a396b9Sroy {
103fde317d2Sroy uint8_t *buf;
104fde317d2Sroy ssize_t len;
105fc67b0cdSjoerg size_t slen = strlen(term->name) + 1;
106fc67b0cdSjoerg
107fc67b0cdSjoerg if (term->base_term != NULL) {
108f73231daSchristos char *cap;
109f73231daSchristos len = (ssize_t)(1 + sizeof(uint32_t) + sizeof(uint16_t) + slen);
110fc67b0cdSjoerg buf = emalloc(len);
111f73231daSchristos cap = (char *)buf;
112f73231daSchristos *cap++ = TERMINFO_ALIAS;
113f73231daSchristos _ti_encode_32(&cap, term->base_term->id);
114f73231daSchristos _ti_encode_count_str(&cap, term->name, slen);
115fc67b0cdSjoerg if (cdbw_put(db, term->name, slen, buf, len))
116d58481dbSroy err(EXIT_FAILURE, "cdbw_put");
1179896a45fSchristos free(buf);
118fc67b0cdSjoerg return 0;
119fc67b0cdSjoerg }
12055a396b9Sroy
121fde317d2Sroy len = _ti_flatten(&buf, term->tic);
122fde317d2Sroy if (len == -1)
12355a396b9Sroy return -1;
1244ca00e00Sroy
125fc67b0cdSjoerg if (cdbw_put_data(db, buf, len, &term->id))
126d58481dbSroy err(EXIT_FAILURE, "cdbw_put_data");
127fc67b0cdSjoerg if (cdbw_put_key(db, term->name, slen, term->id))
128d58481dbSroy err(EXIT_FAILURE, "cdbw_put_key");
129fde317d2Sroy free(buf);
1304ca00e00Sroy return 0;
1314ca00e00Sroy }
1324ca00e00Sroy
1334ca00e00Sroy static TERM *
find_term(const char * name)1344ca00e00Sroy find_term(const char *name)
1354ca00e00Sroy {
1362b5ab407Sjoerg ENTRY elem, *elemp;
1374ca00e00Sroy
1382b5ab407Sjoerg elem.key = __UNCONST(name);
1392b5ab407Sjoerg elem.data = NULL;
1402b5ab407Sjoerg elemp = hsearch(elem, FIND);
1412b5ab407Sjoerg return elemp ? (TERM *)elemp->data : NULL;
1424ca00e00Sroy }
1434ca00e00Sroy
1444ca00e00Sroy static TERM *
find_newest_term(const char * name)1457acb5614Sroy find_newest_term(const char *name)
1467acb5614Sroy {
1477acb5614Sroy char *lname;
1487acb5614Sroy TERM *term;
1497acb5614Sroy
1507acb5614Sroy lname = _ti_getname(TERMINFO_RTYPE, name);
1517acb5614Sroy if (lname == NULL)
1527acb5614Sroy return NULL;
1537acb5614Sroy term = find_term(lname);
1547acb5614Sroy free(lname);
1557acb5614Sroy if (term == NULL)
1567acb5614Sroy term = find_term(name);
1577acb5614Sroy return term;
1587acb5614Sroy }
1597acb5614Sroy
1607acb5614Sroy static TERM *
store_term(const char * name,TERM * base_term)161fc67b0cdSjoerg store_term(const char *name, TERM *base_term)
1624ca00e00Sroy {
1634ca00e00Sroy TERM *term;
1642b5ab407Sjoerg ENTRY elem;
1654ca00e00Sroy
166cff379a9Sjoerg term = ecalloc(1, sizeof(*term));
167cff379a9Sjoerg term->name = estrdup(name);
168fc67b0cdSjoerg STAILQ_INSERT_TAIL(&terms, term, next);
1692b5ab407Sjoerg elem.key = estrdup(name);
1702b5ab407Sjoerg elem.data = term;
1712b5ab407Sjoerg hsearch(elem, ENTER);
1727b1c18b0Sjoerg
173fc67b0cdSjoerg term->base_term = base_term;
174fc67b0cdSjoerg if (base_term != NULL)
1757b1c18b0Sjoerg nalias++;
1767b1c18b0Sjoerg else
1777b1c18b0Sjoerg nterm++;
1787b1c18b0Sjoerg
1794ca00e00Sroy return term;
1804ca00e00Sroy }
1814ca00e00Sroy
1827f0204b5Sroy static void
alias_terms(TERM * term)1837f0204b5Sroy alias_terms(TERM *term)
1847f0204b5Sroy {
1857f0204b5Sroy char *p, *e, *alias;
1867f0204b5Sroy
1877f0204b5Sroy /* Create aliased terms */
1887f0204b5Sroy if (term->tic->alias == NULL)
1897f0204b5Sroy return;
1907f0204b5Sroy
1917f0204b5Sroy alias = p = estrdup(term->tic->alias);
1927f0204b5Sroy while (p != NULL && *p != '\0') {
1937f0204b5Sroy e = strchr(p, '|');
1947f0204b5Sroy if (e != NULL)
1957f0204b5Sroy *e++ = '\0';
1967f0204b5Sroy /* No need to lengthcheck the alias because the main
1977f0204b5Sroy * terminfo description already stores all the aliases
1987f0204b5Sroy * in the same length field as the alias. */
1997f0204b5Sroy if (find_term(p) != NULL) {
2007f0204b5Sroy dowarn("%s: has alias for already assigned"
2017f0204b5Sroy " term %s", term->tic->name, p);
2027f0204b5Sroy } else {
2037f0204b5Sroy store_term(p, term);
2047f0204b5Sroy }
2057f0204b5Sroy p = e;
2067f0204b5Sroy }
2077f0204b5Sroy free(alias);
2087f0204b5Sroy }
2097f0204b5Sroy
2104ca00e00Sroy static int
process_entry(TBUF * buf,int flags)211fde317d2Sroy process_entry(TBUF *buf, int flags)
2124ca00e00Sroy {
2134ca00e00Sroy TERM *term;
2144ca00e00Sroy TIC *tic;
2153958d16aSchristos TBUF sbuf = *buf;
2164ca00e00Sroy
2174ca00e00Sroy if (buf->bufpos == 0)
2184ca00e00Sroy return 0;
2194ca00e00Sroy /* Terminate the string */
2204ca00e00Sroy buf->buf[buf->bufpos - 1] = '\0';
2214ca00e00Sroy /* First rewind the buffer for new entries */
2224ca00e00Sroy buf->bufpos = 0;
2234ca00e00Sroy
2244ca00e00Sroy if (isspace((unsigned char)*buf->buf))
2254ca00e00Sroy return 0;
2264ca00e00Sroy
227fde317d2Sroy tic = _ti_compile(buf->buf, flags);
228fde317d2Sroy if (tic == NULL)
2294ca00e00Sroy return 0;
2304ca00e00Sroy
231fde317d2Sroy if (find_term(tic->name) != NULL) {
232fde317d2Sroy dowarn("%s: duplicate entry", tic->name);
233fde317d2Sroy _ti_freetic(tic);
2344ca00e00Sroy return 0;
2354ca00e00Sroy }
236fc67b0cdSjoerg term = store_term(tic->name, NULL);
237fde317d2Sroy term->tic = tic;
2387f0204b5Sroy alias_terms(term);
2394ca00e00Sroy
2403958d16aSchristos if (tic->rtype == TERMINFO_RTYPE)
2413958d16aSchristos return process_entry(&sbuf, flags | TIC_COMPAT_V1);
2423958d16aSchristos
2434ca00e00Sroy return 0;
2444ca00e00Sroy }
2454ca00e00Sroy
2464ca00e00Sroy static void
merge(TIC * rtic,TIC * utic,int flags)247fde317d2Sroy merge(TIC *rtic, TIC *utic, int flags)
2484ca00e00Sroy {
2493958d16aSchristos char flag, type;
2503958d16aSchristos const char *cap, *code, *str;
251aadfdb11Sroy short ind, len;
252aadfdb11Sroy int num;
2534ca00e00Sroy size_t n;
2544ca00e00Sroy
2557acb5614Sroy if (rtic->rtype < utic->rtype)
2567acb5614Sroy errx(EXIT_FAILURE, "merge rtype diff (%s:%d into %s:%d)",
2577acb5614Sroy utic->name, utic->rtype, rtic->name, rtic->rtype);
258f15baa5bSroy
2594ca00e00Sroy cap = utic->flags.buf;
2604ca00e00Sroy for (n = utic->flags.entries; n > 0; n--) {
261f73231daSchristos ind = _ti_decode_16(&cap);
2624ca00e00Sroy flag = *cap++;
2634ca00e00Sroy if (VALID_BOOLEAN(flag) &&
2643958d16aSchristos _ti_find_cap(rtic, &rtic->flags, 'f', ind) == NULL)
2654ca00e00Sroy {
266f73231daSchristos if (!_ti_encode_buf_id_flags(&rtic->flags, ind, flag))
267d58481dbSroy err(EXIT_FAILURE, "encode flag");
2684ca00e00Sroy }
2694ca00e00Sroy }
2704ca00e00Sroy
2714ca00e00Sroy cap = utic->nums.buf;
2724ca00e00Sroy for (n = utic->nums.entries; n > 0; n--) {
273f73231daSchristos ind = _ti_decode_16(&cap);
274f73231daSchristos num = _ti_decode_num(&cap, utic->rtype);
2754ca00e00Sroy if (VALID_NUMERIC(num) &&
2763958d16aSchristos _ti_find_cap(rtic, &rtic->nums, 'n', ind) == NULL)
2774ca00e00Sroy {
278f73231daSchristos if (!_ti_encode_buf_id_num(&rtic->nums, ind, num,
279f73231daSchristos _ti_numsize(rtic)))
280d58481dbSroy err(EXIT_FAILURE, "encode num");
2814ca00e00Sroy }
2824ca00e00Sroy }
2834ca00e00Sroy
2844ca00e00Sroy cap = utic->strs.buf;
2854ca00e00Sroy for (n = utic->strs.entries; n > 0; n--) {
286f73231daSchristos ind = _ti_decode_16(&cap);
287f73231daSchristos len = _ti_decode_16(&cap);
288aadfdb11Sroy if (len > 0 &&
2893958d16aSchristos _ti_find_cap(rtic, &rtic->strs, 's', ind) == NULL)
2904ca00e00Sroy {
291f73231daSchristos if (!_ti_encode_buf_id_count_str(&rtic->strs, ind, cap,
292f73231daSchristos len))
293d58481dbSroy err(EXIT_FAILURE, "encode str");
2944ca00e00Sroy }
295aadfdb11Sroy cap += len;
2964ca00e00Sroy }
2974ca00e00Sroy
2984ca00e00Sroy cap = utic->extras.buf;
2994ca00e00Sroy for (n = utic->extras.entries; n > 0; n--) {
300f73231daSchristos num = _ti_decode_16(&cap);
3014ca00e00Sroy code = cap;
3024ca00e00Sroy cap += num;
3034ca00e00Sroy type = *cap++;
3044ca00e00Sroy flag = 0;
3054ca00e00Sroy str = NULL;
3064ca00e00Sroy switch (type) {
3074ca00e00Sroy case 'f':
3084ca00e00Sroy flag = *cap++;
3094ca00e00Sroy if (!VALID_BOOLEAN(flag))
3104ca00e00Sroy continue;
3114ca00e00Sroy break;
3124ca00e00Sroy case 'n':
313f73231daSchristos num = _ti_decode_num(&cap, utic->rtype);
3144ca00e00Sroy if (!VALID_NUMERIC(num))
3154ca00e00Sroy continue;
3164ca00e00Sroy break;
3174ca00e00Sroy case 's':
318f73231daSchristos num = _ti_decode_16(&cap);
3194ca00e00Sroy str = cap;
3204ca00e00Sroy cap += num;
3214ca00e00Sroy if (num == 0)
3224ca00e00Sroy continue;
3234ca00e00Sroy break;
3244ca00e00Sroy }
325fde317d2Sroy _ti_store_extra(rtic, 0, code, type, flag, num, str, num,
326fde317d2Sroy flags);
3274ca00e00Sroy }
3284ca00e00Sroy }
3294ca00e00Sroy
3307acb5614Sroy static int
dup_tbuf(TBUF * dst,const TBUF * src)3317acb5614Sroy dup_tbuf(TBUF *dst, const TBUF *src)
3327acb5614Sroy {
3337acb5614Sroy
3347acb5614Sroy if (src->buflen == 0)
3357acb5614Sroy return 0;
3367acb5614Sroy dst->buf = malloc(src->buflen);
3377acb5614Sroy if (dst->buf == NULL)
3387acb5614Sroy return -1;
3397acb5614Sroy dst->buflen = src->buflen;
3407acb5614Sroy memcpy(dst->buf, src->buf, dst->buflen);
3417acb5614Sroy dst->bufpos = src->bufpos;
3427acb5614Sroy dst->entries = src->entries;
3437acb5614Sroy return 0;
3447acb5614Sroy }
3457acb5614Sroy
3467acb5614Sroy static int
promote(TIC * rtic,TIC * utic)3477acb5614Sroy promote(TIC *rtic, TIC *utic)
3487acb5614Sroy {
3497acb5614Sroy TERM *nrterm = find_newest_term(rtic->name);
3507acb5614Sroy TERM *nuterm = find_newest_term(utic->name);
3517acb5614Sroy TERM *term;
3527acb5614Sroy TIC *tic;
3537acb5614Sroy
3547acb5614Sroy if (nrterm == NULL || nuterm == NULL)
3557acb5614Sroy return -1;
3567acb5614Sroy if (nrterm->tic->rtype >= nuterm->tic->rtype)
3577acb5614Sroy return 0;
3587acb5614Sroy
3597acb5614Sroy tic = calloc(1, sizeof(*tic));
3607acb5614Sroy if (tic == NULL)
3617acb5614Sroy return -1;
3627acb5614Sroy
3637acb5614Sroy tic->name = _ti_getname(TERMINFO_RTYPE, rtic->name);
3647acb5614Sroy if (tic->name == NULL)
3657acb5614Sroy goto err;
3667f0204b5Sroy if (rtic->alias != NULL) {
3677f0204b5Sroy tic->alias = strdup(rtic->alias);
3687f0204b5Sroy if (tic->alias == NULL)
3697f0204b5Sroy goto err;
3707f0204b5Sroy }
3717acb5614Sroy if (rtic->desc != NULL) {
3727acb5614Sroy tic->desc = strdup(rtic->desc);
3737acb5614Sroy if (tic->desc == NULL)
3747acb5614Sroy goto err;
3757acb5614Sroy }
3767acb5614Sroy
3777acb5614Sroy tic->rtype = rtic->rtype;
3787acb5614Sroy if (dup_tbuf(&tic->flags, &rtic->flags) == -1)
3797acb5614Sroy goto err;
3807acb5614Sroy if (dup_tbuf(&tic->nums, &rtic->nums) == -1)
3817acb5614Sroy goto err;
3827acb5614Sroy if (dup_tbuf(&tic->strs, &rtic->strs) == -1)
3837acb5614Sroy goto err;
3847acb5614Sroy if (dup_tbuf(&tic->extras, &rtic->extras) == -1)
3857acb5614Sroy goto err;
3867acb5614Sroy if (_ti_promote(tic) == -1)
3877acb5614Sroy goto err;
3887acb5614Sroy
3897acb5614Sroy term = store_term(tic->name, NULL);
3907f0204b5Sroy if (term == NULL)
3917f0204b5Sroy goto err;
3927f0204b5Sroy
3937acb5614Sroy term->tic = tic;
3947f0204b5Sroy alias_terms(term);
3957acb5614Sroy return 0;
3967acb5614Sroy
3977acb5614Sroy err:
3987acb5614Sroy free(tic->flags.buf);
3997acb5614Sroy free(tic->nums.buf);
4007acb5614Sroy free(tic->strs.buf);
4017acb5614Sroy free(tic->extras.buf);
4027acb5614Sroy free(tic->desc);
4037f0204b5Sroy free(tic->alias);
4047acb5614Sroy free(tic->name);
4057acb5614Sroy free(tic);
4067acb5614Sroy return -1;
4077acb5614Sroy }
4087acb5614Sroy
4094ca00e00Sroy static size_t
merge_use(int flags)410fde317d2Sroy merge_use(int flags)
4114ca00e00Sroy {
4124ca00e00Sroy size_t skipped, merged, memn;
413f73231daSchristos const char *cap;
4147acb5614Sroy char *name, *basename;
4154ca00e00Sroy uint16_t num;
4164ca00e00Sroy TIC *rtic, *utic;
4177acb5614Sroy TERM *term, *uterm;
4187acb5614Sroy bool promoted;
4194ca00e00Sroy
4204ca00e00Sroy skipped = merged = 0;
421fc67b0cdSjoerg STAILQ_FOREACH(term, &terms, next) {
422fc67b0cdSjoerg if (term->base_term != NULL)
4234ca00e00Sroy continue;
424fde317d2Sroy rtic = term->tic;
4257acb5614Sroy basename = _ti_getname(TERMINFO_RTYPE_O1, rtic->name);
4267acb5614Sroy promoted = false;
4273958d16aSchristos while ((cap = _ti_find_extra(rtic, &rtic->extras, "use"))
4283958d16aSchristos != NULL) {
4294ca00e00Sroy if (*cap++ != 's') {
4304ca00e00Sroy dowarn("%s: use is not string", rtic->name);
4314ca00e00Sroy break;
4324ca00e00Sroy }
4334ca00e00Sroy cap += sizeof(uint16_t);
4347acb5614Sroy if (strcmp(basename, cap) == 0) {
4354ca00e00Sroy dowarn("%s: uses itself", rtic->name);
4364ca00e00Sroy goto remove;
4374ca00e00Sroy }
4387acb5614Sroy name = _ti_getname(rtic->rtype, cap);
4397acb5614Sroy if (name == NULL) {
4407acb5614Sroy dowarn("%s: ???: %s", rtic->name, cap);
4417acb5614Sroy goto remove;
4427acb5614Sroy }
4437acb5614Sroy uterm = find_term(name);
4447acb5614Sroy free(name);
4457acb5614Sroy if (uterm == NULL)
4464ca00e00Sroy uterm = find_term(cap);
447fc67b0cdSjoerg if (uterm != NULL && uterm->base_term != NULL)
448fc67b0cdSjoerg uterm = uterm->base_term;
4494ca00e00Sroy if (uterm == NULL) {
4504ca00e00Sroy dowarn("%s: no use record for %s",
4514ca00e00Sroy rtic->name, cap);
4524ca00e00Sroy goto remove;
4534ca00e00Sroy }
454fde317d2Sroy utic = uterm->tic;
4554ca00e00Sroy if (strcmp(utic->name, rtic->name) == 0) {
4564ca00e00Sroy dowarn("%s: uses itself", rtic->name);
4574ca00e00Sroy goto remove;
4584ca00e00Sroy }
4593958d16aSchristos if (_ti_find_extra(utic, &utic->extras, "use")
4603958d16aSchristos != NULL) {
4614ca00e00Sroy skipped++;
4624ca00e00Sroy break;
4634ca00e00Sroy }
4647acb5614Sroy
4657acb5614Sroy /* If we need to merge in a term that requires
4667acb5614Sroy * this term to be promoted, we need to duplicate
4677acb5614Sroy * this term, promote it and append it to our list. */
4687acb5614Sroy if (!promoted && rtic->rtype != TERMINFO_RTYPE) {
4697acb5614Sroy if (promote(rtic, utic) == -1)
4707acb5614Sroy err(EXIT_FAILURE, "promote");
471a3cbce75Schristos promoted = rtic->rtype == TERMINFO_RTYPE;
4727acb5614Sroy }
4737acb5614Sroy
474fde317d2Sroy merge(rtic, utic, flags);
4754ca00e00Sroy remove:
4764ca00e00Sroy /* The pointers may have changed, find the use again */
4773958d16aSchristos cap = _ti_find_extra(rtic, &rtic->extras, "use");
4784ca00e00Sroy if (cap == NULL)
4794ca00e00Sroy dowarn("%s: use no longer exists - impossible",
4804ca00e00Sroy rtic->name);
4814ca00e00Sroy else {
482f73231daSchristos char *scap = __UNCONST(
483f73231daSchristos cap - (4 + sizeof(uint16_t)));
4844ca00e00Sroy cap++;
485f73231daSchristos num = _ti_decode_16(&cap);
486f73231daSchristos cap += num;
4874ca00e00Sroy memn = rtic->extras.bufpos -
4884ca00e00Sroy (cap - rtic->extras.buf);
489ff103979Sroy memmove(scap, cap, memn);
4904ca00e00Sroy rtic->extras.bufpos -= cap - scap;
4914ca00e00Sroy cap = scap;
4924ca00e00Sroy rtic->extras.entries--;
4934ca00e00Sroy merged++;
4944ca00e00Sroy }
4954ca00e00Sroy }
4967acb5614Sroy free(basename);
4974ca00e00Sroy }
4984ca00e00Sroy
4994ca00e00Sroy if (merged == 0 && skipped != 0)
5004ca00e00Sroy dowarn("circular use detected");
5014ca00e00Sroy return merged;
5024ca00e00Sroy }
5034ca00e00Sroy
50455a396b9Sroy static int
print_dump(int argc,char ** argv)50555a396b9Sroy print_dump(int argc, char **argv)
50655a396b9Sroy {
50755a396b9Sroy TERM *term;
508fde317d2Sroy uint8_t *buf;
50955a396b9Sroy int i, n;
51055a396b9Sroy size_t j, col;
511fde317d2Sroy ssize_t len;
51255a396b9Sroy
513b164f98aSroy printf("struct compiled_term {\n");
514b164f98aSroy printf("\tconst char *name;\n");
515b164f98aSroy printf("\tconst char *cap;\n");
516b164f98aSroy printf("\tsize_t caplen;\n");
517b164f98aSroy printf("};\n\n");
51855a396b9Sroy
519b164f98aSroy printf("const struct compiled_term compiled_terms[] = {\n");
520b164f98aSroy
521b164f98aSroy n = 0;
52255a396b9Sroy for (i = 0; i < argc; i++) {
5237acb5614Sroy term = find_newest_term(argv[i]);
52455a396b9Sroy if (term == NULL) {
52555a396b9Sroy warnx("%s: no description for terminal", argv[i]);
52655a396b9Sroy continue;
52755a396b9Sroy }
528fc67b0cdSjoerg if (term->base_term != NULL) {
52955a396b9Sroy warnx("%s: cannot dump alias", argv[i]);
53055a396b9Sroy continue;
53155a396b9Sroy }
532fde317d2Sroy /* Don't compile the aliases in, save space */
533fde317d2Sroy free(term->tic->alias);
534fde317d2Sroy term->tic->alias = NULL;
535fde317d2Sroy len = _ti_flatten(&buf, term->tic);
536fde317d2Sroy if (len == 0 || len == -1)
53755a396b9Sroy continue;
53855a396b9Sroy
539b164f98aSroy printf("\t{\n");
540b164f98aSroy printf("\t\t\"%s\",\n", argv[i]);
54155a396b9Sroy n++;
542fde317d2Sroy for (j = 0, col = 0; j < (size_t)len; j++) {
54355a396b9Sroy if (col == 0) {
544b164f98aSroy printf("\t\t\"");
545b164f98aSroy col = 16;
54655a396b9Sroy }
54755a396b9Sroy
548fde317d2Sroy col += printf("\\%03o", (uint8_t)buf[j]);
54955a396b9Sroy if (col > 75) {
55055a396b9Sroy printf("\"%s\n",
551fde317d2Sroy j + 1 == (size_t)len ? "," : "");
55255a396b9Sroy col = 0;
55355a396b9Sroy }
55455a396b9Sroy }
55555a396b9Sroy if (col != 0)
55655a396b9Sroy printf("\",\n");
557fde317d2Sroy printf("\t\t%zu\n", len);
558b164f98aSroy printf("\t}");
559b164f98aSroy if (i + 1 < argc)
560b164f98aSroy printf(",");
561b164f98aSroy printf("\n");
562fde317d2Sroy free(buf);
56355a396b9Sroy }
564b164f98aSroy printf("};\n");
56555a396b9Sroy
56655a396b9Sroy return n;
56755a396b9Sroy }
56855a396b9Sroy
569fc67b0cdSjoerg static void
write_database(const char * dbname)570fc67b0cdSjoerg write_database(const char *dbname)
571fc67b0cdSjoerg {
572fc67b0cdSjoerg struct cdbw *db;
573fc67b0cdSjoerg char *tmp_dbname;
574fc67b0cdSjoerg TERM *term;
575fc67b0cdSjoerg int fd;
576*98b34193Schristos mode_t m;
577fc67b0cdSjoerg
578fc67b0cdSjoerg db = cdbw_open();
579fc67b0cdSjoerg if (db == NULL)
580d58481dbSroy err(EXIT_FAILURE, "cdbw_open failed");
581fc67b0cdSjoerg /* Save the terms */
582fc67b0cdSjoerg STAILQ_FOREACH(term, &terms, next)
583fc67b0cdSjoerg save_term(db, term);
584fc67b0cdSjoerg
585fc67b0cdSjoerg easprintf(&tmp_dbname, "%s.XXXXXX", dbname);
586fc67b0cdSjoerg fd = mkstemp(tmp_dbname);
587fc67b0cdSjoerg if (fd == -1)
588d58481dbSroy err(EXIT_FAILURE,
589d58481dbSroy "creating temporary database %s failed", tmp_dbname);
590fc67b0cdSjoerg if (cdbw_output(db, fd, "NetBSD terminfo", cdbw_stable_seeder))
591d58481dbSroy err(EXIT_FAILURE,
592d58481dbSroy "writing temporary database %s failed", tmp_dbname);
593*98b34193Schristos m = umask(0);
594*98b34193Schristos (void)umask(m);
595*98b34193Schristos if (fchmod(fd, DEFFILEMODE & ~m))
596d58481dbSroy err(EXIT_FAILURE, "fchmod failed");
597fc67b0cdSjoerg if (close(fd))
598d58481dbSroy err(EXIT_FAILURE,
599d58481dbSroy "writing temporary database %s failed", tmp_dbname);
600fc67b0cdSjoerg if (rename(tmp_dbname, dbname))
601d58481dbSroy err(EXIT_FAILURE, "renaming %s to %s failed", tmp_dbname, dbname);
602fc67b0cdSjoerg free(tmp_dbname);
603fc67b0cdSjoerg cdbw_close(db);
604fc67b0cdSjoerg }
605fc67b0cdSjoerg
6064ca00e00Sroy int
main(int argc,char ** argv)6074ca00e00Sroy main(int argc, char **argv)
6084ca00e00Sroy {
609fde317d2Sroy int ch, cflag, sflag, flags;
610fc67b0cdSjoerg char *source, *dbname, *buf, *ofile;
6114ca00e00Sroy FILE *f;
6127b1c18b0Sjoerg size_t buflen;
6136a222e71Sroy ssize_t len;
6144ca00e00Sroy TBUF tbuf;
61555c5fc25Sroy struct term *term;
6164ca00e00Sroy
6174ca00e00Sroy cflag = sflag = 0;
6184ca00e00Sroy ofile = NULL;
619fde317d2Sroy flags = TIC_ALIAS | TIC_DESCRIPTION | TIC_WARNING;
62055a396b9Sroy while ((ch = getopt(argc, argv, "Saco:sx")) != -1)
6214ca00e00Sroy switch (ch) {
62255a396b9Sroy case 'S':
62355a396b9Sroy Sflag = 1;
624fde317d2Sroy /* We still compile aliases so that use= works.
625fde317d2Sroy * However, it's removed before we flatten to save space. */
626fde317d2Sroy flags &= ~TIC_DESCRIPTION;
62755a396b9Sroy break;
6284ca00e00Sroy case 'a':
629fde317d2Sroy flags |= TIC_COMMENT;
6304ca00e00Sroy break;
6314ca00e00Sroy case 'c':
63271dfbe1cSroy cflag = 1;
6334ca00e00Sroy break;
6344ca00e00Sroy case 'o':
6354ca00e00Sroy ofile = optarg;
6364ca00e00Sroy break;
6374ca00e00Sroy case 's':
63871dfbe1cSroy sflag = 1;
6394ca00e00Sroy break;
6404ca00e00Sroy case 'x':
641fde317d2Sroy flags |= TIC_EXTRA;
6424ca00e00Sroy break;
6434ca00e00Sroy case '?': /* FALLTHROUGH */
6444ca00e00Sroy default:
645b164f98aSroy fprintf(stderr, "usage: %s [-acSsx] [-o file] source\n",
6464ca00e00Sroy getprogname());
6474ca00e00Sroy return EXIT_FAILURE;
6484ca00e00Sroy }
6494ca00e00Sroy
6504ca00e00Sroy if (optind == argc)
6514ca00e00Sroy errx(1, "No source file given");
6524ca00e00Sroy source = argv[optind++];
6534ca00e00Sroy f = fopen(source, "r");
6544ca00e00Sroy if (f == NULL)
655d58481dbSroy err(EXIT_FAILURE, "fopen: %s", source);
6564ca00e00Sroy
6572b5ab407Sjoerg hcreate(HASH_SIZE);
6582b5ab407Sjoerg
65968a65e1aSjoerg buf = tbuf.buf = NULL;
6606a222e71Sroy buflen = tbuf.buflen = tbuf.bufpos = 0;
6616a222e71Sroy while ((len = getline(&buf, &buflen, f)) != -1) {
6624ca00e00Sroy /* Skip comments */
6634ca00e00Sroy if (*buf == '#')
6644ca00e00Sroy continue;
6656a222e71Sroy if (buf[len - 1] != '\n') {
666fde317d2Sroy process_entry(&tbuf, flags);
6674ca00e00Sroy dowarn("last line is not a comment"
6684ca00e00Sroy " and does not end with a newline");
6694ca00e00Sroy continue;
6704ca00e00Sroy }
6714ca00e00Sroy /*
672e04b9c57Sroy * If the first char is space not a space then we have a
673e04b9c57Sroy * new entry, so process it.
6744ca00e00Sroy */
6754ca00e00Sroy if (!isspace((unsigned char)*buf) && tbuf.bufpos != 0)
676fde317d2Sroy process_entry(&tbuf, flags);
6774ca00e00Sroy
6784ca00e00Sroy /* Grow the buffer if needed */
6796a222e71Sroy grow_tbuf(&tbuf, len);
6804ca00e00Sroy /* Append the string */
6816a222e71Sroy memcpy(tbuf.buf + tbuf.bufpos, buf, len);
6826a222e71Sroy tbuf.bufpos += len;
6834ca00e00Sroy }
68468a65e1aSjoerg free(buf);
6854ca00e00Sroy /* Process the last entry if not done already */
686fde317d2Sroy process_entry(&tbuf, flags);
68768a65e1aSjoerg free(tbuf.buf);
6884ca00e00Sroy
6894ca00e00Sroy /* Merge use entries until we have merged all we can */
690fde317d2Sroy while (merge_use(flags) != 0)
6914ca00e00Sroy ;
6924ca00e00Sroy
693b164f98aSroy if (Sflag) {
69455a396b9Sroy print_dump(argc - optind, argv + optind);
69555a396b9Sroy return error_exit;
69655a396b9Sroy }
69755a396b9Sroy
698b164f98aSroy if (cflag)
6994ca00e00Sroy return error_exit;
7004ca00e00Sroy
701fc67b0cdSjoerg if (ofile == NULL)
702fc67b0cdSjoerg easprintf(&dbname, "%s.cdb", source);
703fc67b0cdSjoerg else
704fc67b0cdSjoerg dbname = ofile;
705fc67b0cdSjoerg write_database(dbname);
7064ca00e00Sroy
7074ca00e00Sroy if (sflag != 0)
7084ca00e00Sroy fprintf(stderr, "%zu entries and %zu aliases written to %s\n",
709fc67b0cdSjoerg nterm, nalias, dbname);
7104ca00e00Sroy
711fc67b0cdSjoerg if (ofile == NULL)
712fc67b0cdSjoerg free(dbname);
713fc67b0cdSjoerg while ((term = STAILQ_FIRST(&terms)) != NULL) {
714fc67b0cdSjoerg STAILQ_REMOVE_HEAD(&terms, next);
71568a65e1aSjoerg _ti_freetic(term->tic);
71668a65e1aSjoerg free(term->name);
71768a65e1aSjoerg free(term);
71868a65e1aSjoerg }
7199a21bc93Schristos #ifndef HAVE_NBTOOL_CONFIG_H
7209a21bc93Schristos /*
7219a21bc93Schristos * hdestroy1 is not standard but we don't really care if we
7229a21bc93Schristos * leak in the tools version
7239a21bc93Schristos */
724ed61af43Schristos hdestroy1(free, NULL);
7259a21bc93Schristos #endif
72668a65e1aSjoerg
7274ca00e00Sroy return EXIT_SUCCESS;
7284ca00e00Sroy }
729