diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index 3ed14aff4..ea2d81068 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -253,6 +253,7 @@ ./usr/bin/ifconfig minix-sys ./usr/bin/ifdef minix-sys ./usr/bin/indent minix-sys +./usr/bin/infocmp minix-sys ./usr/bin/in.fingerd minix-sys ./usr/bin/in.rshd minix-sys ./usr/bin/install minix-sys @@ -1222,6 +1223,7 @@ ./usr/man/man1/if.1 minix-sys ./usr/man/man1/ifdef.1 minix-sys ./usr/man/man1/indent.1 minix-sys +./usr/man/man1/infocmp.1 minix-sys ./usr/man/man1/install.1 minix-sys ./usr/man/man1/isodir.1 minix-sys ./usr/man/man1/isoinfo.1 minix-sys diff --git a/releasetools/nbsd_ports b/releasetools/nbsd_ports index aacdb457c..167cce6af 100644 --- a/releasetools/nbsd_ports +++ b/releasetools/nbsd_ports @@ -121,6 +121,7 @@ 2012/10/17 12:00:00,usr.bin/genassym 2012/10/17 12:00:00,usr.bin/gzip 2012/10/17 12:00:00,usr.bin/indent +2012/10/17 12:00:00,usr.bin/infocmp 2012/10/17 12:00:00,usr.bin/join 2011/01/17 18:11:10,usr.bin/ldd 2012/02/10 16:16:12,usr.bin/login diff --git a/usr.bin/Makefile b/usr.bin/Makefile index d720f8218..8d8899612 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -12,7 +12,7 @@ SUBDIR= \ \ \ genassym \ - indent join \ + indent infocmp join \ ldd \ login lorder m4 \ make man \ diff --git a/usr.bin/infocmp/Makefile b/usr.bin/infocmp/Makefile new file mode 100644 index 000000000..f2b5a4cb0 --- /dev/null +++ b/usr.bin/infocmp/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.1 2010/02/03 15:16:33 roy Exp $ + +PROG= infocmp +WARNS= 4 + +CPPFLAGS+= -I${.CURDIR}/../../lib/libterminfo +LDADD+= -lterminfo +DPADD+= ${LIBTERMINFO} + +.include diff --git a/usr.bin/infocmp/infocmp.1 b/usr.bin/infocmp/infocmp.1 new file mode 100644 index 000000000..10132cf01 --- /dev/null +++ b/usr.bin/infocmp/infocmp.1 @@ -0,0 +1,131 @@ +.\" $NetBSD: infocmp.1,v 1.5 2011/01/14 14:21:36 wiz Exp $ +.\" +.\" Copyright (c) 2009 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Roy Marples. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd February 5, 2010 +.Dt INFOCMP 1 +.Os +.Sh NAME +.Nm infocmp +.Nd compare or print compiled terminfo descriptions +.Sh SYNOPSIS +.Nm infocmp +.Op Fl 1acnqux +.Op Fl A Ar database +.Op Fl B Ar database +.Op Fl w Ar cols +.Op Ar term ... +.Sh DESCRIPTION +The +.Nm +reconstructs the first available +.Xr terminfo 5 +definition found for +.Ar term +and prints the result in a +.Xr terminfo 5 +format. +Capability types are grouped together and new types start new lines, +first flags, then numbers, then strings. +Capabilities are sorted by their name. +If a second +.Ar term +is given then the capabilities are compared against each other. +.Pp +The following options are available: +.Bl -tag -width Ev +.It Fl 1 +Print one capability per line. +.It Fl A Ar database +Use this database to load the first terminal definition. +.It Fl B Ar database +Use this database to load subsequent terminal definitions. +.It Fl a +Include commented out capabilities. +This only works if the database was compiled with the +.Fl a +flag passed to +.Xr tic 1 . +This also sets the +.Fl x +flag as +.Nm +retains commented out capabilities as non standard. +.It Fl c +Print capabilities common to each definition. +.It Fl n +Print capabilities that do not exist in either definition. +.It Fl q +Make the comparison listing shorter by omitting subheadings and using +- for absent capabilities, @ for canceled capabilities rather than +.Dv NULL . +.It Fl u +Build a new terminal description for the first terminal description, +using subsequent terminal descriptions. +This also sets the +.Fl a +flag. +.It Fl w Ar cols +Limit the width to +.Ar cols . +.It Fl x +Include non-standard capabilities. +More +.Fl x +only handles non-standard capabilities. +This only works if the database was compiled with the +.Fl x +flag passed to +.Xr tic 1 . +.El +.Sh ENVIRONMENT +.Bl -tag -width Ev +.It Ev COLUMNS +Override columns returned by the output terminal. +.Fl w +.Ar cols +supersedes this. +.It Ev TERM +.Nm +uses the contents of the +.Ev TERM +environment variable if no terminal name is given on the command line. +.El +.Sh EXIT STATUS +.Ex -std infocmp +.Sh SEE ALSO +.Xr tic 1 , +.Xr terminfo 5 +.Sh STANDARDS +The +.Nm +utility outputs information that conforms to the +.St -xcurses4.2 +standard. +.Sh AUTHORS +.An Roy Marples Aq roy@NetBSD.org diff --git a/usr.bin/infocmp/infocmp.c b/usr.bin/infocmp/infocmp.c new file mode 100644 index 000000000..581708e04 --- /dev/null +++ b/usr.bin/infocmp/infocmp.c @@ -0,0 +1,795 @@ +/* $NetBSD: infocmp.c,v 1.7 2010/02/22 23:05:39 roy Exp $ */ + +/* + * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Roy Marples. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__RCSID("$NetBSD: infocmp.c,v 1.7 2010/02/22 23:05:39 roy Exp $"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Specifically needed on MINIX, as struct winsize in not defined elsewhere */ +#include + +#define SW 8 + +typedef struct tient { + char type; + const char *id; + signed char flag; + short num; + const char *str; +} TIENT; + +static size_t cols; +static int aflag, cflag, nflag, qflag, xflag; + +static size_t +outstr(FILE *f, const char *str) +{ + unsigned char ch; + size_t r, l; + + r = 0; + l = strlen(str); + while ((ch = (unsigned char)(*str++)) != '\0') { + switch (ch) { + case 128: + ch = '0'; + break; + case '\033': + ch = 'E'; + break; + case '\014': + ch = 'f'; + break; + case '^': /* FALLTHROUGH */ + case ',': /* escape these */ + break; + case ' ': + ch = 's'; + break; + default: + if (ch == '\177') { + if (f != NULL) + fputc('^', f); + ch = '?'; + r++; + } else if (iscntrl(ch) && + ch < 128 && + ch != '\\' && + (l < 4 || isdigit((unsigned char)*str))) + { + if (f != NULL) + fputc('^', f); + ch += '@'; + r++; + } else if (!isprint(ch)) { + if (f != NULL) + fprintf(f, "\\%03o", ch); + r += 4; + continue; + } + goto prnt; + } + + if (f != NULL) + fputc('\\', f); + r++; +prnt: + if (f != NULL) + fputc(ch, f); + r++; + } + return r; +} + +static int +ent_compare(const void *a, const void *b) +{ + const TIENT *ta, *tb; + + ta = (const TIENT *)a; + tb = (const TIENT *)b; + return strcmp(ta->id, tb->id); +} + +static void +setdb(char *db) +{ + size_t len; + + len = strlen(db); + if (len > 3 && + db[len - 3] == '.' && + db[len - 2] == 'd' && + db[len - 1] == 'b') + db[len - 3] = '\0'; + setenv("TERMINFO", db, 1); +} + +static void +print_ent(const TIENT *ents, size_t nents) +{ + size_t col, i, l; + char nbuf[64]; + + if (nents == 0) + return; + + col = SW; + printf("\t"); + for (i = 0; i < nents; i++) { + if (*ents[i].id == '.' && aflag == 0) + continue; + switch (ents[i].type) { + case 'f': + if (ents[i].flag == ABSENT_BOOLEAN) + continue; + l = strlen(ents[i].id) + 2; + if (ents[i].flag == CANCELLED_BOOLEAN) + l++; + break; + case 'n': + if (ents[i].num == ABSENT_NUMERIC) + continue; + if (VALID_NUMERIC(ents[i].num)) + l = snprintf(nbuf, sizeof(nbuf), "%s#%d,", + ents[i].id, ents[i].num); + else + l = snprintf(nbuf, sizeof(nbuf), "%s@,", + ents[i].id); + break; + case 's': + if (ents[i].str == ABSENT_STRING) + continue; + if (VALID_STRING(ents[i].str)) + l = strlen(ents[i].id) + + outstr(NULL, ents[i].str) + 7; + else + l = strlen(ents[i].id) + 3; + break; + default: + errx(1, "invalid type"); + } + if (col != SW) { + if (col + l > cols) { + printf("\n\t"); + col = SW; + } else + col += printf(" "); + } + switch (ents[i].type) { + case 'f': + col += printf("%s", ents[i].id); + if (ents[i].flag == ABSENT_BOOLEAN || + ents[i].flag == CANCELLED_BOOLEAN) + col += printf("@"); + col += printf(","); + break; + case 'n': + col += printf("%s", nbuf); + break; + case 's': + col += printf("%s", ents[i].id); + if (VALID_STRING(ents[i].str)) { + col += printf("="); + col += outstr(stdout, ents[i].str); + } else + col += printf("@"); + col += printf(","); + break; + } + } + printf("\n"); +} + +static size_t +load_ents(TIENT *ents, TERMINAL *t, char type) +{ + size_t i, n, max; + TERMUSERDEF *ud; + + switch (type) { + case 'f': + max = TIFLAGMAX; + break; + case 'n': + max = TINUMMAX; + break; + default: + max = TISTRMAX; + } + + n = 0; + for (i = 0; i <= max; i++) { + switch (type) { + case 'f': + if (t->flags[i] == 1 || + (aflag && t->flags[i] == CANCELLED_BOOLEAN)) + { + ents[n].id = _ti_flagid(i); + ents[n].type = 'f'; + ents[n++].flag = t->flags[i]; + } + break; + case 'n': + if (VALID_NUMERIC(t->nums[i]) || + (aflag && t->nums[i] == CANCELLED_NUMERIC)) + { + ents[n].id = _ti_numid(i); + ents[n].type = 'n'; + ents[n++].num = t->nums[i]; + } + break; + default: + if (VALID_STRING(t->strs[i]) || + (aflag && t->strs[i] == CANCELLED_STRING)) + { + ents[n].id = _ti_strid(i); + ents[n].type = 's'; + ents[n++].str = t->strs[i]; + } + break; + } + } + + if (xflag != 0 && t->_nuserdefs != 0) { + for (i = 0; i < t->_nuserdefs; i++) { + ud = &t->_userdefs[i]; + if (ud->type == type) { + switch (type) { + case 'f': + if (!aflag && + !VALID_BOOLEAN(ud->flag)) + continue; + break; + case 'n': + if (!aflag && + !VALID_NUMERIC(ud->num)) + continue; + break; + case 's': + if (!aflag && + !VALID_STRING(ud->str)) + continue; + break; + } + ents[n].id = ud->id; + ents[n].type = ud->type; + ents[n].flag = ud->flag; + ents[n].num = ud->num; + ents[n++].str = ud->str; + } + } + } + + qsort(ents, n, sizeof(TIENT), ent_compare); + return n; +} + +static void +cprint_ent(TIENT *ent) +{ + + if (ent == NULL) { + if (qflag == 0) + printf("NULL"); + else + printf("-"); + } + + switch (ent->type) { + case 'f': + if (VALID_BOOLEAN(ent->flag)) + printf(ent->flag == 1 ? "T" : "F"); + else if (qflag == 0) + printf("F"); + else if (ent->flag == CANCELLED_BOOLEAN) + printf("@"); + else + printf("-"); + break; + case 'n': + if (VALID_NUMERIC(ent->num)) + printf("%d", ent->num); + else if (qflag == 0) + printf("NULL"); + else if (ent->num == CANCELLED_NUMERIC) + printf("@"); + else + printf("-"); + break; + case 's': + if (VALID_STRING(ent->str)) { + printf("'"); + outstr(stdout, ent->str); + printf("'"); + } else if (qflag == 0) + printf("NULL"); + else if (ent->str == CANCELLED_STRING) + printf("@"); + else + printf("-"); + break; + } +} + +static void +compare_ents(TIENT *ents1, size_t n1, TIENT *ents2, size_t n2) +{ + size_t i1, i2; + TIENT *e1, *e2, ee; + int c; + + i1 = i2 = 0; + ee.type = 'f'; + ee.flag = ABSENT_BOOLEAN; + ee.num = ABSENT_NUMERIC; + ee.str = ABSENT_STRING; + while (i1 != n1 || i2 != n2) { + if (i1 == n1) + c = 1; + else if (i2 == n2) + c = -1; + else + c = strcmp(ents1[i1].id, ents2[i2].id); + if (c == 0) { + e1 = &ents1[i1++]; + e2 = &ents2[i2++]; + } else if (c < 0) { + e1 = &ents1[i1++]; + e2 = ⅇ + ee.id = e1->id; + ee.type = e1->type; + } else { + e1 = ⅇ + e2 = &ents2[i2++]; + ee.id = e2->id; + ee.type = e2->type; + } + switch (e1->type) { + case 'f': + if (cflag != 0) { + if (e1->flag == e2->flag) + printf("\t%s\n", ents1[i1].id); + continue; + } + if (e1->flag == e2->flag) + continue; + break; + case 'n': + if (cflag != 0) { + if (e1->num == e2->num) + printf("\t%s#%d\n", + ents1[i1].id, ents1[i1].num); + continue; + } + if (e1->num == e2->num) + continue; + break; + case 's': + if (cflag != 0) { + if (VALID_STRING(e1->str) && + VALID_STRING(e2->str) && + strcmp(e1->str, e2->str) == 0) { + printf("\t%s=", ents1[i1].id); + outstr(stdout, ents1[i1].str); + printf("\n"); + } + continue; + } + if (VALID_STRING(e1->str) && + VALID_STRING(e2->str) && + strcmp(e1->str, e2->str) == 0) + continue; + break; + } + printf("\t%s: ", e1->id); + cprint_ent(e1); + if (e1->type == 'f') + printf(":"); + else + printf(", "); + cprint_ent(e2); + printf(".\n"); + } +} + +static TERMINAL * +load_term(const char *name) +{ + TERMINAL *t; + + t = calloc(1, sizeof(*t)); + if (t == NULL) + err(1, "calloc"); + if (name == NULL) + name = getenv("TERM"); + if (name == NULL) + name = "dumb"; + if (_ti_getterm(t, name, 1) == 1) + return t; + + if (_ti_database == NULL) + errx(1, "no terminal definition found in internal database"); + else + errx(1, "no terminal definition found in %s.db", _ti_database); +} + +static void +show_missing(TERMINAL *t1, TERMINAL *t2, char type) +{ + ssize_t i, max; + const char *id; + + switch (type) { + case 'f': + max = TIFLAGMAX; + break; + case 'n': + max = TINUMMAX; + break; + default: + max = TISTRMAX; + } + + for (i = 0; i <= max; i++) { + switch (type) { + case 'f': + if (t1->flags[i] != ABSENT_BOOLEAN || + t2->flags[i] != ABSENT_BOOLEAN) + continue; + id = _ti_flagid(i); + break; + case 'n': + if (t1->nums[i] != ABSENT_NUMERIC || + t2->nums[i] != ABSENT_NUMERIC) + continue; + id = _ti_numid(i); + break; + default: + if (t1->strs[i] != ABSENT_STRING || + t2->strs[i] != ABSENT_STRING) + continue; + id = _ti_strid(i); + break; + } + printf("\t!%s.\n", id); + } +} + +static TERMUSERDEF * +find_userdef(TERMINAL *term, const char *id) +{ + size_t i; + + for (i = 0; i < term->_nuserdefs; i++) + if (strcmp(term->_userdefs[i].id, id) == 0) + return &term->_userdefs[i]; + return NULL; +} + +static void +use_terms(TERMINAL *term, size_t nuse, char **uterms) +{ + TERMINAL **terms; + TERMUSERDEF *ud, *tud; + size_t i, j, agree, absent, data; + + terms = malloc(sizeof(**terms) * nuse); + if (terms == NULL) + err(1, "malloc"); + for (i = 0; i < nuse; i++) { + if (strcmp(term->name, *uterms) == 0) + errx(1, "cannot use same terminal"); + for (j = 0; j < i; j++) + if (strcmp(terms[j]->name, *uterms) == 0) + errx(1, "cannot use same terminal"); + terms[i] = load_term(*uterms++); + } + + for (i = 0; i < TIFLAGMAX + 1; i++) { + agree = absent = data = 0; + for (j = 0; j < nuse; j++) { + if (terms[j]->flags[i] == ABSENT_BOOLEAN || + terms[j]->flags[i] == CANCELLED_BOOLEAN) + absent++; + else { + data++; + if (term->flags[i] == terms[j]->flags[i]) + agree++; + } + } + if (data == 0) + continue; + if (agree > 0 && agree + absent == nuse) + term->flags[i] = ABSENT_BOOLEAN; + else if (term->flags[i] == ABSENT_BOOLEAN) + term->flags[i] = CANCELLED_BOOLEAN; + } + + for (i = 0; i < TINUMMAX + 1; i++) { + agree = absent = data = 0; + for (j = 0; j < nuse; j++) { + if (terms[j]->nums[i] == ABSENT_NUMERIC || + terms[j]->nums[i] == CANCELLED_NUMERIC) + absent++; + else { + data++; + if (term->nums[i] == terms[j]->nums[i]) + agree++; + } + } + if (data == 0) + continue; + if (agree > 0 && agree + absent == nuse) + term->nums[i] = ABSENT_NUMERIC; + else if (term->nums[i] == ABSENT_NUMERIC) + term->nums[i] = CANCELLED_NUMERIC; + } + + for (i = 0; i < TISTRMAX + 1; i++) { + agree = absent = data = 0; + for (j = 0; j < nuse; j++) { + if (terms[j]->strs[i] == ABSENT_STRING || + terms[j]->strs[i] == CANCELLED_STRING) + absent++; + else { + data++; + if (VALID_STRING(term->strs[i]) && + strcmp(term->strs[i], + terms[j]->strs[i]) == 0) + agree++; + } + } + if (data == 0) + continue; + if (agree > 0 && agree + absent == nuse) + term->strs[i] = ABSENT_STRING; + else if (term->strs[i] == ABSENT_STRING) + term->strs[i] = CANCELLED_STRING; + } + + /* User defined caps are more tricky. + First we set any to absent that agree. */ + for (i = 0; i < term->_nuserdefs; i++) { + agree = absent = data = 0; + ud = &term->_userdefs[i]; + for (j = 0; j < nuse; j++) { + tud = find_userdef(terms[j], ud->id); + if (tud == NULL) + absent++; + else { + data++; + switch (ud->type) { + case 'f': + if (tud->type == 'f' && + tud->flag == ud->flag) + agree++; + break; + case 'n': + if (tud->type == 'n' && + tud->num == ud->num) + agree++; + break; + case 's': + if (tud->type == 's' && + VALID_STRING(tud->str) && + VALID_STRING(ud->str) && + strcmp(ud->str, tud->str) == 0) + agree++; + break; + } + } + } + if (data == 0) + continue; + if (agree > 0 && agree + absent == nuse) { + ud->flag = ABSENT_BOOLEAN; + ud->num = ABSENT_NUMERIC; + ud->str = ABSENT_STRING; + } + } + + /* Now add any that we don't have as cancelled */ + for (i = 0; i < nuse; i++) { + for (j = 0; j < terms[i]->_nuserdefs; j++) { + ud = find_userdef(term, terms[i]->_userdefs[j].id); + if (ud != NULL) + continue; /* We have handled this */ + term->_userdefs = realloc(term->_userdefs, + sizeof(*term->_userdefs) * (term->_nuserdefs + 1)); + if (term->_userdefs == NULL) + err(1, "malloc"); + tud = &term->_userdefs[term->_nuserdefs++]; + tud->id = terms[i]->_userdefs[j].id; + tud->type = terms[i]->_userdefs[j].flag; + tud->flag = CANCELLED_BOOLEAN; + tud->num = CANCELLED_NUMERIC; + tud->str = CANCELLED_STRING; + } + } +} + +int +main(int argc, char **argv) +{ + char *term, *Barg; + int ch, uflag; + TERMINAL *t, *t2; + size_t n, n2; + struct winsize ws; + TIENT ents[TISTRMAX + 1], ents2[TISTRMAX + 1]; + + cols = 80; /* default */ + term = getenv("COLUMNS"); + if (term != NULL) + cols = strtoul(term, NULL, 10); + else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0) + cols = ws.ws_col; + + uflag = xflag = 0; + Barg = NULL; + while ((ch = getopt(argc, argv, "1A:B:acnquw:x")) != -1) + switch (ch) { + case '1': + cols = 1; + break; + case 'A': + setdb(optarg); + break; + case 'B': + Barg = optarg; + break; + case 'a': + aflag = 1; + break; + case 'c': + cflag = 1; + break; + case 'n': + nflag = 1; + break; + case 'q': + qflag = 1; + break; + case 'u': + uflag = 1; + aflag = 1; + break; + case 'w': + cols = strtoul(optarg, NULL, 10); + break; + case 'x': + xflag = 1; + break; + case '?': + default: + fprintf(stderr, + "usage: %s [-1acnqux] [-A database] [-B database] " + "[-w cols] [term]\n", + getprogname()); + return EXIT_FAILURE; + } + cols--; + + if (optind + 1 < argc) + aflag = 1; + + if (optind < argc) + term = argv[optind++]; + else + term = NULL; + t = load_term(term); + + if (uflag != 0) + use_terms(t, argc - optind, argv + optind); + + if ((optind + 1 != argc && nflag == 0) || uflag != 0) { + if (uflag == 0) { + printf("# Reconstructed from "); + if (_ti_database == NULL) + printf("internal database\n"); + else + printf("%s%s\n", _ti_database, + *_ti_database == '/' ? ".db" : ""); + } + printf("%s", t->name); + if (t->_alias != NULL && *t->_alias != '\0') + printf("|%s", t->_alias); + if (t->desc != NULL && *t->desc != '\0') + printf("|%s", t->desc); + printf(",\n"); + + n = load_ents(ents, t, 'f'); + print_ent(ents, n); + n = load_ents(ents, t, 'n'); + print_ent(ents, n); + n = load_ents(ents, t, 's'); + print_ent(ents, n); + + if (uflag != 0) { + printf("\t"); + n = SW; + for (; optind < argc; optind++) { + n2 = 5 + strlen(argv[optind]); + if (n != SW) { + if (n + n2 > cols) { + printf("\n\t"); + n = SW; + } else + n += printf(" "); + } + n += printf("use=%s,", argv[optind]); + } + printf("\n"); + } + return EXIT_SUCCESS; + } + + if (Barg == NULL) + unsetenv("TERMINFO"); + else + setdb(Barg); + t2 = load_term(argv[optind++]); + printf("comparing %s to %s.\n", t->name, t2->name); + if (qflag == 0) + printf(" comparing booleans.\n"); + if (nflag == 0) { + n = load_ents(ents, t, 'f'); + n2 = load_ents(ents2, t2, 'f'); + compare_ents(ents, n, ents2, n2); + } else + show_missing(t, t2, 'f'); + if (qflag == 0) + printf(" comparing numbers.\n"); + if (nflag == 0) { + n = load_ents(ents, t, 'n'); + n2 = load_ents(ents2, t2, 'n'); + compare_ents(ents, n, ents2, n2); + } else + show_missing(t, t2, 'n'); + if (qflag == 0) + printf(" comparing strings.\n"); + if (nflag == 0) { + n = load_ents(ents, t, 's'); + n2 = load_ents(ents2, t2, 's'); + compare_ents(ents, n, ents2, n2); + } else + show_missing(t, t2, 's'); + return EXIT_SUCCESS; +}