version 1.8, 2000/01/16 01:35:19 |
version 1.9, 2000/03/13 23:53:41 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
|
|
/**************************************************************************** |
/**************************************************************************** |
* Copyright (c) 1998-2000 Free Software Foundation, Inc. * |
* Copyright (c) 1998,1999,2000 Free Software Foundation, Inc. * |
* * |
* * |
* Permission is hereby granted, free of charge, to any person obtaining a * |
* Permission is hereby granted, free of charge, to any person obtaining a * |
* copy of this software and associated documentation files (the * |
* copy of this software and associated documentation files (the * |
|
|
#include <term_entry.h> |
#include <term_entry.h> |
#include <dump_entry.h> |
#include <dump_entry.h> |
|
|
MODULE_ID("$From: infocmp.c,v 1.48 2000/01/15 22:46:12 tom Exp $") |
MODULE_ID("$From: infocmp.c,v 1.52 2000/03/12 02:34:09 tom Exp $") |
|
|
#define L_CURL "{" |
#define L_CURL "{" |
#define R_CURL "}" |
#define R_CURL "}" |
|
|
#define MAXTERMS 32 /* max # terminal arguments we can handle */ |
#define MAXTERMS 32 /* max # terminal arguments we can handle */ |
|
#define MAX_STRING 1024 /* maximum formatted string */ |
|
|
const char *_nc_progname = "infocmp"; |
const char *_nc_progname = "infocmp"; |
|
|
|
|
***************************************************************************/ |
***************************************************************************/ |
|
|
static char *tname[MAXTERMS]; /* terminal type names */ |
static char *tname[MAXTERMS]; /* terminal type names */ |
static TERMTYPE term[MAXTERMS]; /* terminfo entries */ |
static ENTRY entries[MAXTERMS]; /* terminfo entries */ |
static int termcount; /* count of terminal entries */ |
static int termcount; /* count of terminal entries */ |
|
|
|
static bool limited = TRUE; /* "-r" option is not set */ |
|
static bool quiet = FALSE; |
|
static char *bool_sep = ":"; |
|
static char *s_absent = "NULL"; |
|
static char *s_cancel = "NULL"; |
static const char *tversion; /* terminfo version selected */ |
static const char *tversion; /* terminfo version selected */ |
static int numbers = 0; /* format "%'char'" to/from "%{number}" */ |
|
static int outform = F_TERMINFO; /* output format */ |
|
static int sortmode; /* sort_mode */ |
|
static int itrace; /* trace flag for debugging */ |
static int itrace; /* trace flag for debugging */ |
static int mwidth = 60; |
static int mwidth = 60; |
|
static int numbers = 0; /* format "%'char'" to/from "%{number}" */ |
|
static int outform = F_TERMINFO;/* output format */ |
|
static int sortmode; /* sort_mode */ |
|
|
/* main comparison mode */ |
/* main comparison mode */ |
static int compare; |
static int compare; |
|
|
ExitProgram(int code) |
ExitProgram(int code) |
{ |
{ |
while (termcount-- > 0) |
while (termcount-- > 0) |
_nc_free_termtype(&term[termcount]); |
_nc_free_termtype(&entries[termcount].tterm); |
_nc_leaks_dump_entry(); |
_nc_leaks_dump_entry(); |
_nc_free_and_exit(code); |
_nc_free_and_exit(code); |
} |
} |
|
|
char *bp; |
char *bp; |
|
|
(void) strcpy(buf, ptr); |
(void) strcpy(buf, ptr); |
if ((bp = strchr(buf, '|')) != (char *) NULL) |
if ((bp = strchr(buf, '|')) != 0) |
*bp = '\0'; |
*bp = '\0'; |
|
|
return (buf); |
return (buf); |
|
|
***************************************************************************/ |
***************************************************************************/ |
|
|
static int |
static int |
capcmp(const char *s, const char *t) |
capcmp(int idx, const char *s, const char *t) |
/* capability comparison function */ |
/* capability comparison function */ |
{ |
{ |
if (!VALID_STRING(s) && !VALID_STRING(t)) |
if (!VALID_STRING(s) && !VALID_STRING(t)) |
return (0); |
return (s != t); |
else if (!VALID_STRING(s) || !VALID_STRING(t)) |
else if (!VALID_STRING(s) || !VALID_STRING(t)) |
return (1); |
return (1); |
|
|
if (ignorepads) |
if ((idx == acs_chars_index) || !ignorepads) |
return (_nc_capcmp(s, t)); |
|
else |
|
return (strcmp(s, t)); |
return (strcmp(s, t)); |
|
else |
|
return (_nc_capcmp(s, t)); |
} |
} |
|
|
static int |
static int |
use_predicate(int type, int idx) |
use_predicate(int type, int idx) |
/* predicate function to use for use decompilation */ |
/* predicate function to use for use decompilation */ |
{ |
{ |
TERMTYPE *tp; |
ENTRY *ep; |
|
|
switch (type) { |
switch (type) { |
case BOOLEAN:{ |
case BOOLEAN: |
|
{ |
int is_set = FALSE; |
int is_set = FALSE; |
|
|
/* |
/* |
|
|
* This is true if we take the semantics of multiple uses to |
* This is true if we take the semantics of multiple uses to |
* be 'each capability gets the first non-default value found |
* be 'each capability gets the first non-default value found |
* in the sequence of use entries'. |
* in the sequence of use entries'. |
|
* |
|
* Note that cancelled or absent booleans are stored as FALSE, |
|
* unlike numbers and strings, whose cancelled/absent state is |
|
* recorded in the terminfo database. |
*/ |
*/ |
for (tp = &term[1]; tp < term + termcount; tp++) |
for (ep = &entries[1]; ep < entries + termcount; ep++) |
if (tp->Booleans[idx]) { |
if (ep->tterm.Booleans[idx] == TRUE) { |
is_set = TRUE; |
is_set = entries[0].tterm.Booleans[idx]; |
break; |
break; |
} |
} |
if (is_set != term->Booleans[idx]) |
if (is_set != entries[0].tterm.Booleans[idx]) |
return (!is_set); |
return (!is_set); |
else |
else |
return (FAIL); |
return (FAIL); |
} |
} |
|
|
case NUMBER:{ |
case NUMBER: |
|
{ |
int value = ABSENT_NUMERIC; |
int value = ABSENT_NUMERIC; |
|
|
/* |
/* |
|
|
* capability gets the first non-default value found |
* capability gets the first non-default value found |
* in the sequence of use entries'. |
* in the sequence of use entries'. |
*/ |
*/ |
for (tp = &term[1]; tp < term + termcount; tp++) |
for (ep = &entries[1]; ep < entries + termcount; ep++) |
if (tp->Numbers[idx] >= 0) { |
if (VALID_NUMERIC(ep->tterm.Numbers[idx])) { |
value = tp->Numbers[idx]; |
value = ep->tterm.Numbers[idx]; |
break; |
break; |
} |
} |
|
|
if (value != term->Numbers[idx]) |
if (value != entries[0].tterm.Numbers[idx]) |
return (value != ABSENT_NUMERIC); |
return (value != ABSENT_NUMERIC); |
else |
else |
return (FAIL); |
return (FAIL); |
} |
} |
|
|
case STRING:{ |
case STRING: |
|
{ |
char *termstr, *usestr = ABSENT_STRING; |
char *termstr, *usestr = ABSENT_STRING; |
|
|
termstr = term->Strings[idx]; |
termstr = entries[0].tterm.Strings[idx]; |
|
|
/* |
/* |
* We take the semantics of multiple uses to be 'each |
* We take the semantics of multiple uses to be 'each |
* capability gets the first non-default value found |
* capability gets the first non-default value found |
* in the sequence of use entries'. |
* in the sequence of use entries'. |
*/ |
*/ |
for (tp = &term[1]; tp < term + termcount; tp++) |
for (ep = &entries[1]; ep < entries + termcount; ep++) |
if (tp->Strings[idx]) { |
if (ep->tterm.Strings[idx]) { |
usestr = tp->Strings[idx]; |
usestr = ep->tterm.Strings[idx]; |
break; |
break; |
} |
} |
|
|
if (usestr == ABSENT_STRING && termstr == ABSENT_STRING) |
if (usestr == ABSENT_STRING && termstr == ABSENT_STRING) |
return (FAIL); |
return (FAIL); |
else if (!usestr || !termstr || capcmp(usestr, termstr)) |
else if (!usestr || !termstr || capcmp(idx, usestr, termstr)) |
return (TRUE); |
return (TRUE); |
else |
else |
return (FAIL); |
return (FAIL); |
|
|
} |
} |
|
|
static bool |
static bool |
|
useeq(ENTRY * e1, ENTRY * e2) |
|
/* are the use references in two entries equivalent? */ |
|
{ |
|
int i, j; |
|
|
|
if (e1->nuses != e2->nuses) |
|
return (FALSE); |
|
|
|
/* Ugh...this is quadratic again */ |
|
for (i = 0; i < e1->nuses; i++) { |
|
bool foundmatch = FALSE; |
|
|
|
/* search second entry for given use reference */ |
|
for (j = 0; j < e2->nuses; j++) |
|
if (!strcmp(e1->uses[i].name, e2->uses[j].name)) { |
|
foundmatch = TRUE; |
|
break; |
|
} |
|
|
|
if (!foundmatch) |
|
return (FALSE); |
|
} |
|
|
|
return (TRUE); |
|
} |
|
|
|
static bool |
entryeq(TERMTYPE * t1, TERMTYPE * t2) |
entryeq(TERMTYPE * t1, TERMTYPE * t2) |
/* are two terminal types equal */ |
/* are two entries equivalent? */ |
{ |
{ |
int i; |
int i; |
|
|
|
|
return (FALSE); |
return (FALSE); |
|
|
for (i = 0; i < NUM_STRINGS(t1); i++) |
for (i = 0; i < NUM_STRINGS(t1); i++) |
if (capcmp(t1->Strings[i], t2->Strings[i])) |
if (capcmp(i, t1->Strings[i], t2->Strings[i])) |
return (FALSE); |
return (FALSE); |
|
|
return (TRUE); |
return (TRUE); |
|
|
#define TIC_EXPAND(result) _nc_tic_expand(result, outform==F_TERMINFO, numbers) |
#define TIC_EXPAND(result) _nc_tic_expand(result, outform==F_TERMINFO, numbers) |
|
|
static void |
static void |
|
print_uses(ENTRY * ep, FILE * fp) |
|
/* print an entry's use references */ |
|
{ |
|
int i; |
|
|
|
if (!ep->nuses) |
|
fputs("NULL", fp); |
|
else |
|
for (i = 0; i < ep->nuses; i++) { |
|
fputs(ep->uses[i].name, fp); |
|
if (i < ep->nuses - 1) |
|
fputs(" ", fp); |
|
} |
|
} |
|
|
|
static char * |
|
dump_boolean(int val) |
|
/* display the value of a boolean capability */ |
|
{ |
|
switch (val) { |
|
case ABSENT_BOOLEAN: |
|
return (s_absent); |
|
case CANCELLED_BOOLEAN: |
|
return (s_cancel); |
|
case FALSE: |
|
return ("F"); |
|
case TRUE: |
|
return ("T"); |
|
default: |
|
return ("?"); |
|
} |
|
} |
|
|
|
static void |
|
dump_numeric(int val, char *buf) |
|
/* display the value of a boolean capability */ |
|
{ |
|
switch (val) { |
|
case ABSENT_NUMERIC: |
|
strcpy(buf, s_absent); |
|
break; |
|
case CANCELLED_NUMERIC: |
|
strcpy(buf, s_cancel); |
|
break; |
|
default: |
|
sprintf(buf, "%d", val); |
|
break; |
|
} |
|
} |
|
|
|
static void |
|
dump_string(char *val, char *buf) |
|
/* display the value of a string capability */ |
|
{ |
|
if (val == ABSENT_STRING) |
|
strcpy(buf, s_absent); |
|
else if (val == CANCELLED_STRING) |
|
strcpy(buf, s_cancel); |
|
else { |
|
sprintf(buf, "'%.*s'", MAX_STRING - 3, TIC_EXPAND(val)); |
|
} |
|
} |
|
|
|
static void |
compare_predicate(int type, int idx, const char *name) |
compare_predicate(int type, int idx, const char *name) |
/* predicate function to use for entry difference reports */ |
/* predicate function to use for entry difference reports */ |
{ |
{ |
register TERMTYPE *t1 = &term[0]; |
register ENTRY *e1 = &entries[0]; |
register TERMTYPE *t2 = &term[1]; |
register ENTRY *e2 = &entries[1]; |
|
char buf1[MAX_STRING], buf2[MAX_STRING]; |
|
int b1, b2; |
|
int n1, n2; |
char *s1, *s2; |
char *s1, *s2; |
|
|
switch (type) { |
switch (type) { |
case BOOLEAN: |
case CMP_BOOLEAN: |
|
b1 = e1->tterm.Booleans[idx]; |
|
b2 = e2->tterm.Booleans[idx]; |
switch (compare) { |
switch (compare) { |
case C_DIFFERENCE: |
case C_DIFFERENCE: |
if (t1->Booleans[idx] != t2->Booleans[idx]) |
if (!(b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) && b1 != b2) |
(void) printf("\t%s: %c:%c.\n", |
(void) printf("\t%s: %s%s%s.\n", |
name, |
name, |
t1->Booleans[idx] ? 'T' : 'F', |
dump_boolean(b1), |
t2->Booleans[idx] ? 'T' : 'F'); |
bool_sep, |
|
dump_boolean(b2)); |
break; |
break; |
|
|
case C_COMMON: |
case C_COMMON: |
if (t1->Booleans[idx] && t2->Booleans[idx]) |
if (b1 == b2 && b1 != ABSENT_BOOLEAN) |
(void) printf("\t%s= T.\n", name); |
(void) printf("\t%s= %s.\n", name, dump_boolean(b1)); |
break; |
break; |
|
|
case C_NAND: |
case C_NAND: |
if (!t1->Booleans[idx] && !t2->Booleans[idx]) |
if (b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) |
(void) printf("\t!%s.\n", name); |
(void) printf("\t!%s.\n", name); |
break; |
break; |
} |
} |
break; |
break; |
|
|
case NUMBER: |
case CMP_NUMBER: |
|
n1 = e1->tterm.Numbers[idx]; |
|
n2 = e2->tterm.Numbers[idx]; |
|
dump_numeric(n1, buf1); |
|
dump_numeric(n2, buf2); |
switch (compare) { |
switch (compare) { |
case C_DIFFERENCE: |
case C_DIFFERENCE: |
if (t1->Numbers[idx] != t2->Numbers[idx]) |
if (!((n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)) && n1 != n2) |
(void) printf("\t%s: %d:%d.\n", |
(void) printf("\t%s: %s, %s.\n", name, buf1, buf2); |
name, t1->Numbers[idx], t2->Numbers[idx]); |
|
break; |
break; |
|
|
case C_COMMON: |
case C_COMMON: |
if (t1->Numbers[idx] != -1 && t2->Numbers[idx] != -1 |
if (n1 != ABSENT_NUMERIC && n2 != ABSENT_NUMERIC && n1 == n2) |
&& t1->Numbers[idx] == t2->Numbers[idx]) |
(void) printf("\t%s= %s.\n", name, buf1); |
(void) printf("\t%s= %d.\n", name, t1->Numbers[idx]); |
|
break; |
break; |
|
|
case C_NAND: |
case C_NAND: |
if (t1->Numbers[idx] == -1 && t2->Numbers[idx] == -1) |
if (n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC) |
(void) printf("\t!%s.\n", name); |
(void) printf("\t!%s.\n", name); |
break; |
break; |
} |
} |
break; |
break; |
|
|
case STRING: |
case CMP_STRING: |
s1 = t1->Strings[idx]; |
s1 = e1->tterm.Strings[idx]; |
s2 = t2->Strings[idx]; |
s2 = e2->tterm.Strings[idx]; |
switch (compare) { |
switch (compare) { |
case C_DIFFERENCE: |
case C_DIFFERENCE: |
if (capcmp(s1, s2)) { |
if (capcmp(idx, s1, s2)) { |
char buf1[BUFSIZ], buf2[BUFSIZ]; |
dump_string(s1, buf1); |
|
dump_string(s2, buf2); |
if (s1 == (char *) NULL) |
|
(void) strcpy(buf1, "NULL"); |
|
else { |
|
(void) strcpy(buf1, "'"); |
|
(void) strcat(buf1, TIC_EXPAND(s1)); |
|
(void) strcat(buf1, "'"); |
|
} |
|
|
|
if (s2 == (char *) NULL) |
|
(void) strcpy(buf2, "NULL"); |
|
else { |
|
(void) strcpy(buf2, "'"); |
|
(void) strcat(buf2, TIC_EXPAND(s2)); |
|
(void) strcat(buf2, "'"); |
|
} |
|
|
|
if (strcmp(buf1, buf2)) |
if (strcmp(buf1, buf2)) |
(void) printf("\t%s: %s, %s.\n", |
(void) printf("\t%s: %s, %s.\n", name, buf1, buf2); |
name, buf1, buf2); |
|
} |
} |
break; |
break; |
|
|
case C_COMMON: |
case C_COMMON: |
if (s1 && s2 && !capcmp(s1, s2)) |
if (s1 && s2 && !capcmp(idx, s1, s2)) |
(void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1)); |
(void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1)); |
break; |
break; |
|
|
|
|
break; |
break; |
} |
} |
break; |
break; |
} |
|
|
|
|
case CMP_USE: |
|
/* unlike the other modes, this compares *all* use entries */ |
|
switch (compare) { |
|
case C_DIFFERENCE: |
|
if (!useeq(e1, e2)) { |
|
(void) fputs("\tuse: ", stdout); |
|
print_uses(e1, stdout); |
|
fputs(", ", stdout); |
|
print_uses(e2, stdout); |
|
fputs(".\n", stdout); |
|
} |
|
break; |
|
|
|
case C_COMMON: |
|
if (e1->nuses && e2->nuses && useeq(e1, e2)) { |
|
(void) fputs("\tuse: ", stdout); |
|
print_uses(e1, stdout); |
|
fputs(".\n", stdout); |
|
} |
|
break; |
|
|
|
case C_NAND: |
|
if (!e1->nuses && !e2->nuses) |
|
(void) printf("\t!use.\n"); |
|
break; |
|
} |
|
} |
} |
} |
|
|
/*************************************************************************** |
/*************************************************************************** |
|
|
(void) strcat(buf2, ep); |
(void) strcat(buf2, ep); |
(void) strcat(buf2, ";"); |
(void) strcat(buf2, ";"); |
} while |
} while |
((ep = strtok((char *) NULL, ";"))); |
((ep = strtok((char *) 0, ";"))); |
buf2[strlen(buf2) - 1] = '\0'; |
buf2[strlen(buf2) - 1] = '\0'; |
expansion = buf2; |
expansion = buf2; |
} |
} |
|
|
(void) strcat(buf2, ep); |
(void) strcat(buf2, ep); |
(void) strcat(buf2, ";"); |
(void) strcat(buf2, ";"); |
} while |
} while |
((ep = strtok((char *) NULL, ";"))); |
((ep = strtok((char *) 0, ";"))); |
|
|
buf2[strlen(buf2) - 1] = '\0'; |
buf2[strlen(buf2) - 1] = '\0'; |
expansion = buf2; |
expansion = buf2; |
|
|
ENTRY *qp, *rp; |
ENTRY *qp, *rp; |
int i, n; |
int i, n; |
|
|
dump_init((char *) NULL, F_LITERAL, S_TERMINFO, 0, itrace, FALSE); |
dump_init((char *) 0, F_LITERAL, S_TERMINFO, 0, itrace, FALSE); |
|
|
for (n = 0; n < argc && n < MAXCOMPARE; n++) { |
for (n = 0; n < argc && n < MAXCOMPARE; n++) { |
if (freopen(argv[n], "r", stdin) == NULL) |
if (freopen(argv[n], "r", stdin) == 0) |
_nc_err_abort("Can't open %s", argv[n]); |
_nc_err_abort("Can't open %s", argv[n]); |
|
|
_nc_head = _nc_tail = (ENTRY *) NULL; |
_nc_head = _nc_tail = 0; |
|
|
/* parse entries out of the source file */ |
/* parse entries out of the source file */ |
_nc_set_source(argv[n]); |
_nc_set_source(argv[n]); |
|
|
if (itrace) |
if (itrace) |
(void) fprintf(stderr, "Resolving file %d...\n", n - 0); |
(void) fprintf(stderr, "Resolving file %d...\n", n - 0); |
|
|
/* do use resolution */ |
/* maybe do use resolution */ |
if (!_nc_resolve_uses()) { |
if (!_nc_resolve_uses(!limited)) { |
(void) fprintf(stderr, |
(void) fprintf(stderr, |
"There are unresolved use entries in %s:\n", |
"There are unresolved use entries in %s:\n", |
argv[n]); |
argv[n]); |
for_entry_list(qp) |
for_entry_list(qp) { |
if (qp->nuses) { |
if (qp->nuses) { |
(void) fputs(qp->tterm.term_names, stderr); |
(void) fputs(qp->tterm.term_names, stderr); |
(void) fputc('\n', stderr); |
(void) fputc('\n', stderr); |
|
} |
} |
} |
exit(EXIT_FAILURE); |
exit(EXIT_FAILURE); |
} |
} |
|
|
if (itrace) |
if (itrace) |
(void) fprintf(stderr, "Entries are now in core...\n"); |
(void) fprintf(stderr, "Entries are now in core...\n"); |
|
|
/* |
/* The entry-matching loop. Sigh, this is intrinsically quadratic. */ |
* The entry-matching loop. We're not using the use[] |
|
* slots any more (they got zeroed out by resolve_uses) so |
|
* we stash each entry's matches in the other file there. |
|
* Sigh, this is intrinsically quadratic. |
|
*/ |
|
for (qp = heads[0]; qp; qp = qp->next) { |
for (qp = heads[0]; qp; qp = qp->next) { |
for (rp = heads[1]; rp; rp = rp->next) |
for (rp = heads[1]; rp; rp = rp->next) |
if (_nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) { |
if (_nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) { |
/* |
if (qp->ncrosslinks < MAX_CROSSLINKS) |
* This is why the uses structure parent element is |
qp->crosslinks[qp->ncrosslinks] = rp; |
* (void *) -- so we can have either (char *) for |
qp->ncrosslinks++; |
* names or entry structure pointers in them and still |
|
* be type-safe. |
|
*/ |
|
if (qp->nuses < MAX_USES) |
|
qp->uses[qp->nuses].parent = (void *) rp; |
|
qp->nuses++; |
|
|
|
if (rp->nuses < MAX_USES) |
if (rp->ncrosslinks < MAX_CROSSLINKS) |
rp->uses[rp->nuses].parent = (void *) qp; |
rp->crosslinks[rp->ncrosslinks] = qp; |
rp->nuses++; |
rp->ncrosslinks++; |
} |
} |
} |
} |
|
|
|
|
if (itrace) |
if (itrace) |
(void) fprintf(stderr, "Name matches are done...\n"); |
(void) fprintf(stderr, "Name matches are done...\n"); |
|
|
for (qp = heads[0]; qp; qp = qp->next) |
for (qp = heads[0]; qp; qp = qp->next) { |
if (qp->nuses > 1) { |
if (qp->ncrosslinks > 1) { |
(void) fprintf(stderr, |
(void) fprintf(stderr, |
"%s in file 1 (%s) has %d matches in file 2 (%s):\n", |
"%s in file 1 (%s) has %d matches in file 2 (%s):\n", |
_nc_first_name(qp->tterm.term_names), |
_nc_first_name(qp->tterm.term_names), |
argv[0], |
argv[0], |
qp->nuses, |
qp->ncrosslinks, |
argv[1]); |
argv[1]); |
for (i = 0; i < qp->nuses; i++) |
for (i = 0; i < qp->ncrosslinks; i++) |
(void) fprintf(stderr, |
(void) fprintf(stderr, |
"\t%s\n", |
"\t%s\n", |
_nc_first_name(((ENTRY *) qp->uses[i].parent)->tterm.term_names)); |
_nc_first_name((qp->crosslinks[i])->tterm.term_names)); |
} |
} |
for (rp = heads[1]; rp; rp = rp->next) |
} |
if (rp->nuses > 1) { |
|
|
for (rp = heads[1]; rp; rp = rp->next) { |
|
if (rp->ncrosslinks > 1) { |
(void) fprintf(stderr, |
(void) fprintf(stderr, |
"%s in file 2 (%s) has %d matches in file 1 (%s):\n", |
"%s in file 2 (%s) has %d matches in file 1 (%s):\n", |
_nc_first_name(rp->tterm.term_names), |
_nc_first_name(rp->tterm.term_names), |
argv[1], |
argv[1], |
rp->nuses, |
rp->ncrosslinks, |
argv[0]); |
argv[0]); |
for (i = 0; i < rp->nuses; i++) |
for (i = 0; i < rp->ncrosslinks; i++) |
(void) fprintf(stderr, |
(void) fprintf(stderr, |
"\t%s\n", |
"\t%s\n", |
_nc_first_name(((ENTRY *) rp->uses[i].parent)->tterm.term_names)); |
_nc_first_name((rp->crosslinks[i])->tterm.term_names)); |
} |
} |
|
} |
|
|
(void) printf("In file 1 (%s) only:\n", argv[0]); |
(void) printf("In file 1 (%s) only:\n", argv[0]); |
for (qp = heads[0]; qp; qp = qp->next) |
for (qp = heads[0]; qp; qp = qp->next) |
if (qp->nuses == 0) |
if (qp->ncrosslinks == 0) |
(void) printf("\t%s\n", |
(void) printf("\t%s\n", |
_nc_first_name(qp->tterm.term_names)); |
_nc_first_name(qp->tterm.term_names)); |
|
|
(void) printf("In file 2 (%s) only:\n", argv[1]); |
(void) printf("In file 2 (%s) only:\n", argv[1]); |
for (rp = heads[1]; rp; rp = rp->next) |
for (rp = heads[1]; rp; rp = rp->next) |
if (rp->nuses == 0) |
if (rp->ncrosslinks == 0) |
(void) printf("\t%s\n", |
(void) printf("\t%s\n", |
_nc_first_name(rp->tterm.term_names)); |
_nc_first_name(rp->tterm.term_names)); |
|
|
(void) printf("The following entries are equivalent:\n"); |
(void) printf("The following entries are equivalent:\n"); |
for (qp = heads[0]; qp; qp = qp->next) { |
for (qp = heads[0]; qp; qp = qp->next) { |
rp = (ENTRY *) qp->uses[0].parent; |
rp = qp->crosslinks[0]; |
|
|
if (qp->nuses == 1 && entryeq(&qp->tterm, &rp->tterm)) { |
if (qp->ncrosslinks == 1) { |
char name1[NAMESIZE], name2[NAMESIZE]; |
rp = qp->crosslinks[0]; |
|
|
(void) canonical_name(qp->tterm.term_names, name1); |
repair_acsc(&qp->tterm); |
(void) canonical_name(rp->tterm.term_names, name2); |
repair_acsc(&rp->tterm); |
|
#if NCURSES_XNAMES |
|
_nc_align_termtype(&qp->tterm, &rp->tterm); |
|
#endif |
|
if (entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp)) { |
|
char name1[NAMESIZE], name2[NAMESIZE]; |
|
|
(void) printf("%s = %s\n", name1, name2); |
(void) canonical_name(qp->tterm.term_names, name1); |
|
(void) canonical_name(rp->tterm.term_names, name2); |
|
|
|
(void) printf("%s = %s\n", name1, name2); |
|
} |
} |
} |
} |
} |
|
|
(void) printf("Differing entries:\n"); |
(void) printf("Differing entries:\n"); |
termcount = 2; |
termcount = 2; |
for (qp = heads[0]; qp; qp = qp->next) { |
for (qp = heads[0]; qp; qp = qp->next) { |
rp = (ENTRY *) qp->uses[0].parent; |
|
|
|
|
if (qp->ncrosslinks == 1) { |
|
rp = qp->crosslinks[0]; |
#if NCURSES_XNAMES |
#if NCURSES_XNAMES |
if (termcount > 1) |
/* sorry - we have to do this on each pass */ |
_nc_align_termtype(&qp->tterm, &rp->tterm); |
_nc_align_termtype(&qp->tterm, &rp->tterm); |
#endif |
#endif |
if (qp->nuses == 1 && !entryeq(&qp->tterm, &rp->tterm)) { |
if (!(entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp))) { |
char name1[NAMESIZE], name2[NAMESIZE]; |
char name1[NAMESIZE], name2[NAMESIZE]; |
|
|
term[0] = qp->tterm; |
entries[0] = *qp; |
term[1] = rp->tterm; |
entries[1] = *rp; |
|
|
(void) canonical_name(qp->tterm.term_names, name1); |
(void) canonical_name(qp->tterm.term_names, name1); |
(void) canonical_name(rp->tterm.term_names, name2); |
(void) canonical_name(rp->tterm.term_names, name2); |
|
|
switch (compare) { |
switch (compare) { |
case C_DIFFERENCE: |
case C_DIFFERENCE: |
if (itrace) |
if (itrace) |
(void) fprintf(stderr, "infocmp: dumping differences\n"); |
(void) fprintf(stderr, |
(void) printf("comparing %s to %s.\n", name1, name2); |
"infocmp: dumping differences\n"); |
compare_entry(compare_predicate, term); |
(void) printf("comparing %s to %s.\n", name1, name2); |
break; |
compare_entry(compare_predicate, &entries->tterm, quiet); |
|
break; |
|
|
case C_COMMON: |
case C_COMMON: |
if (itrace) |
if (itrace) |
(void) fprintf(stderr, |
(void) fprintf(stderr, |
"infocmp: dumping common capabilities\n"); |
"infocmp: dumping common capabilities\n"); |
(void) printf("comparing %s to %s.\n", name1, name2); |
(void) printf("comparing %s to %s.\n", name1, name2); |
compare_entry(compare_predicate, term); |
compare_entry(compare_predicate, &entries->tterm, quiet); |
break; |
break; |
|
|
case C_NAND: |
case C_NAND: |
if (itrace) |
if (itrace) |
(void) fprintf(stderr, |
(void) fprintf(stderr, |
"infocmp: dumping differences\n"); |
"infocmp: dumping differences\n"); |
(void) printf("comparing %s to %s.\n", name1, name2); |
(void) printf("comparing %s to %s.\n", name1, name2); |
compare_entry(compare_predicate, term); |
compare_entry(compare_predicate, &entries->tterm, quiet); |
break; |
break; |
|
|
|
} |
} |
} |
} |
} |
} |
} |
|
|
," -l output terminfo names" |
," -l output terminfo names" |
," -n list capabilities in neither" |
," -n list capabilities in neither" |
," -p ignore padding specifiers" |
," -p ignore padding specifiers" |
|
," -q brief listing, removes headers" |
," -r with -C, output in termcap form" |
," -r with -C, output in termcap form" |
|
," -r with -F, resolve use-references" |
," -s [d|i|l|c] sort fields" |
," -s [d|i|l|c] sort fields" |
," -u produce source with 'use='" |
," -u produce source with 'use='" |
," -v number (verbose)" |
," -v number (verbose)" |
|
|
char *s; |
char *s; |
|
|
if (initializer == 0) |
if (initializer == 0) |
initializer = malloc(strlen(term->term_names) + 20); |
initializer = (char *) malloc(strlen(entries->tterm.term_names) + 20); |
|
|
(void) sprintf(initializer, "%s_data_%s", type, term->term_names); |
(void) sprintf(initializer, "%s_data_%s", type, entries->tterm.term_names); |
for (s = initializer; *s != 0 && *s != '|'; s++) { |
for (s = initializer; *s != 0 && *s != '|'; s++) { |
if (!isalnum(*s)) |
if (!isalnum(*s)) |
*s = '_'; |
*s = '_'; |
|
|
|
|
/* dump C initializers for the terminal type */ |
/* dump C initializers for the terminal type */ |
static void |
static void |
dump_initializers(void) |
dump_initializers(TERMTYPE * term) |
{ |
{ |
int n; |
int n; |
const char *str = 0; |
const char *str = 0; |
|
|
(void) printf("static char * %s[] = %s\n", name_initializer("string"), L_CURL); |
(void) printf("static char * %s[] = %s\n", name_initializer("string"), L_CURL); |
|
|
for_each_string(n, term) { |
for_each_string(n, term) { |
char buf[BUFSIZ], *sp, *tp; |
char buf[MAX_STRING], *sp, *tp; |
|
|
if (term->Strings[n] == ABSENT_STRING) |
if (term->Strings[n] == ABSENT_STRING) |
str = "ABSENT_STRING"; |
str = "ABSENT_STRING"; |
|
|
else { |
else { |
tp = buf; |
tp = buf; |
*tp++ = '"'; |
*tp++ = '"'; |
for (sp = term->Strings[n]; *sp; sp++) { |
for (sp = term->Strings[n]; |
|
*sp != 0 && (tp - buf) < MAX_STRING - 6; |
|
sp++) { |
if (isascii(*sp) && isprint(*sp) && *sp != '\\' && *sp != '"') |
if (isascii(*sp) && isprint(*sp) && *sp != '\\' && *sp != '"') |
*tp++ = *sp; |
*tp++ = *sp; |
else { |
else { |
|
|
|
|
/* dump C initializers for the terminal type */ |
/* dump C initializers for the terminal type */ |
static void |
static void |
dump_termtype(void) |
dump_termtype(TERMTYPE * term) |
{ |
{ |
(void) printf("\t%s\n\t\t\"%s\",\n", L_CURL, term->term_names); |
(void) printf("\t%s\n\t\t\"%s\",\n", L_CURL, term->term_names); |
(void) printf("\t\t(char *)0,\t/* pointer to string table */\n"); |
(void) printf("\t\t(char *)0,\t/* pointer to string table */\n"); |
|
|
char *terminal, *firstdir, *restdir; |
char *terminal, *firstdir, *restdir; |
/* Avoid "local data >32k" error with mwcc */ |
/* Avoid "local data >32k" error with mwcc */ |
/* Also avoid overflowing smaller stacks on systems like AmigaOS */ |
/* Also avoid overflowing smaller stacks on systems like AmigaOS */ |
path *tfile = malloc(sizeof(path) * MAXTERMS); |
path *tfile = (path *) malloc(sizeof(path) * MAXTERMS); |
int c, i, len; |
int c, i, len; |
bool formatted = FALSE; |
bool formatted = FALSE; |
bool filecompare = FALSE; |
bool filecompare = FALSE; |
int initdump = 0; |
int initdump = 0; |
bool init_analyze = FALSE; |
bool init_analyze = FALSE; |
bool limited = TRUE; |
|
|
|
if ((terminal = getenv("TERM")) == NULL) { |
if ((terminal = getenv("TERM")) == 0) { |
(void) fprintf(stderr, |
(void) fprintf(stderr, |
"infocmp: environment variable TERM not set\n"); |
"infocmp: environment variable TERM not set\n"); |
return EXIT_FAILURE; |
return EXIT_FAILURE; |
|
|
/* where is the terminfo database location going to default to? */ |
/* where is the terminfo database location going to default to? */ |
restdir = firstdir = 0; |
restdir = firstdir = 0; |
|
|
while ((c = getopt(argc, argv, "deEcCfFGgIinlLprR:s:uv:Vw:A:B:1T")) != EOF) |
while ((c = getopt(argc, argv, "deEcCfFGgIinlLpqrR:s:uv:Vw:A:B:1T")) != EOF) |
switch (c) { |
switch (c) { |
case 'd': |
case 'd': |
compare = C_DIFFERENCE; |
compare = C_DIFFERENCE; |
|
|
ignorepads = TRUE; |
ignorepads = TRUE; |
break; |
break; |
|
|
|
case 'q': |
|
quiet = TRUE; |
|
s_absent = "-"; |
|
s_cancel = "@"; |
|
bool_sep = ", "; |
|
break; |
|
|
case 'r': |
case 'r': |
tversion = 0; |
tversion = 0; |
limited = FALSE; |
limited = FALSE; |
|
|
argv[optind], tfile[termcount]); |
argv[optind], tfile[termcount]); |
|
|
status = _nc_read_file_entry(tfile[termcount], |
status = _nc_read_file_entry(tfile[termcount], |
&term[termcount]); |
&entries[termcount].tterm); |
} else { |
} else { |
if (itrace) |
if (itrace) |
(void) fprintf(stderr, |
(void) fprintf(stderr, |
|
|
|
|
status = _nc_read_entry(tname[termcount], |
status = _nc_read_entry(tname[termcount], |
tfile[termcount], |
tfile[termcount], |
&term[termcount]); |
&entries[termcount].tterm); |
directory = TERMINFO; /* for error message */ |
directory = TERMINFO; /* for error message */ |
} |
} |
|
|
|
|
tfile[termcount]); |
tfile[termcount]); |
return EXIT_FAILURE; |
return EXIT_FAILURE; |
} |
} |
|
repair_acsc(&entries[termcount].tterm); |
termcount++; |
termcount++; |
} |
} |
} |
} |
|
|
#if NCURSES_XNAMES |
#if NCURSES_XNAMES |
if (termcount > 1) |
if (termcount > 1) |
_nc_align_termtype(&term[0], &term[1]); |
_nc_align_termtype(&entries[0].tterm, &entries[1].tterm); |
#endif |
#endif |
|
|
/* dump as C initializer for the terminal type */ |
/* dump as C initializer for the terminal type */ |
if (initdump) { |
if (initdump) { |
if (initdump & 1) |
if (initdump & 1) |
dump_termtype(); |
dump_termtype(&entries[0].tterm); |
if (initdump & 2) |
if (initdump & 2) |
dump_initializers(); |
dump_initializers(&entries[0].tterm); |
ExitProgram(EXIT_SUCCESS); |
ExitProgram(EXIT_SUCCESS); |
} |
} |
|
|
/* analyze the init strings */ |
/* analyze the init strings */ |
if (init_analyze) { |
if (init_analyze) { |
#undef CUR |
#undef CUR |
#define CUR term[0]. |
#define CUR entries[0].tterm. |
analyze_string("is1", init_1string, &term[0]); |
analyze_string("is1", init_1string, &entries[0].tterm); |
analyze_string("is2", init_2string, &term[0]); |
analyze_string("is2", init_2string, &entries[0].tterm); |
analyze_string("is3", init_3string, &term[0]); |
analyze_string("is3", init_3string, &entries[0].tterm); |
analyze_string("rs1", reset_1string, &term[0]); |
analyze_string("rs1", reset_1string, &entries[0].tterm); |
analyze_string("rs2", reset_2string, &term[0]); |
analyze_string("rs2", reset_2string, &entries[0].tterm); |
analyze_string("rs3", reset_3string, &term[0]); |
analyze_string("rs3", reset_3string, &entries[0].tterm); |
analyze_string("smcup", enter_ca_mode, &term[0]); |
analyze_string("smcup", enter_ca_mode, &entries[0].tterm); |
analyze_string("rmcup", exit_ca_mode, &term[0]); |
analyze_string("rmcup", exit_ca_mode, &entries[0].tterm); |
#undef CUR |
#undef CUR |
ExitProgram(EXIT_SUCCESS); |
ExitProgram(EXIT_SUCCESS); |
} |
} |
|
|
tname[0]); |
tname[0]); |
(void) printf("#\tReconstructed via infocmp from file: %s\n", |
(void) printf("#\tReconstructed via infocmp from file: %s\n", |
tfile[0]); |
tfile[0]); |
len = dump_entry(&term[0], limited, numbers, NULL); |
len = dump_entry(&entries[0].tterm, limited, numbers, NULL); |
putchar('\n'); |
putchar('\n'); |
if (itrace) |
if (itrace) |
(void) fprintf(stderr, "infocmp: length %d\n", len); |
(void) fprintf(stderr, "infocmp: length %d\n", len); |
|
|
if (itrace) |
if (itrace) |
(void) fprintf(stderr, "infocmp: dumping differences\n"); |
(void) fprintf(stderr, "infocmp: dumping differences\n"); |
(void) printf("comparing %s to %s.\n", tname[0], tname[1]); |
(void) printf("comparing %s to %s.\n", tname[0], tname[1]); |
compare_entry(compare_predicate, term); |
compare_entry(compare_predicate, &entries->tterm, quiet); |
break; |
break; |
|
|
case C_COMMON: |
case C_COMMON: |
|
|
(void) fprintf(stderr, |
(void) fprintf(stderr, |
"infocmp: dumping common capabilities\n"); |
"infocmp: dumping common capabilities\n"); |
(void) printf("comparing %s to %s.\n", tname[0], tname[1]); |
(void) printf("comparing %s to %s.\n", tname[0], tname[1]); |
compare_entry(compare_predicate, term); |
compare_entry(compare_predicate, &entries->tterm, quiet); |
break; |
break; |
|
|
case C_NAND: |
case C_NAND: |
|
|
(void) fprintf(stderr, |
(void) fprintf(stderr, |
"infocmp: dumping differences\n"); |
"infocmp: dumping differences\n"); |
(void) printf("comparing %s to %s.\n", tname[0], tname[1]); |
(void) printf("comparing %s to %s.\n", tname[0], tname[1]); |
compare_entry(compare_predicate, term); |
compare_entry(compare_predicate, &entries->tterm, quiet); |
break; |
break; |
|
|
case C_USEALL: |
case C_USEALL: |
if (itrace) |
if (itrace) |
(void) fprintf(stderr, "infocmp: dumping use entry\n"); |
(void) fprintf(stderr, "infocmp: dumping use entry\n"); |
len = dump_entry(&term[0], limited, numbers, use_predicate); |
len = dump_entry(&entries[0].tterm, limited, numbers, use_predicate); |
for (i = 1; i < termcount; i++) |
for (i = 1; i < termcount; i++) |
len += dump_uses(tname[i], !(outform == F_TERMCAP || outform |
len += dump_uses(tname[i], !(outform == F_TERMCAP || outform |
== F_TCONVERR)); |
== F_TCONVERR)); |