📄 infocmp.c
字号:
/**************************************************************************** * Copyright (c) 1998-2004,2005 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, distribute with modifications, sublicense, and/or sell * * copies of the Software, and to permit persons to whom the Software is * * furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included * * in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * * Except as contained in this notice, the name(s) of the above copyright * * holders shall not be used in advertising or otherwise to promote the * * sale, use or other dealings in this Software without prior written * * authorization. * ****************************************************************************//**************************************************************************** * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * * and: Eric S. Raymond <esr@snark.thyrsus.com> * * and: Thomas E. Dickey 1996-on * ****************************************************************************//* * infocmp.c -- decompile an entry, or compare two entries * written by Eric S. Raymond */#include <progs.priv.h>#include <dump_entry.h>MODULE_ID("$Id: infocmp.c,v 1.79 2005/09/25 00:39:43 tom Exp $")#define L_CURL "{"#define R_CURL "}"#define MAXTERMS 32 /* max # terminal arguments we can handle */#define MAX_STRING 1024 /* maximum formatted string */const char *_nc_progname = "infocmp";typedef char path[PATH_MAX];/*************************************************************************** * * The following control variables, together with the contents of the * terminfo entries, completely determine the actions of the program. * ***************************************************************************/static char *tname[MAXTERMS]; /* terminal type names */static ENTRY entries[MAXTERMS]; /* terminfo entries */static int termcount; /* count of terminal entries */static bool limited = TRUE; /* "-r" option is not set */static bool quiet = FALSE;static bool literal = FALSE;static const char *bool_sep = ":";static const char *s_absent = "NULL";static const char *s_cancel = "NULL";static const char *tversion; /* terminfo version selected */static int itrace; /* trace flag for debugging */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 */static int compare;#define C_DEFAULT 0 /* don't force comparison mode */#define C_DIFFERENCE 1 /* list differences between two terminals */#define C_COMMON 2 /* list common capabilities */#define C_NAND 3 /* list capabilities in neither terminal */#define C_USEALL 4 /* generate relative use-form entry */static bool ignorepads; /* ignore pad prefixes when diffing */#if NO_LEAKS#undef ExitProgramstatic void ExitProgram(int code) GCC_NORETURN;/* prototype is to get gcc to accept the noreturn attribute */static voidExitProgram(int code){ while (termcount-- > 0) _nc_free_termtype(&entries[termcount].tterm); _nc_leaks_dump_entry(); _nc_free_and_exit(code);}#endifstatic char *canonical_name(char *ptr, char *buf)/* extract the terminal type's primary name */{ char *bp; (void) strcpy(buf, ptr); if ((bp = strchr(buf, '|')) != 0) *bp = '\0'; return (buf);}/*************************************************************************** * * Predicates for dump function * ***************************************************************************/static intcapcmp(PredIdx idx, const char *s, const char *t)/* capability comparison function */{ if (!VALID_STRING(s) && !VALID_STRING(t)) return (s != t); else if (!VALID_STRING(s) || !VALID_STRING(t)) return (1); if ((idx == acs_chars_index) || !ignorepads) return (strcmp(s, t)); else return (_nc_capcmp(s, t));}static intuse_predicate(unsigned type, PredIdx idx)/* predicate function to use for use decompilation */{ ENTRY *ep; switch (type) { case BOOLEAN: { int is_set = FALSE; /* * This assumes that multiple use entries are supposed * to contribute the logical or of their boolean capabilities. * This is true if we take the semantics of multiple uses to * be 'each capability gets the first non-default value found * 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 (ep = &entries[1]; ep < entries + termcount; ep++) if (ep->tterm.Booleans[idx] == TRUE) { is_set = entries[0].tterm.Booleans[idx]; break; } if (is_set != entries[0].tterm.Booleans[idx]) return (!is_set); else return (FAIL); } case NUMBER: { int value = ABSENT_NUMERIC; /* * We take the semantics of multiple uses to be 'each * capability gets the first non-default value found * in the sequence of use entries'. */ for (ep = &entries[1]; ep < entries + termcount; ep++) if (VALID_NUMERIC(ep->tterm.Numbers[idx])) { value = ep->tterm.Numbers[idx]; break; } if (value != entries[0].tterm.Numbers[idx]) return (value != ABSENT_NUMERIC); else return (FAIL); } case STRING: { char *termstr, *usestr = ABSENT_STRING; termstr = entries[0].tterm.Strings[idx]; /* * We take the semantics of multiple uses to be 'each * capability gets the first non-default value found * in the sequence of use entries'. */ for (ep = &entries[1]; ep < entries + termcount; ep++) if (ep->tterm.Strings[idx]) { usestr = ep->tterm.Strings[idx]; break; } if (usestr == ABSENT_STRING && termstr == ABSENT_STRING) return (FAIL); else if (!usestr || !termstr || capcmp(idx, usestr, termstr)) return (TRUE); else return (FAIL); } } return (FALSE); /* pacify compiler */}static booluseeq(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 boolentryeq(TERMTYPE *t1, TERMTYPE *t2)/* are two entries equivalent? */{ unsigned i; for (i = 0; i < NUM_BOOLEANS(t1); i++) if (t1->Booleans[i] != t2->Booleans[i]) return (FALSE); for (i = 0; i < NUM_NUMBERS(t1); i++) if (t1->Numbers[i] != t2->Numbers[i]) return (FALSE); for (i = 0; i < NUM_STRINGS(t1); i++) if (capcmp((PredIdx) i, t1->Strings[i], t2->Strings[i])) return (FALSE); return (TRUE);}#define TIC_EXPAND(result) _nc_tic_expand(result, outform==F_TERMINFO, numbers)static voidprint_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 const 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 voiddump_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 voiddump_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 voidcompare_predicate(PredType type, PredIdx idx, const char *name)/* predicate function to use for entry difference reports */{ register ENTRY *e1 = &entries[0]; register ENTRY *e2 = &entries[1]; char buf1[MAX_STRING], buf2[MAX_STRING]; int b1, b2; int n1, n2; char *s1, *s2; switch (type) { case CMP_BOOLEAN: b1 = e1->tterm.Booleans[idx]; b2 = e2->tterm.Booleans[idx]; switch (compare) { case C_DIFFERENCE: if (!(b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) && b1 != b2) (void) printf("\t%s: %s%s%s.\n", name, dump_boolean(b1), bool_sep, dump_boolean(b2)); break; case C_COMMON: if (b1 == b2 && b1 != ABSENT_BOOLEAN) (void) printf("\t%s= %s.\n", name, dump_boolean(b1)); break; case C_NAND: if (b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) (void) printf("\t!%s.\n", name); break; } break; case CMP_NUMBER: n1 = e1->tterm.Numbers[idx]; n2 = e2->tterm.Numbers[idx]; dump_numeric(n1, buf1); dump_numeric(n2, buf2); switch (compare) { case C_DIFFERENCE: if (!((n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)) && n1 != n2) (void) printf("\t%s: %s, %s.\n", name, buf1, buf2); break; case C_COMMON: if (n1 != ABSENT_NUMERIC && n2 != ABSENT_NUMERIC && n1 == n2) (void) printf("\t%s= %s.\n", name, buf1); break; case C_NAND: if (n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC) (void) printf("\t!%s.\n", name); break; } break; case CMP_STRING: s1 = e1->tterm.Strings[idx]; s2 = e2->tterm.Strings[idx]; switch (compare) { case C_DIFFERENCE: if (capcmp(idx, s1, s2)) { dump_string(s1, buf1); dump_string(s2, buf2); if (strcmp(buf1, buf2)) (void) printf("\t%s: %s, %s.\n", name, buf1, buf2); } break; case C_COMMON: if (s1 && s2 && !capcmp(idx, s1, s2)) (void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1)); break; case C_NAND: if (!s1 && !s2) (void) printf("\t!%s.\n", name); 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; } }}/*************************************************************************** * * Init string analysis * ***************************************************************************/typedef struct { const char *from; const char *to;} assoc;static const assoc std_caps[] ={ /* these are specified by X.364 and iBCS2 */ {"\033c", "RIS"}, /* full reset */ {"\0337", "SC"}, /* save cursor */ {"\0338", "RC"}, /* restore cursor */ {"\033[r", "RSR"}, /* not an X.364 mnemonic */ {"\033[m", "SGR0"}, /* not an X.364 mnemonic */ {"\033[2J", "ED2"}, /* clear page */ /* this group is specified by ISO 2022 */ {"\033(0", "ISO DEC G0"}, /* enable DEC graphics for G0 */ {"\033(A", "ISO UK G0"}, /* enable UK chars for G0 */ {"\033(B", "ISO US G0"}, /* enable US chars for G0 */ {"\033)0", "ISO DEC G1"}, /* enable DEC graphics for G1 */ {"\033)A", "ISO UK G1"}, /* enable UK chars for G1 */ {"\033)B", "ISO US G1"}, /* enable US chars for G1 */ /* these are DEC private controls widely supported by emulators */ {"\033=", "DECPAM"}, /* application keypad mode */ {"\033>", "DECPNM"}, /* normal keypad mode */ {"\033<", "DECANSI"}, /* enter ANSI mode */ {"\033[!p", "DECSTR"}, /* soft reset */ {"\033 F", "S7C1T"}, /* 7-bit controls */ {(char *) 0, (char *) 0}};static const assoc std_modes[] =/* ECMA \E[ ... [hl] modes recognized by many emulators */{ {"2", "AM"}, /* keyboard action mode */ {"4", "IRM"}, /* insert/replace mode */ {"12", "SRM"}, /* send/receive mode */ {"20", "LNM"}, /* linefeed mode */ {(char *) 0, (char *) 0}};static const assoc private_modes[] =/* DEC \E[ ... [hl] modes recognized by many emulators */{ {"1", "CKM"}, /* application cursor keys */ {"2", "ANM"}, /* set VT52 mode */ {"3", "COLM"}, /* 132-column mode */ {"4", "SCLM"}, /* smooth scroll */ {"5", "SCNM"}, /* reverse video mode */ {"6", "OM"}, /* origin mode */ {"7", "AWM"}, /* wraparound mode */ {"8", "ARM"}, /* auto-repeat mode */ {(char *) 0, (char *) 0}};static const assoc ecma_highlights[] =/* recognize ECMA attribute sequences */{ {"0", "NORMAL"}, /* normal */ {"1", "+BOLD"}, /* bold on */ {"2", "+DIM"}, /* dim on */ {"3", "+ITALIC"}, /* italic on */ {"4", "+UNDERLINE"}, /* underline on */ {"5", "+BLINK"}, /* blink on */ {"6", "+FASTBLINK"}, /* fastblink on */ {"7", "+REVERSE"}, /* reverse on */ {"8", "+INVISIBLE"}, /* invisible on */ {"9", "+DELETED"}, /* deleted on */ {"10", "MAIN-FONT"}, /* select primary font */ {"11", "ALT-FONT-1"}, /* select alternate font 1 */ {"12", "ALT-FONT-2"}, /* select alternate font 2 */ {"13", "ALT-FONT-3"}, /* select alternate font 3 */ {"14", "ALT-FONT-4"}, /* select alternate font 4 */ {"15", "ALT-FONT-5"}, /* select alternate font 5 */ {"16", "ALT-FONT-6"}, /* select alternate font 6 */ {"17", "ALT-FONT-7"}, /* select alternate font 7 */ {"18", "ALT-FONT-1"}, /* select alternate font 1 */ {"19", "ALT-FONT-1"}, /* select alternate font 1 */ {"20", "FRAKTUR"}, /* Fraktur font */ {"21", "DOUBLEUNDER"}, /* double underline */ {"22", "-DIM"}, /* dim off */ {"23", "-ITALIC"}, /* italic off */ {"24", "-UNDERLINE"}, /* underline off */ {"25", "-BLINK"}, /* blink off */ {"26", "-FASTBLINK"}, /* fastblink off */ {"27", "-REVERSE"}, /* reverse off */ {"28", "-INVISIBLE"}, /* invisible off */ {"29", "-DELETED"}, /* deleted off */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -