150276Speter/**************************************************************************** 2176187Srafan * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * 350276Speter * * 450276Speter * Permission is hereby granted, free of charge, to any person obtaining a * 550276Speter * copy of this software and associated documentation files (the * 650276Speter * "Software"), to deal in the Software without restriction, including * 750276Speter * without limitation the rights to use, copy, modify, merge, publish, * 850276Speter * distribute, distribute with modifications, sublicense, and/or sell * 950276Speter * copies of the Software, and to permit persons to whom the Software is * 1050276Speter * furnished to do so, subject to the following conditions: * 1150276Speter * * 1250276Speter * The above copyright notice and this permission notice shall be included * 1350276Speter * in all copies or substantial portions of the Software. * 1450276Speter * * 1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2250276Speter * * 2350276Speter * Except as contained in this notice, the name(s) of the above copyright * 2450276Speter * holders shall not be used in advertising or otherwise to promote the * 2550276Speter * sale, use or other dealings in this Software without prior written * 2650276Speter * authorization. * 2750276Speter ****************************************************************************/ 2850276Speter 2950276Speter/**************************************************************************** 3050276Speter * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 3150276Speter * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32166124Srafan * and: Thomas E. Dickey 1996-on * 3350276Speter ****************************************************************************/ 3450276Speter 3550276Speter/* 3650276Speter * infocmp.c -- decompile an entry, or compare two entries 3750276Speter * written by Eric S. Raymond 38174993Srafan * and Thomas E Dickey 3950276Speter */ 4050276Speter 4150276Speter#include <progs.priv.h> 4250276Speter 4350276Speter#include <dump_entry.h> 4450276Speter 45184989SrafanMODULE_ID("$Id: infocmp.c,v 1.103 2008/08/16 22:04:56 tom Exp $") 4650276Speter 4750276Speter#define L_CURL "{" 4850276Speter#define R_CURL "}" 4950276Speter 5062449Speter#define MAX_STRING 1024 /* maximum formatted string */ 5150276Speter 5250276Speterconst char *_nc_progname = "infocmp"; 5350276Speter 5462449Spetertypedef char path[PATH_MAX]; 5550276Speter 5650276Speter/*************************************************************************** 5750276Speter * 5850276Speter * The following control variables, together with the contents of the 5950276Speter * terminfo entries, completely determine the actions of the program. 6050276Speter * 6150276Speter ***************************************************************************/ 6250276Speter 63174993Srafanstatic ENTRY *entries; /* terminfo entries */ 6450276Speterstatic int termcount; /* count of terminal entries */ 6550276Speter 6662449Speterstatic bool limited = TRUE; /* "-r" option is not set */ 6762449Speterstatic bool quiet = FALSE; 68166124Srafanstatic bool literal = FALSE; 6962449Speterstatic const char *bool_sep = ":"; 7062449Speterstatic const char *s_absent = "NULL"; 7162449Speterstatic const char *s_cancel = "NULL"; 7250276Speterstatic const char *tversion; /* terminfo version selected */ 7362449Speterstatic int itrace; /* trace flag for debugging */ 7462449Speterstatic int mwidth = 60; 7550276Speterstatic int numbers = 0; /* format "%'char'" to/from "%{number}" */ 7666963Speterstatic int outform = F_TERMINFO; /* output format */ 7750276Speterstatic int sortmode; /* sort_mode */ 7850276Speter 7950276Speter/* main comparison mode */ 8050276Speterstatic int compare; 8150276Speter#define C_DEFAULT 0 /* don't force comparison mode */ 8250276Speter#define C_DIFFERENCE 1 /* list differences between two terminals */ 8350276Speter#define C_COMMON 2 /* list common capabilities */ 8450276Speter#define C_NAND 3 /* list capabilities in neither terminal */ 8550276Speter#define C_USEALL 4 /* generate relative use-form entry */ 8650276Speterstatic bool ignorepads; /* ignore pad prefixes when diffing */ 8750276Speter 8850276Speter#if NO_LEAKS 8950276Speter#undef ExitProgram 90166124Srafanstatic void ExitProgram(int code) GCC_NORETURN; 91166124Srafan/* prototype is to get gcc to accept the noreturn attribute */ 9262449Speterstatic void 93166124SrafanExitProgram(int code) 9450276Speter{ 9562449Speter while (termcount-- > 0) 9662449Speter _nc_free_termtype(&entries[termcount].tterm); 9762449Speter _nc_leaks_dump_entry(); 98174993Srafan free(entries); 99174993Srafan _nc_free_tic(code); 10050276Speter} 10150276Speter#endif 10250276Speter 10362449Speterstatic char * 10462449Spetercanonical_name(char *ptr, char *buf) 10550276Speter/* extract the terminal type's primary name */ 10650276Speter{ 10762449Speter char *bp; 10850276Speter 10950276Speter (void) strcpy(buf, ptr); 11062449Speter if ((bp = strchr(buf, '|')) != 0) 11150276Speter *bp = '\0'; 11250276Speter 11362449Speter return (buf); 11450276Speter} 11550276Speter 11650276Speter/*************************************************************************** 11750276Speter * 11850276Speter * Predicates for dump function 11950276Speter * 12050276Speter ***************************************************************************/ 12150276Speter 12262449Speterstatic int 123166124Srafancapcmp(PredIdx idx, const char *s, const char *t) 12450276Speter/* capability comparison function */ 12550276Speter{ 12650276Speter if (!VALID_STRING(s) && !VALID_STRING(t)) 12762449Speter return (s != t); 12850276Speter else if (!VALID_STRING(s) || !VALID_STRING(t)) 12962449Speter return (1); 13050276Speter 13162449Speter if ((idx == acs_chars_index) || !ignorepads) 13262449Speter return (strcmp(s, t)); 13350276Speter else 13462449Speter return (_nc_capcmp(s, t)); 13550276Speter} 13650276Speter 13762449Speterstatic int 138166124Srafanuse_predicate(unsigned type, PredIdx idx) 13950276Speter/* predicate function to use for use decompilation */ 14050276Speter{ 14162449Speter ENTRY *ep; 14250276Speter 14362449Speter switch (type) { 14462449Speter case BOOLEAN: 14550276Speter { 14662449Speter int is_set = FALSE; 14750276Speter 14862449Speter /* 14962449Speter * This assumes that multiple use entries are supposed 15062449Speter * to contribute the logical or of their boolean capabilities. 15162449Speter * This is true if we take the semantics of multiple uses to 15262449Speter * be 'each capability gets the first non-default value found 15362449Speter * in the sequence of use entries'. 15462449Speter * 15562449Speter * Note that cancelled or absent booleans are stored as FALSE, 15662449Speter * unlike numbers and strings, whose cancelled/absent state is 15762449Speter * recorded in the terminfo database. 15862449Speter */ 15962449Speter for (ep = &entries[1]; ep < entries + termcount; ep++) 16062449Speter if (ep->tterm.Booleans[idx] == TRUE) { 16162449Speter is_set = entries[0].tterm.Booleans[idx]; 16262449Speter break; 16350276Speter } 16462449Speter if (is_set != entries[0].tterm.Booleans[idx]) 16562449Speter return (!is_set); 16662449Speter else 16762449Speter return (FAIL); 16862449Speter } 16950276Speter 17062449Speter case NUMBER: 17162449Speter { 17262449Speter int value = ABSENT_NUMERIC; 17350276Speter 17462449Speter /* 17562449Speter * We take the semantics of multiple uses to be 'each 17662449Speter * capability gets the first non-default value found 17762449Speter * in the sequence of use entries'. 17862449Speter */ 17962449Speter for (ep = &entries[1]; ep < entries + termcount; ep++) 18062449Speter if (VALID_NUMERIC(ep->tterm.Numbers[idx])) { 18162449Speter value = ep->tterm.Numbers[idx]; 18262449Speter break; 18362449Speter } 18450276Speter 18562449Speter if (value != entries[0].tterm.Numbers[idx]) 18662449Speter return (value != ABSENT_NUMERIC); 18762449Speter else 18862449Speter return (FAIL); 18962449Speter } 19062449Speter 19162449Speter case STRING: 19262449Speter { 19362449Speter char *termstr, *usestr = ABSENT_STRING; 19462449Speter 19562449Speter termstr = entries[0].tterm.Strings[idx]; 19662449Speter 19762449Speter /* 19862449Speter * We take the semantics of multiple uses to be 'each 19962449Speter * capability gets the first non-default value found 20062449Speter * in the sequence of use entries'. 20162449Speter */ 20262449Speter for (ep = &entries[1]; ep < entries + termcount; ep++) 20362449Speter if (ep->tterm.Strings[idx]) { 20462449Speter usestr = ep->tterm.Strings[idx]; 20562449Speter break; 20650276Speter } 20750276Speter 20862449Speter if (usestr == ABSENT_STRING && termstr == ABSENT_STRING) 20962449Speter return (FAIL); 21062449Speter else if (!usestr || !termstr || capcmp(idx, usestr, termstr)) 21162449Speter return (TRUE); 21262449Speter else 21362449Speter return (FAIL); 21462449Speter } 21562449Speter } 21650276Speter 21762449Speter return (FALSE); /* pacify compiler */ 21862449Speter} 21950276Speter 22062449Speterstatic bool 22162449Speteruseeq(ENTRY * e1, ENTRY * e2) 22262449Speter/* are the use references in two entries equivalent? */ 22362449Speter{ 224184989Srafan unsigned i, j; 22550276Speter 22662449Speter if (e1->nuses != e2->nuses) 22762449Speter return (FALSE); 22862449Speter 22962449Speter /* Ugh...this is quadratic again */ 23062449Speter for (i = 0; i < e1->nuses; i++) { 23162449Speter bool foundmatch = FALSE; 23262449Speter 23362449Speter /* search second entry for given use reference */ 23462449Speter for (j = 0; j < e2->nuses; j++) 23562449Speter if (!strcmp(e1->uses[i].name, e2->uses[j].name)) { 23662449Speter foundmatch = TRUE; 23762449Speter break; 23850276Speter } 23950276Speter 24062449Speter if (!foundmatch) 24162449Speter return (FALSE); 24262449Speter } 24362449Speter 24462449Speter return (TRUE); 24550276Speter} 24650276Speter 24762449Speterstatic bool 248166124Srafanentryeq(TERMTYPE *t1, TERMTYPE *t2) 24962449Speter/* are two entries equivalent? */ 25050276Speter{ 251166124Srafan unsigned i; 25250276Speter 25350276Speter for (i = 0; i < NUM_BOOLEANS(t1); i++) 25450276Speter if (t1->Booleans[i] != t2->Booleans[i]) 25562449Speter return (FALSE); 25650276Speter 25750276Speter for (i = 0; i < NUM_NUMBERS(t1); i++) 25850276Speter if (t1->Numbers[i] != t2->Numbers[i]) 25962449Speter return (FALSE); 26050276Speter 26150276Speter for (i = 0; i < NUM_STRINGS(t1); i++) 262166124Srafan if (capcmp((PredIdx) i, t1->Strings[i], t2->Strings[i])) 26362449Speter return (FALSE); 26450276Speter 26562449Speter return (TRUE); 26650276Speter} 26750276Speter 26850276Speter#define TIC_EXPAND(result) _nc_tic_expand(result, outform==F_TERMINFO, numbers) 26950276Speter 27062449Speterstatic void 271166124Srafanprint_uses(ENTRY * ep, FILE *fp) 27262449Speter/* print an entry's use references */ 27362449Speter{ 274184989Srafan unsigned i; 27562449Speter 27662449Speter if (!ep->nuses) 27762449Speter fputs("NULL", fp); 27862449Speter else 27962449Speter for (i = 0; i < ep->nuses; i++) { 28062449Speter fputs(ep->uses[i].name, fp); 28162449Speter if (i < ep->nuses - 1) 28262449Speter fputs(" ", fp); 28362449Speter } 28462449Speter} 28562449Speter 28662449Speterstatic const char * 28762449Speterdump_boolean(int val) 28862449Speter/* display the value of a boolean capability */ 28962449Speter{ 29062449Speter switch (val) { 29162449Speter case ABSENT_BOOLEAN: 29262449Speter return (s_absent); 29362449Speter case CANCELLED_BOOLEAN: 29462449Speter return (s_cancel); 29562449Speter case FALSE: 29662449Speter return ("F"); 29762449Speter case TRUE: 29862449Speter return ("T"); 29962449Speter default: 30062449Speter return ("?"); 30162449Speter } 30262449Speter} 30362449Speter 30462449Speterstatic void 30562449Speterdump_numeric(int val, char *buf) 30662449Speter/* display the value of a boolean capability */ 30762449Speter{ 30862449Speter switch (val) { 30962449Speter case ABSENT_NUMERIC: 31062449Speter strcpy(buf, s_absent); 31162449Speter break; 31262449Speter case CANCELLED_NUMERIC: 31362449Speter strcpy(buf, s_cancel); 31462449Speter break; 31562449Speter default: 31662449Speter sprintf(buf, "%d", val); 31762449Speter break; 31862449Speter } 31962449Speter} 32062449Speter 32162449Speterstatic void 32262449Speterdump_string(char *val, char *buf) 32362449Speter/* display the value of a string capability */ 32462449Speter{ 32562449Speter if (val == ABSENT_STRING) 32662449Speter strcpy(buf, s_absent); 32762449Speter else if (val == CANCELLED_STRING) 32862449Speter strcpy(buf, s_cancel); 32962449Speter else { 33062449Speter sprintf(buf, "'%.*s'", MAX_STRING - 3, TIC_EXPAND(val)); 33162449Speter } 33262449Speter} 33362449Speter 33462449Speterstatic void 335166124Srafancompare_predicate(PredType type, PredIdx idx, const char *name) 33650276Speter/* predicate function to use for entry difference reports */ 33750276Speter{ 33862449Speter register ENTRY *e1 = &entries[0]; 33962449Speter register ENTRY *e2 = &entries[1]; 34062449Speter char buf1[MAX_STRING], buf2[MAX_STRING]; 34162449Speter int b1, b2; 34262449Speter int n1, n2; 34362449Speter char *s1, *s2; 34450276Speter 34562449Speter switch (type) { 34662449Speter case CMP_BOOLEAN: 34762449Speter b1 = e1->tterm.Booleans[idx]; 34862449Speter b2 = e2->tterm.Booleans[idx]; 34962449Speter switch (compare) { 35062449Speter case C_DIFFERENCE: 35162449Speter if (!(b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) && b1 != b2) 35262449Speter (void) printf("\t%s: %s%s%s.\n", 35366963Speter name, 35466963Speter dump_boolean(b1), 35566963Speter bool_sep, 35666963Speter dump_boolean(b2)); 35762449Speter break; 35850276Speter 35962449Speter case C_COMMON: 36062449Speter if (b1 == b2 && b1 != ABSENT_BOOLEAN) 36162449Speter (void) printf("\t%s= %s.\n", name, dump_boolean(b1)); 36262449Speter break; 36350276Speter 36462449Speter case C_NAND: 36562449Speter if (b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) 36662449Speter (void) printf("\t!%s.\n", name); 36762449Speter break; 36862449Speter } 36962449Speter break; 37050276Speter 37162449Speter case CMP_NUMBER: 37262449Speter n1 = e1->tterm.Numbers[idx]; 37362449Speter n2 = e2->tterm.Numbers[idx]; 37462449Speter dump_numeric(n1, buf1); 37562449Speter dump_numeric(n2, buf2); 37662449Speter switch (compare) { 37762449Speter case C_DIFFERENCE: 37862449Speter if (!((n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)) && n1 != n2) 37962449Speter (void) printf("\t%s: %s, %s.\n", name, buf1, buf2); 38062449Speter break; 38150276Speter 38262449Speter case C_COMMON: 38362449Speter if (n1 != ABSENT_NUMERIC && n2 != ABSENT_NUMERIC && n1 == n2) 38462449Speter (void) printf("\t%s= %s.\n", name, buf1); 38562449Speter break; 38650276Speter 38762449Speter case C_NAND: 38862449Speter if (n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC) 38962449Speter (void) printf("\t!%s.\n", name); 39062449Speter break; 39162449Speter } 39250276Speter break; 39350276Speter 39462449Speter case CMP_STRING: 39562449Speter s1 = e1->tterm.Strings[idx]; 39662449Speter s2 = e2->tterm.Strings[idx]; 39762449Speter switch (compare) { 39862449Speter case C_DIFFERENCE: 39962449Speter if (capcmp(idx, s1, s2)) { 40062449Speter dump_string(s1, buf1); 40162449Speter dump_string(s2, buf2); 40262449Speter if (strcmp(buf1, buf2)) 40362449Speter (void) printf("\t%s: %s, %s.\n", name, buf1, buf2); 40462449Speter } 40562449Speter break; 40650276Speter 40762449Speter case C_COMMON: 40862449Speter if (s1 && s2 && !capcmp(idx, s1, s2)) 40962449Speter (void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1)); 41062449Speter break; 41150276Speter 41262449Speter case C_NAND: 41362449Speter if (!s1 && !s2) 41462449Speter (void) printf("\t!%s.\n", name); 41562449Speter break; 41662449Speter } 41762449Speter break; 41850276Speter 41962449Speter case CMP_USE: 42062449Speter /* unlike the other modes, this compares *all* use entries */ 42162449Speter switch (compare) { 42262449Speter case C_DIFFERENCE: 42362449Speter if (!useeq(e1, e2)) { 42462449Speter (void) fputs("\tuse: ", stdout); 42562449Speter print_uses(e1, stdout); 42662449Speter fputs(", ", stdout); 42762449Speter print_uses(e2, stdout); 42862449Speter fputs(".\n", stdout); 42962449Speter } 43062449Speter break; 43150276Speter 43262449Speter case C_COMMON: 43362449Speter if (e1->nuses && e2->nuses && useeq(e1, e2)) { 43462449Speter (void) fputs("\tuse: ", stdout); 43562449Speter print_uses(e1, stdout); 43662449Speter fputs(".\n", stdout); 43762449Speter } 43862449Speter break; 43950276Speter 44062449Speter case C_NAND: 44162449Speter if (!e1->nuses && !e2->nuses) 44262449Speter (void) printf("\t!use.\n"); 44362449Speter break; 44450276Speter } 44562449Speter } 44650276Speter} 44750276Speter 44850276Speter/*************************************************************************** 44950276Speter * 45050276Speter * Init string analysis 45150276Speter * 45250276Speter ***************************************************************************/ 45350276Speter 45462449Spetertypedef struct { 45562449Speter const char *from; 45662449Speter const char *to; 45762449Speter} assoc; 45850276Speter 45950276Speterstatic const assoc std_caps[] = 46050276Speter{ 46150276Speter /* these are specified by X.364 and iBCS2 */ 46262449Speter {"\033c", "RIS"}, /* full reset */ 46362449Speter {"\0337", "SC"}, /* save cursor */ 46462449Speter {"\0338", "RC"}, /* restore cursor */ 46562449Speter {"\033[r", "RSR"}, /* not an X.364 mnemonic */ 46662449Speter {"\033[m", "SGR0"}, /* not an X.364 mnemonic */ 46762449Speter {"\033[2J", "ED2"}, /* clear page */ 46850276Speter 46950276Speter /* this group is specified by ISO 2022 */ 47062449Speter {"\033(0", "ISO DEC G0"}, /* enable DEC graphics for G0 */ 47162449Speter {"\033(A", "ISO UK G0"}, /* enable UK chars for G0 */ 47262449Speter {"\033(B", "ISO US G0"}, /* enable US chars for G0 */ 47362449Speter {"\033)0", "ISO DEC G1"}, /* enable DEC graphics for G1 */ 47462449Speter {"\033)A", "ISO UK G1"}, /* enable UK chars for G1 */ 47562449Speter {"\033)B", "ISO US G1"}, /* enable US chars for G1 */ 47650276Speter 477166124Srafan /* these are DEC private controls widely supported by emulators */ 47862449Speter {"\033=", "DECPAM"}, /* application keypad mode */ 47962449Speter {"\033>", "DECPNM"}, /* normal keypad mode */ 48062449Speter {"\033<", "DECANSI"}, /* enter ANSI mode */ 481166124Srafan {"\033[!p", "DECSTR"}, /* soft reset */ 482166124Srafan {"\033 F", "S7C1T"}, /* 7-bit controls */ 48350276Speter 48462449Speter {(char *) 0, (char *) 0} 48550276Speter}; 48650276Speter 487166124Srafanstatic const assoc std_modes[] = 488166124Srafan/* ECMA \E[ ... [hl] modes recognized by many emulators */ 489166124Srafan{ 490166124Srafan {"2", "AM"}, /* keyboard action mode */ 491166124Srafan {"4", "IRM"}, /* insert/replace mode */ 492166124Srafan {"12", "SRM"}, /* send/receive mode */ 493166124Srafan {"20", "LNM"}, /* linefeed mode */ 494166124Srafan {(char *) 0, (char *) 0} 495166124Srafan}; 496166124Srafan 49750276Speterstatic const assoc private_modes[] = 49850276Speter/* DEC \E[ ... [hl] modes recognized by many emulators */ 49950276Speter{ 50062449Speter {"1", "CKM"}, /* application cursor keys */ 50162449Speter {"2", "ANM"}, /* set VT52 mode */ 50262449Speter {"3", "COLM"}, /* 132-column mode */ 50362449Speter {"4", "SCLM"}, /* smooth scroll */ 50462449Speter {"5", "SCNM"}, /* reverse video mode */ 50562449Speter {"6", "OM"}, /* origin mode */ 50662449Speter {"7", "AWM"}, /* wraparound mode */ 50762449Speter {"8", "ARM"}, /* auto-repeat mode */ 50862449Speter {(char *) 0, (char *) 0} 50950276Speter}; 51050276Speter 51150276Speterstatic const assoc ecma_highlights[] = 51250276Speter/* recognize ECMA attribute sequences */ 51350276Speter{ 51462449Speter {"0", "NORMAL"}, /* normal */ 51562449Speter {"1", "+BOLD"}, /* bold on */ 51662449Speter {"2", "+DIM"}, /* dim on */ 51762449Speter {"3", "+ITALIC"}, /* italic on */ 51862449Speter {"4", "+UNDERLINE"}, /* underline on */ 51962449Speter {"5", "+BLINK"}, /* blink on */ 52062449Speter {"6", "+FASTBLINK"}, /* fastblink on */ 52162449Speter {"7", "+REVERSE"}, /* reverse on */ 52262449Speter {"8", "+INVISIBLE"}, /* invisible on */ 52362449Speter {"9", "+DELETED"}, /* deleted on */ 52462449Speter {"10", "MAIN-FONT"}, /* select primary font */ 52562449Speter {"11", "ALT-FONT-1"}, /* select alternate font 1 */ 52662449Speter {"12", "ALT-FONT-2"}, /* select alternate font 2 */ 52762449Speter {"13", "ALT-FONT-3"}, /* select alternate font 3 */ 52862449Speter {"14", "ALT-FONT-4"}, /* select alternate font 4 */ 52962449Speter {"15", "ALT-FONT-5"}, /* select alternate font 5 */ 53062449Speter {"16", "ALT-FONT-6"}, /* select alternate font 6 */ 53162449Speter {"17", "ALT-FONT-7"}, /* select alternate font 7 */ 53262449Speter {"18", "ALT-FONT-1"}, /* select alternate font 1 */ 53362449Speter {"19", "ALT-FONT-1"}, /* select alternate font 1 */ 53462449Speter {"20", "FRAKTUR"}, /* Fraktur font */ 53562449Speter {"21", "DOUBLEUNDER"}, /* double underline */ 53662449Speter {"22", "-DIM"}, /* dim off */ 53762449Speter {"23", "-ITALIC"}, /* italic off */ 53862449Speter {"24", "-UNDERLINE"}, /* underline off */ 53962449Speter {"25", "-BLINK"}, /* blink off */ 54062449Speter {"26", "-FASTBLINK"}, /* fastblink off */ 54162449Speter {"27", "-REVERSE"}, /* reverse off */ 54262449Speter {"28", "-INVISIBLE"}, /* invisible off */ 54362449Speter {"29", "-DELETED"}, /* deleted off */ 54462449Speter {(char *) 0, (char *) 0} 54550276Speter}; 54650276Speter 547166124Srafanstatic int 548166124Srafanskip_csi(const char *cap) 549166124Srafan{ 550166124Srafan int result = 0; 551166124Srafan if (cap[0] == '\033' && cap[1] == '[') 552166124Srafan result = 2; 553166124Srafan else if (UChar(cap[0]) == 0233) 554166124Srafan result = 1; 555166124Srafan return result; 556166124Srafan} 557166124Srafan 558166124Srafanstatic bool 559166124Srafansame_param(const char *table, const char *param, unsigned length) 560166124Srafan{ 561166124Srafan bool result = FALSE; 562166124Srafan if (strncmp(table, param, length) == 0) { 563166124Srafan result = !isdigit(UChar(param[length])); 564166124Srafan } 565166124Srafan return result; 566166124Srafan} 567166124Srafan 568166124Srafanstatic char * 569166124Srafanlookup_params(const assoc * table, char *dst, char *src) 570166124Srafan{ 571184989Srafan char *result = 0; 572166124Srafan const char *ep = strtok(src, ";"); 573166124Srafan 574184989Srafan if (ep != 0) { 575184989Srafan const assoc *ap; 576166124Srafan 577184989Srafan do { 578184989Srafan bool found = FALSE; 579166124Srafan 580184989Srafan for (ap = table; ap->from; ap++) { 581184989Srafan size_t tlen = strlen(ap->from); 582184989Srafan 583184989Srafan if (same_param(ap->from, ep, tlen)) { 584184989Srafan (void) strcat(dst, ap->to); 585184989Srafan found = TRUE; 586184989Srafan break; 587184989Srafan } 588166124Srafan } 589166124Srafan 590184989Srafan if (!found) 591184989Srafan (void) strcat(dst, ep); 592184989Srafan (void) strcat(dst, ";"); 593184989Srafan } while 594184989Srafan ((ep = strtok((char *) 0, ";"))); 595166124Srafan 596184989Srafan dst[strlen(dst) - 1] = '\0'; 597166124Srafan 598184989Srafan result = dst; 599184989Srafan } 600184989Srafan return result; 601166124Srafan} 602166124Srafan 60362449Speterstatic void 604166124Srafananalyze_string(const char *name, const char *cap, TERMTYPE *tp) 60550276Speter{ 60662449Speter char buf2[MAX_TERMINFO_LENGTH]; 607166124Srafan const char *sp; 60862449Speter const assoc *ap; 609166124Srafan int tp_lines = tp->Numbers[2]; 61050276Speter 61150276Speter if (cap == ABSENT_STRING || cap == CANCELLED_STRING) 61250276Speter return; 61350276Speter (void) printf("%s: ", name); 61450276Speter 61562449Speter for (sp = cap; *sp; sp++) { 61662449Speter int i; 617166124Srafan int csi; 61862449Speter size_t len = 0; 619166124Srafan size_t next; 62050276Speter const char *expansion = 0; 621166124Srafan char buf3[MAX_TERMINFO_LENGTH]; 62250276Speter 62350276Speter /* first, check other capabilities in this entry */ 62462449Speter for (i = 0; i < STRCOUNT; i++) { 62562449Speter char *cp = tp->Strings[i]; 62650276Speter 62750276Speter /* don't use soft-key capabilities */ 62850276Speter if (strnames[i][0] == 'k' && strnames[i][0] == 'f') 62950276Speter continue; 63050276Speter 63162449Speter if (cp != ABSENT_STRING && cp != CANCELLED_STRING && cp[0] && cp 63262449Speter != cap) { 63350276Speter len = strlen(cp); 63450276Speter (void) strncpy(buf2, sp, len); 63550276Speter buf2[len] = '\0'; 63650276Speter 63750276Speter if (_nc_capcmp(cp, buf2)) 63850276Speter continue; 63950276Speter 64050276Speter#define ISRS(s) (!strncmp((s), "is", 2) || !strncmp((s), "rs", 2)) 64150276Speter /* 64250276Speter * Theoretically we just passed the test for translation 64350276Speter * (equality once the padding is stripped). However, there 64450276Speter * are a few more hoops that need to be jumped so that 64550276Speter * identical pairs of initialization and reset strings 64650276Speter * don't just refer to each other. 64750276Speter */ 64850276Speter if (ISRS(name) || ISRS(strnames[i])) 64950276Speter if (cap < cp) 65050276Speter continue; 65150276Speter#undef ISRS 65250276Speter 65350276Speter expansion = strnames[i]; 65450276Speter break; 65550276Speter } 65650276Speter } 65750276Speter 65850276Speter /* now check the standard capabilities */ 659166124Srafan if (!expansion) { 660166124Srafan csi = skip_csi(sp); 66162449Speter for (ap = std_caps; ap->from; ap++) { 662184989Srafan size_t adj = (size_t) (csi ? 2 : 0); 663166124Srafan 66450276Speter len = strlen(ap->from); 665166124Srafan if (csi && skip_csi(ap->from) != csi) 666166124Srafan continue; 667166124Srafan if (len > adj 668166124Srafan && strncmp(ap->from + adj, sp + csi, len - adj) == 0) { 66950276Speter expansion = ap->to; 670166124Srafan len -= adj; 671184989Srafan len += (size_t) csi; 67250276Speter break; 67350276Speter } 67450276Speter } 675166124Srafan } 67650276Speter 677166124Srafan /* now check for standard-mode sequences */ 67850276Speter if (!expansion 679166124Srafan && (csi = skip_csi(sp)) != 0 680166124Srafan && (len = strspn(sp + csi, "0123456789;")) 681184989Srafan && (len < sizeof(buf3)) 682184989Srafan && (next = (size_t) csi + len) 683166124Srafan && ((sp[next] == 'h') || (sp[next] == 'l'))) { 68450276Speter 685166124Srafan (void) strcpy(buf2, (sp[next] == 'h') ? "ECMA+" : "ECMA-"); 686166124Srafan (void) strncpy(buf3, sp + csi, len); 68750276Speter buf3[len] = '\0'; 688184989Srafan len += (size_t) csi + 1; 68950276Speter 690166124Srafan expansion = lookup_params(std_modes, buf2, buf3); 691166124Srafan } 69250276Speter 693166124Srafan /* now check for private-mode sequences */ 694166124Srafan if (!expansion 695166124Srafan && (csi = skip_csi(sp)) != 0 696166124Srafan && sp[csi] == '?' 697166124Srafan && (len = strspn(sp + csi + 1, "0123456789;")) 698184989Srafan && (len < sizeof(buf3)) 699184989Srafan && (next = (size_t) csi + 1 + len) 700166124Srafan && ((sp[next] == 'h') || (sp[next] == 'l'))) { 70150276Speter 702166124Srafan (void) strcpy(buf2, (sp[next] == 'h') ? "DEC+" : "DEC-"); 703166124Srafan (void) strncpy(buf3, sp + csi + 1, len); 704166124Srafan buf3[len] = '\0'; 705184989Srafan len += (size_t) csi + 2; 70650276Speter 707166124Srafan expansion = lookup_params(private_modes, buf2, buf3); 70850276Speter } 70950276Speter 71050276Speter /* now check for ECMA highlight sequences */ 71150276Speter if (!expansion 712166124Srafan && (csi = skip_csi(sp)) != 0 713166124Srafan && (len = strspn(sp + csi, "0123456789;")) != 0 714184989Srafan && (len < sizeof(buf3)) 715184989Srafan && (next = (size_t) csi + len) 716166124Srafan && sp[next] == 'm') { 71750276Speter 71850276Speter (void) strcpy(buf2, "SGR:"); 719166124Srafan (void) strncpy(buf3, sp + csi, len); 72050276Speter buf3[len] = '\0'; 721184989Srafan len += (size_t) csi + 1; 72250276Speter 723166124Srafan expansion = lookup_params(ecma_highlights, buf2, buf3); 724166124Srafan } 72550276Speter 726166124Srafan if (!expansion 727166124Srafan && (csi = skip_csi(sp)) != 0 728166124Srafan && sp[csi] == 'm') { 729184989Srafan len = (size_t) csi + 1; 730166124Srafan (void) strcpy(buf2, "SGR:"); 731166124Srafan strcat(buf2, ecma_highlights[0].to); 73250276Speter expansion = buf2; 73350276Speter } 734166124Srafan 73550276Speter /* now check for scroll region reset */ 736166124Srafan if (!expansion 737166124Srafan && (csi = skip_csi(sp)) != 0) { 738166124Srafan if (sp[csi] == 'r') { 73950276Speter expansion = "RSR"; 740166124Srafan len = 1; 741166124Srafan } else { 742166124Srafan (void) sprintf(buf2, "1;%dr", tp_lines); 743166124Srafan len = strlen(buf2); 744166124Srafan if (strncmp(buf2, sp + csi, len) == 0) 745166124Srafan expansion = "RSR"; 746166124Srafan } 747184989Srafan len += (size_t) csi; 74850276Speter } 74950276Speter 75050276Speter /* now check for home-down */ 751166124Srafan if (!expansion 752166124Srafan && (csi = skip_csi(sp)) != 0) { 753166124Srafan (void) sprintf(buf2, "%d;1H", tp_lines); 75450276Speter len = strlen(buf2); 755166124Srafan if (strncmp(buf2, sp + csi, len) == 0) { 75662449Speter expansion = "LL"; 757166124Srafan } else { 758166124Srafan (void) sprintf(buf2, "%dH", tp_lines); 759166124Srafan len = strlen(buf2); 760166124Srafan if (strncmp(buf2, sp + csi, len) == 0) { 761166124Srafan expansion = "LL"; 762166124Srafan } 763166124Srafan } 764184989Srafan len += (size_t) csi; 76550276Speter } 76650276Speter 76750276Speter /* now look at the expansion we got, if any */ 76862449Speter if (expansion) { 769184989Srafan printf("{%s}", expansion); 77050276Speter sp += len - 1; 77162449Speter } else { 77250276Speter /* couldn't match anything */ 77350276Speter buf2[0] = *sp; 77450276Speter buf2[1] = '\0'; 775184989Srafan fputs(TIC_EXPAND(buf2), stdout); 77650276Speter } 77750276Speter } 778184989Srafan putchar('\n'); 77950276Speter} 78050276Speter 78150276Speter/*************************************************************************** 78250276Speter * 78350276Speter * File comparison 78450276Speter * 78550276Speter ***************************************************************************/ 78650276Speter 78762449Speterstatic void 78862449Speterfile_comparison(int argc, char *argv[]) 78950276Speter{ 79050276Speter#define MAXCOMPARE 2 79150276Speter /* someday we may allow comparisons on more files */ 79262449Speter int filecount = 0; 79362449Speter ENTRY *heads[MAXCOMPARE]; 79462449Speter ENTRY *qp, *rp; 79562449Speter int i, n; 79650276Speter 797184989Srafan memset(heads, 0, sizeof(heads)); 79862449Speter dump_init((char *) 0, F_LITERAL, S_TERMINFO, 0, itrace, FALSE); 79950276Speter 80062449Speter for (n = 0; n < argc && n < MAXCOMPARE; n++) { 80162449Speter if (freopen(argv[n], "r", stdin) == 0) 80250276Speter _nc_err_abort("Can't open %s", argv[n]); 80350276Speter 80462449Speter _nc_head = _nc_tail = 0; 80550276Speter 80650276Speter /* parse entries out of the source file */ 80750276Speter _nc_set_source(argv[n]); 808166124Srafan _nc_read_entry_source(stdin, NULL, TRUE, literal, NULLHOOK); 80950276Speter 81050276Speter if (itrace) 81162449Speter (void) fprintf(stderr, "Resolving file %d...\n", n - 0); 81250276Speter 81362449Speter /* maybe do use resolution */ 814166124Srafan if (!_nc_resolve_uses2(!limited, literal)) { 81550276Speter (void) fprintf(stderr, 81666963Speter "There are unresolved use entries in %s:\n", 81766963Speter argv[n]); 81862449Speter for_entry_list(qp) { 81962449Speter if (qp->nuses) { 82050276Speter (void) fputs(qp->tterm.term_names, stderr); 82150276Speter (void) fputc('\n', stderr); 82250276Speter } 82362449Speter } 824166124Srafan ExitProgram(EXIT_FAILURE); 82550276Speter } 82650276Speter 82750276Speter heads[filecount] = _nc_head; 82850276Speter filecount++; 82950276Speter } 83050276Speter 83150276Speter /* OK, all entries are in core. Ready to do the comparison */ 83250276Speter if (itrace) 83350276Speter (void) fprintf(stderr, "Entries are now in core...\n"); 83450276Speter 83562449Speter /* The entry-matching loop. Sigh, this is intrinsically quadratic. */ 83662449Speter for (qp = heads[0]; qp; qp = qp->next) { 83750276Speter for (rp = heads[1]; rp; rp = rp->next) 83862449Speter if (_nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) { 83962449Speter if (qp->ncrosslinks < MAX_CROSSLINKS) 84062449Speter qp->crosslinks[qp->ncrosslinks] = rp; 84162449Speter qp->ncrosslinks++; 84250276Speter 84362449Speter if (rp->ncrosslinks < MAX_CROSSLINKS) 84462449Speter rp->crosslinks[rp->ncrosslinks] = qp; 84562449Speter rp->ncrosslinks++; 84650276Speter } 84750276Speter } 84850276Speter 84950276Speter /* now we have two circular lists with crosslinks */ 85050276Speter if (itrace) 85150276Speter (void) fprintf(stderr, "Name matches are done...\n"); 85250276Speter 85362449Speter for (qp = heads[0]; qp; qp = qp->next) { 85462449Speter if (qp->ncrosslinks > 1) { 85550276Speter (void) fprintf(stderr, 85666963Speter "%s in file 1 (%s) has %d matches in file 2 (%s):\n", 85766963Speter _nc_first_name(qp->tterm.term_names), 85866963Speter argv[0], 85966963Speter qp->ncrosslinks, 86066963Speter argv[1]); 86162449Speter for (i = 0; i < qp->ncrosslinks; i++) 86250276Speter (void) fprintf(stderr, 86366963Speter "\t%s\n", 86466963Speter _nc_first_name((qp->crosslinks[i])->tterm.term_names)); 86550276Speter } 86662449Speter } 86762449Speter 86862449Speter for (rp = heads[1]; rp; rp = rp->next) { 86962449Speter if (rp->ncrosslinks > 1) { 87050276Speter (void) fprintf(stderr, 87166963Speter "%s in file 2 (%s) has %d matches in file 1 (%s):\n", 87266963Speter _nc_first_name(rp->tterm.term_names), 87366963Speter argv[1], 87466963Speter rp->ncrosslinks, 87566963Speter argv[0]); 87662449Speter for (i = 0; i < rp->ncrosslinks; i++) 87750276Speter (void) fprintf(stderr, 87866963Speter "\t%s\n", 87966963Speter _nc_first_name((rp->crosslinks[i])->tterm.term_names)); 88050276Speter } 88162449Speter } 88250276Speter 88350276Speter (void) printf("In file 1 (%s) only:\n", argv[0]); 88450276Speter for (qp = heads[0]; qp; qp = qp->next) 88562449Speter if (qp->ncrosslinks == 0) 88650276Speter (void) printf("\t%s\n", 88766963Speter _nc_first_name(qp->tterm.term_names)); 88850276Speter 88950276Speter (void) printf("In file 2 (%s) only:\n", argv[1]); 89050276Speter for (rp = heads[1]; rp; rp = rp->next) 89162449Speter if (rp->ncrosslinks == 0) 89250276Speter (void) printf("\t%s\n", 89366963Speter _nc_first_name(rp->tterm.term_names)); 89450276Speter 89550276Speter (void) printf("The following entries are equivalent:\n"); 89662449Speter for (qp = heads[0]; qp; qp = qp->next) { 89762449Speter rp = qp->crosslinks[0]; 89850276Speter 89962449Speter if (qp->ncrosslinks == 1) { 90062449Speter rp = qp->crosslinks[0]; 90150276Speter 90262449Speter repair_acsc(&qp->tterm); 90362449Speter repair_acsc(&rp->tterm); 90462449Speter#if NCURSES_XNAMES 90562449Speter _nc_align_termtype(&qp->tterm, &rp->tterm); 90662449Speter#endif 90762449Speter if (entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp)) { 90862449Speter char name1[NAMESIZE], name2[NAMESIZE]; 90950276Speter 91062449Speter (void) canonical_name(qp->tterm.term_names, name1); 91162449Speter (void) canonical_name(rp->tterm.term_names, name2); 91262449Speter 91362449Speter (void) printf("%s = %s\n", name1, name2); 91462449Speter } 91550276Speter } 91650276Speter } 91750276Speter 91850276Speter (void) printf("Differing entries:\n"); 91950276Speter termcount = 2; 92062449Speter for (qp = heads[0]; qp; qp = qp->next) { 92150276Speter 92262449Speter if (qp->ncrosslinks == 1) { 92362449Speter rp = qp->crosslinks[0]; 92450276Speter#if NCURSES_XNAMES 92562449Speter /* sorry - we have to do this on each pass */ 92650276Speter _nc_align_termtype(&qp->tterm, &rp->tterm); 92750276Speter#endif 92862449Speter if (!(entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp))) { 92962449Speter char name1[NAMESIZE], name2[NAMESIZE]; 93050276Speter 93162449Speter entries[0] = *qp; 93262449Speter entries[1] = *rp; 93350276Speter 93462449Speter (void) canonical_name(qp->tterm.term_names, name1); 93562449Speter (void) canonical_name(rp->tterm.term_names, name2); 93650276Speter 93762449Speter switch (compare) { 93862449Speter case C_DIFFERENCE: 93962449Speter if (itrace) 94062449Speter (void) fprintf(stderr, 941174993Srafan "%s: dumping differences\n", 942174993Srafan _nc_progname); 94362449Speter (void) printf("comparing %s to %s.\n", name1, name2); 94462449Speter compare_entry(compare_predicate, &entries->tterm, quiet); 94562449Speter break; 94650276Speter 94762449Speter case C_COMMON: 94862449Speter if (itrace) 94962449Speter (void) fprintf(stderr, 950174993Srafan "%s: dumping common capabilities\n", 951174993Srafan _nc_progname); 95262449Speter (void) printf("comparing %s to %s.\n", name1, name2); 95362449Speter compare_entry(compare_predicate, &entries->tterm, quiet); 95462449Speter break; 95550276Speter 95662449Speter case C_NAND: 95762449Speter if (itrace) 95862449Speter (void) fprintf(stderr, 959174993Srafan "%s: dumping differences\n", 960174993Srafan _nc_progname); 96162449Speter (void) printf("comparing %s to %s.\n", name1, name2); 96262449Speter compare_entry(compare_predicate, &entries->tterm, quiet); 96362449Speter break; 96450276Speter 96562449Speter } 96650276Speter } 96750276Speter } 96850276Speter } 96950276Speter} 97050276Speter 97162449Speterstatic void 97262449Speterusage(void) 97350276Speter{ 97462449Speter static const char *tbl[] = 97562449Speter { 97662449Speter "Usage: infocmp [options] [-A directory] [-B directory] [termname...]" 97762449Speter ,"" 97862449Speter ,"Options:" 97962449Speter ," -1 print single-column" 98062449Speter ," -C use termcap-names" 98162449Speter ," -F compare terminfo-files" 98262449Speter ," -I use terminfo-names" 98362449Speter ," -L use long names" 98462449Speter ," -R subset (see manpage)" 98562449Speter ," -T eliminate size limits (test)" 986166124Srafan ," -U eliminate post-processing of entries" 98762449Speter ," -V print version" 98862449Speter#if NCURSES_XNAMES 98962449Speter ," -a with -F, list commented-out caps" 99062449Speter#endif 99162449Speter ," -c list common capabilities" 99262449Speter ," -d list different capabilities" 99362449Speter ," -e format output for C initializer" 99462449Speter ," -E format output as C tables" 99562449Speter ," -f with -1, format complex strings" 99662449Speter ," -G format %{number} to %'char'" 99762449Speter ," -g format %'char' to %{number}" 99862449Speter ," -i analyze initialization/reset" 99962449Speter ," -l output terminfo names" 100062449Speter ," -n list capabilities in neither" 100162449Speter ," -p ignore padding specifiers" 100262449Speter ," -q brief listing, removes headers" 100362449Speter ," -r with -C, output in termcap form" 100462449Speter ," -r with -F, resolve use-references" 100562449Speter ," -s [d|i|l|c] sort fields" 1006166124Srafan#if NCURSES_XNAMES 1007166124Srafan ," -t suppress commented-out capabilities" 1008166124Srafan#endif 100962449Speter ," -u produce source with 'use='" 101062449Speter ," -v number (verbose)" 101162449Speter ," -w number (width)" 1012166124Srafan#if NCURSES_XNAMES 1013166124Srafan ," -x treat unknown capabilities as user-defined" 1014166124Srafan#endif 101562449Speter }; 101662449Speter const size_t first = 3; 101766963Speter const size_t last = SIZEOF(tbl); 101862449Speter const size_t left = (last - first + 1) / 2 + first; 101962449Speter size_t n; 102050276Speter 102162449Speter for (n = 0; n < left; n++) { 102262449Speter size_t m = (n < first) ? last : n + left - first; 102362449Speter if (m < last) 102462449Speter fprintf(stderr, "%-40.40s%s\n", tbl[n], tbl[m]); 102562449Speter else 102662449Speter fprintf(stderr, "%s\n", tbl[n]); 102762449Speter } 1028166124Srafan ExitProgram(EXIT_FAILURE); 102950276Speter} 103050276Speter 103162449Speterstatic char * 103297049Speterany_initializer(const char *fmt, const char *type) 103350276Speter{ 103450276Speter static char *initializer; 103550276Speter char *s; 103650276Speter 103750276Speter if (initializer == 0) 103897049Speter initializer = (char *) malloc(strlen(entries->tterm.term_names) + 103997049Speter strlen(type) + strlen(fmt)); 104050276Speter 104197049Speter (void) strcpy(initializer, entries->tterm.term_names); 104262449Speter for (s = initializer; *s != 0 && *s != '|'; s++) { 104397049Speter if (!isalnum(UChar(*s))) 104450276Speter *s = '_'; 104550276Speter } 104650276Speter *s = 0; 104797049Speter (void) sprintf(s, fmt, type); 104850276Speter return initializer; 104950276Speter} 105050276Speter 105197049Speterstatic char * 105297049Spetername_initializer(const char *type) 105397049Speter{ 105497049Speter return any_initializer("_%s_data", type); 105597049Speter} 105697049Speter 105797049Speterstatic char * 105897049Speterstring_variable(const char *type) 105997049Speter{ 106097049Speter return any_initializer("_s_%s", type); 106197049Speter} 106297049Speter 106350276Speter/* dump C initializers for the terminal type */ 106462449Speterstatic void 1065166124Srafandump_initializers(TERMTYPE *term) 106650276Speter{ 1067166124Srafan unsigned n; 106850276Speter const char *str = 0; 106950276Speter 107097049Speter printf("\nstatic char %s[] = \"%s\";\n\n", 107197049Speter name_initializer("alias"), entries->tterm.term_names); 107297049Speter 107397049Speter for_each_string(n, term) { 107497049Speter char buf[MAX_STRING], *sp, *tp; 107597049Speter 107697049Speter if (VALID_STRING(term->Strings[n])) { 107797049Speter tp = buf; 107897049Speter *tp++ = '"'; 107997049Speter for (sp = term->Strings[n]; 108097049Speter *sp != 0 && (tp - buf) < MAX_STRING - 6; 108197049Speter sp++) { 108297049Speter if (isascii(UChar(*sp)) 108397049Speter && isprint(UChar(*sp)) 108497049Speter && *sp != '\\' 108597049Speter && *sp != '"') 108697049Speter *tp++ = *sp; 108797049Speter else { 108897049Speter (void) sprintf(tp, "\\%03o", UChar(*sp)); 108997049Speter tp += 4; 109097049Speter } 109197049Speter } 109297049Speter *tp++ = '"'; 109397049Speter *tp = '\0'; 109497049Speter (void) printf("static char %-20s[] = %s;\n", 109597049Speter string_variable(ExtStrname(term, n, strnames)), buf); 109697049Speter } 109797049Speter } 109897049Speter printf("\n"); 109997049Speter 110062449Speter (void) printf("static char %s[] = %s\n", name_initializer("bool"), L_CURL); 110150276Speter 110262449Speter for_each_boolean(n, term) { 110362449Speter switch ((int) (term->Booleans[n])) { 110450276Speter case TRUE: 110550276Speter str = "TRUE"; 110650276Speter break; 110750276Speter 110850276Speter case FALSE: 110950276Speter str = "FALSE"; 111050276Speter break; 111150276Speter 111250276Speter case ABSENT_BOOLEAN: 111350276Speter str = "ABSENT_BOOLEAN"; 111450276Speter break; 111550276Speter 111650276Speter case CANCELLED_BOOLEAN: 111750276Speter str = "CANCELLED_BOOLEAN"; 111850276Speter break; 111950276Speter } 1120166124Srafan (void) printf("\t/* %3u: %-8s */\t%s,\n", 112166963Speter n, ExtBoolname(term, n, boolnames), str); 112250276Speter } 112350276Speter (void) printf("%s;\n", R_CURL); 112450276Speter 112550276Speter (void) printf("static short %s[] = %s\n", name_initializer("number"), L_CURL); 112650276Speter 112762449Speter for_each_number(n, term) { 112862449Speter char buf[BUFSIZ]; 112962449Speter switch (term->Numbers[n]) { 113050276Speter case ABSENT_NUMERIC: 113150276Speter str = "ABSENT_NUMERIC"; 113250276Speter break; 113350276Speter case CANCELLED_NUMERIC: 113450276Speter str = "CANCELLED_NUMERIC"; 113550276Speter break; 113650276Speter default: 113750276Speter sprintf(buf, "%d", term->Numbers[n]); 113850276Speter str = buf; 113950276Speter break; 114050276Speter } 1141166124Srafan (void) printf("\t/* %3u: %-8s */\t%s,\n", n, 114266963Speter ExtNumname(term, n, numnames), str); 114350276Speter } 114450276Speter (void) printf("%s;\n", R_CURL); 114550276Speter 114650276Speter (void) printf("static char * %s[] = %s\n", name_initializer("string"), L_CURL); 114750276Speter 114862449Speter for_each_string(n, term) { 114950276Speter 115050276Speter if (term->Strings[n] == ABSENT_STRING) 115150276Speter str = "ABSENT_STRING"; 115250276Speter else if (term->Strings[n] == CANCELLED_STRING) 115350276Speter str = "CANCELLED_STRING"; 115462449Speter else { 115597049Speter str = string_variable(ExtStrname(term, n, strnames)); 115650276Speter } 1157166124Srafan (void) printf("\t/* %3u: %-8s */\t%s,\n", n, 115866963Speter ExtStrname(term, n, strnames), str); 115950276Speter } 116050276Speter (void) printf("%s;\n", R_CURL); 116197049Speter 116297049Speter#if NCURSES_XNAMES 116397049Speter if ((NUM_BOOLEANS(term) != BOOLCOUNT) 116497049Speter || (NUM_NUMBERS(term) != NUMCOUNT) 116597049Speter || (NUM_STRINGS(term) != STRCOUNT)) { 116697049Speter (void) printf("static char * %s[] = %s\n", 116797049Speter name_initializer("string_ext"), L_CURL); 116897049Speter for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) { 1169166124Srafan (void) printf("\t/* %3u: bool */\t\"%s\",\n", 117097049Speter n, ExtBoolname(term, n, boolnames)); 117197049Speter } 117297049Speter for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) { 1173166124Srafan (void) printf("\t/* %3u: num */\t\"%s\",\n", 117497049Speter n, ExtNumname(term, n, numnames)); 117597049Speter } 117697049Speter for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) { 1177166124Srafan (void) printf("\t/* %3u: str */\t\"%s\",\n", 117897049Speter n, ExtStrname(term, n, strnames)); 117997049Speter } 118097049Speter (void) printf("%s;\n", R_CURL); 118197049Speter } 118297049Speter#endif 118350276Speter} 118450276Speter 118550276Speter/* dump C initializers for the terminal type */ 118662449Speterstatic void 1187166124Srafandump_termtype(TERMTYPE *term) 118850276Speter{ 118997049Speter (void) printf("\t%s\n\t\t%s,\n", L_CURL, name_initializer("alias")); 119050276Speter (void) printf("\t\t(char *)0,\t/* pointer to string table */\n"); 119150276Speter 119250276Speter (void) printf("\t\t%s,\n", name_initializer("bool")); 119350276Speter (void) printf("\t\t%s,\n", name_initializer("number")); 119450276Speter 119550276Speter (void) printf("\t\t%s,\n", name_initializer("string")); 119650276Speter 119750276Speter#if NCURSES_XNAMES 119850276Speter (void) printf("#if NCURSES_XNAMES\n"); 119950276Speter (void) printf("\t\t(char *)0,\t/* pointer to extended string table */\n"); 120050276Speter (void) printf("\t\t%s,\t/* ...corresponding names */\n", 120197049Speter ((NUM_BOOLEANS(term) != BOOLCOUNT) 120297049Speter || (NUM_NUMBERS(term) != NUMCOUNT) 120397049Speter || (NUM_STRINGS(term) != STRCOUNT)) 120466963Speter ? name_initializer("string_ext") 120566963Speter : "(char **)0"); 120650276Speter 120750276Speter (void) printf("\t\t%d,\t\t/* count total Booleans */\n", NUM_BOOLEANS(term)); 120862449Speter (void) printf("\t\t%d,\t\t/* count total Numbers */\n", NUM_NUMBERS(term)); 120962449Speter (void) printf("\t\t%d,\t\t/* count total Strings */\n", NUM_STRINGS(term)); 121050276Speter 121162449Speter (void) printf("\t\t%d,\t\t/* count extensions to Booleans */\n", 121266963Speter NUM_BOOLEANS(term) - BOOLCOUNT); 121362449Speter (void) printf("\t\t%d,\t\t/* count extensions to Numbers */\n", 121466963Speter NUM_NUMBERS(term) - NUMCOUNT); 121562449Speter (void) printf("\t\t%d,\t\t/* count extensions to Strings */\n", 121666963Speter NUM_STRINGS(term) - STRCOUNT); 121750276Speter 121850276Speter (void) printf("#endif /* NCURSES_XNAMES */\n"); 1219176187Srafan#else 1220176187Srafan (void) term; 122150276Speter#endif /* NCURSES_XNAMES */ 122250276Speter (void) printf("\t%s\n", R_CURL); 122350276Speter} 122450276Speter 122566963Speterstatic int 122666963Speteroptarg_to_number(void) 122766963Speter{ 122866963Speter char *temp = 0; 122966963Speter long value = strtol(optarg, &temp, 0); 123066963Speter 123166963Speter if (temp == 0 || temp == optarg || *temp != 0) { 123266963Speter fprintf(stderr, "Expected a number, not \"%s\"\n", optarg); 1233166124Srafan ExitProgram(EXIT_FAILURE); 123466963Speter } 123566963Speter return (int) value; 123666963Speter} 123766963Speter 1238166124Srafanstatic char * 1239166124Srafanterminal_env(void) 1240166124Srafan{ 1241166124Srafan char *terminal; 1242166124Srafan 1243166124Srafan if ((terminal = getenv("TERM")) == 0) { 1244166124Srafan (void) fprintf(stderr, 1245174993Srafan "%s: environment variable TERM not set\n", 1246174993Srafan _nc_progname); 1247166124Srafan exit(EXIT_FAILURE); 1248166124Srafan } 1249166124Srafan return terminal; 1250166124Srafan} 1251166124Srafan 125250276Speter/*************************************************************************** 125350276Speter * 125450276Speter * Main sequence 125550276Speter * 125650276Speter ***************************************************************************/ 125750276Speter 125862449Speterint 125962449Spetermain(int argc, char *argv[]) 126050276Speter{ 126162449Speter /* Avoid "local data >32k" error with mwcc */ 126262449Speter /* Also avoid overflowing smaller stacks on systems like AmigaOS */ 1263174993Srafan path *tfile = 0; 1264174993Srafan char **tname = 0; 1265174993Srafan int maxterms; 1266174993Srafan 1267174993Srafan char **myargv; 1268174993Srafan 1269174993Srafan char *firstdir, *restdir; 127062449Speter int c, i, len; 127162449Speter bool formatted = FALSE; 127262449Speter bool filecompare = FALSE; 127362449Speter int initdump = 0; 127462449Speter bool init_analyze = FALSE; 1275166124Srafan bool suppress_untranslatable = FALSE; 127650276Speter 127762449Speter /* where is the terminfo database location going to default to? */ 127862449Speter restdir = firstdir = 0; 127950276Speter 1280166124Srafan#if NCURSES_XNAMES 1281166124Srafan use_extended_names(FALSE); 1282166124Srafan#endif 1283166124Srafan 1284174993Srafan _nc_progname = _nc_rootname(argv[0]); 1285174993Srafan 1286174993Srafan /* make sure we have enough space to add two terminal entries */ 1287184989Srafan myargv = typeCalloc(char *, (size_t) (argc + 3)); 1288184989Srafan memcpy(myargv, argv, (sizeof(char *) * (size_t) argc)); 1289174993Srafan argv = myargv; 1290174993Srafan 1291166124Srafan while ((c = getopt(argc, 1292166124Srafan argv, 1293174993Srafan "1A:aB:CcdEeFfGgIiLlnpqR:rs:TtUuVv:w:x")) != -1) { 129462449Speter switch (c) { 1295166124Srafan case '1': 1296166124Srafan mwidth = 0; 1297166124Srafan break; 1298166124Srafan 1299166124Srafan case 'A': 1300166124Srafan firstdir = optarg; 1301166124Srafan break; 1302166124Srafan 130362449Speter#if NCURSES_XNAMES 130462449Speter case 'a': 130562449Speter _nc_disable_period = TRUE; 130662449Speter use_extended_names(TRUE); 130762449Speter break; 130862449Speter#endif 1309166124Srafan case 'B': 1310166124Srafan restdir = optarg; 1311166124Srafan break; 1312166124Srafan 1313166124Srafan case 'C': 1314166124Srafan outform = F_TERMCAP; 1315166124Srafan tversion = "BSD"; 1316166124Srafan if (sortmode == S_DEFAULT) 1317166124Srafan sortmode = S_TERMCAP; 1318166124Srafan break; 1319166124Srafan 1320166124Srafan case 'c': 1321166124Srafan compare = C_COMMON; 1322166124Srafan break; 1323166124Srafan 132462449Speter case 'd': 132562449Speter compare = C_DIFFERENCE; 132662449Speter break; 132750276Speter 132862449Speter case 'E': 132962449Speter initdump |= 2; 133062449Speter break; 133150276Speter 1332166124Srafan case 'e': 1333166124Srafan initdump |= 1; 133462449Speter break; 133550276Speter 1336166124Srafan case 'F': 1337166124Srafan filecompare = TRUE; 133862449Speter break; 133950276Speter 134062449Speter case 'f': 134162449Speter formatted = TRUE; 134262449Speter break; 134350276Speter 134462449Speter case 'G': 134562449Speter numbers = 1; 134662449Speter break; 134750276Speter 134862449Speter case 'g': 134962449Speter numbers = -1; 135062449Speter break; 135150276Speter 135262449Speter case 'I': 135362449Speter outform = F_TERMINFO; 135462449Speter if (sortmode == S_DEFAULT) 135562449Speter sortmode = S_VARIABLE; 135662449Speter tversion = 0; 135762449Speter break; 135850276Speter 135962449Speter case 'i': 136062449Speter init_analyze = TRUE; 136162449Speter break; 136250276Speter 136362449Speter case 'L': 136462449Speter outform = F_VARIABLE; 136562449Speter if (sortmode == S_DEFAULT) 136662449Speter sortmode = S_VARIABLE; 136762449Speter break; 136850276Speter 1369166124Srafan case 'l': 1370166124Srafan outform = F_TERMINFO; 1371166124Srafan break; 1372166124Srafan 137362449Speter case 'n': 137462449Speter compare = C_NAND; 137562449Speter break; 137650276Speter 137762449Speter case 'p': 137862449Speter ignorepads = TRUE; 137962449Speter break; 138050276Speter 138162449Speter case 'q': 138262449Speter quiet = TRUE; 138362449Speter s_absent = "-"; 138462449Speter s_cancel = "@"; 138562449Speter bool_sep = ", "; 138662449Speter break; 138750276Speter 1388166124Srafan case 'R': 1389166124Srafan tversion = optarg; 1390166124Srafan break; 1391166124Srafan 139262449Speter case 'r': 139362449Speter tversion = 0; 139462449Speter break; 139550276Speter 139662449Speter case 's': 139762449Speter if (*optarg == 'd') 139862449Speter sortmode = S_NOSORT; 139962449Speter else if (*optarg == 'i') 140062449Speter sortmode = S_TERMINFO; 140162449Speter else if (*optarg == 'l') 140262449Speter sortmode = S_VARIABLE; 140362449Speter else if (*optarg == 'c') 140462449Speter sortmode = S_TERMCAP; 140562449Speter else { 140662449Speter (void) fprintf(stderr, 1407174993Srafan "%s: unknown sort mode\n", 1408174993Srafan _nc_progname); 1409166124Srafan ExitProgram(EXIT_FAILURE); 141062449Speter } 141162449Speter break; 141250276Speter 1413166124Srafan case 'T': 1414166124Srafan limited = FALSE; 1415166124Srafan break; 1416166124Srafan 1417166124Srafan#if NCURSES_XNAMES 1418166124Srafan case 't': 1419166124Srafan _nc_disable_period = FALSE; 1420166124Srafan suppress_untranslatable = TRUE; 1421166124Srafan break; 1422166124Srafan#endif 1423166124Srafan 1424166124Srafan case 'U': 1425166124Srafan literal = TRUE; 1426166124Srafan break; 1427166124Srafan 142862449Speter case 'u': 142962449Speter compare = C_USEALL; 143062449Speter break; 143150276Speter 1432166124Srafan case 'V': 1433166124Srafan puts(curses_version()); 1434166124Srafan ExitProgram(EXIT_SUCCESS); 1435166124Srafan 143662449Speter case 'v': 143766963Speter itrace = optarg_to_number(); 143862449Speter set_trace_level(itrace); 143962449Speter break; 144050276Speter 144162449Speter case 'w': 144266963Speter mwidth = optarg_to_number(); 144362449Speter break; 144450276Speter 1445166124Srafan#if NCURSES_XNAMES 1446166124Srafan case 'x': 1447166124Srafan use_extended_names(TRUE); 144862449Speter break; 1449166124Srafan#endif 145050276Speter 145162449Speter default: 145262449Speter usage(); 145362449Speter } 1454166124Srafan } 145550276Speter 1456176187Srafan maxterms = (argc + 2 - optind); 1457174993Srafan tfile = typeMalloc(path, maxterms); 1458174993Srafan tname = typeCalloc(char *, maxterms); 1459174993Srafan entries = typeCalloc(ENTRY, maxterms); 1460174993Srafan 1461174993Srafan if (tfile == 0 1462174993Srafan || tname == 0 1463174993Srafan || entries == 0) { 1464174993Srafan fprintf(stderr, "%s: not enough memory\n", _nc_progname); 1465174993Srafan ExitProgram(EXIT_FAILURE); 1466174993Srafan } 1467174993Srafan 146862449Speter /* by default, sort by terminfo name */ 146962449Speter if (sortmode == S_DEFAULT) 147062449Speter sortmode = S_TERMINFO; 147150276Speter 147262449Speter /* set up for display */ 147362449Speter dump_init(tversion, outform, sortmode, mwidth, itrace, formatted); 147450276Speter 147562449Speter /* make sure we have at least one terminal name to work with */ 147662449Speter if (optind >= argc) 1477166124Srafan argv[argc++] = terminal_env(); 147850276Speter 147962449Speter /* if user is after a comparison, make sure we have two entries */ 148062449Speter if (compare != C_DEFAULT && optind >= argc - 1) 1481166124Srafan argv[argc++] = terminal_env(); 148250276Speter 148362449Speter /* exactly two terminal names with no options means do -d */ 148462449Speter if (argc - optind == 2 && compare == C_DEFAULT) 148562449Speter compare = C_DIFFERENCE; 148650276Speter 148762449Speter if (!filecompare) { 148862449Speter /* grab the entries */ 148962449Speter termcount = 0; 149062449Speter for (; optind < argc; optind++) { 1491174993Srafan const char *directory = termcount ? restdir : firstdir; 1492174993Srafan int status; 149350276Speter 1494174993Srafan tname[termcount] = argv[optind]; 149550276Speter 1496174993Srafan if (directory) { 1497166124Srafan#if USE_DATABASE 1498174993Srafan#if MIXEDCASE_FILENAMES 1499174993Srafan#define LEAF_FMT "%c" 1500174993Srafan#else 1501174993Srafan#define LEAF_FMT "%02x" 1502174993Srafan#endif 1503174993Srafan (void) sprintf(tfile[termcount], "%s/" LEAF_FMT "/%s", 1504174993Srafan directory, 1505174993Srafan UChar(*argv[optind]), argv[optind]); 1506174993Srafan if (itrace) 1507174993Srafan (void) fprintf(stderr, 1508174993Srafan "%s: reading entry %s from file %s\n", 1509174993Srafan _nc_progname, 1510174993Srafan argv[optind], tfile[termcount]); 151150276Speter 1512174993Srafan status = _nc_read_file_entry(tfile[termcount], 1513174993Srafan &entries[termcount].tterm); 1514166124Srafan#else 1515174993Srafan (void) fprintf(stderr, "%s: terminfo files not supported\n", 1516174993Srafan _nc_progname); 1517174993Srafan ExitProgram(EXIT_FAILURE); 1518166124Srafan#endif 1519174993Srafan } else { 1520174993Srafan if (itrace) 1521174993Srafan (void) fprintf(stderr, 1522174993Srafan "%s: reading entry %s from database\n", 1523174993Srafan _nc_progname, 1524174993Srafan tname[termcount]); 152550276Speter 1526174993Srafan status = _nc_read_entry(tname[termcount], 1527174993Srafan tfile[termcount], 1528174993Srafan &entries[termcount].tterm); 1529174993Srafan directory = TERMINFO; /* for error message */ 1530174993Srafan } 153162449Speter 1532174993Srafan if (status <= 0) { 1533174993Srafan (void) fprintf(stderr, 1534174993Srafan "%s: couldn't open terminfo file %s.\n", 1535174993Srafan _nc_progname, 1536174993Srafan tfile[termcount]); 1537174993Srafan ExitProgram(EXIT_FAILURE); 153850276Speter } 1539174993Srafan repair_acsc(&entries[termcount].tterm); 1540174993Srafan termcount++; 154162449Speter } 154250276Speter 154350276Speter#if NCURSES_XNAMES 154462449Speter if (termcount > 1) 154562449Speter _nc_align_termtype(&entries[0].tterm, &entries[1].tterm); 154650276Speter#endif 154750276Speter 154862449Speter /* dump as C initializer for the terminal type */ 154962449Speter if (initdump) { 155062449Speter if (initdump & 1) 155162449Speter dump_termtype(&entries[0].tterm); 155262449Speter if (initdump & 2) 155362449Speter dump_initializers(&entries[0].tterm); 155462449Speter } 155550276Speter 155662449Speter /* analyze the init strings */ 1557166124Srafan else if (init_analyze) { 155850276Speter#undef CUR 155962449Speter#define CUR entries[0].tterm. 156062449Speter analyze_string("is1", init_1string, &entries[0].tterm); 156162449Speter analyze_string("is2", init_2string, &entries[0].tterm); 156262449Speter analyze_string("is3", init_3string, &entries[0].tterm); 156362449Speter analyze_string("rs1", reset_1string, &entries[0].tterm); 156462449Speter analyze_string("rs2", reset_2string, &entries[0].tterm); 156562449Speter analyze_string("rs3", reset_3string, &entries[0].tterm); 156662449Speter analyze_string("smcup", enter_ca_mode, &entries[0].tterm); 156762449Speter analyze_string("rmcup", exit_ca_mode, &entries[0].tterm); 156850276Speter#undef CUR 1569166124Srafan } else { 157050276Speter 1571166124Srafan /* 1572166124Srafan * Here's where the real work gets done 1573166124Srafan */ 1574166124Srafan switch (compare) { 1575166124Srafan case C_DEFAULT: 1576166124Srafan if (itrace) 1577166124Srafan (void) fprintf(stderr, 1578174993Srafan "%s: about to dump %s\n", 1579174993Srafan _nc_progname, 1580166124Srafan tname[0]); 1581166124Srafan (void) printf("#\tReconstructed via infocmp from file: %s\n", 1582166124Srafan tfile[0]); 1583166124Srafan dump_entry(&entries[0].tterm, 1584166124Srafan suppress_untranslatable, 1585166124Srafan limited, 1586166124Srafan numbers, 1587166124Srafan NULL); 1588166124Srafan len = show_entry(); 1589166124Srafan if (itrace) 1590174993Srafan (void) fprintf(stderr, "%s: length %d\n", _nc_progname, len); 1591166124Srafan break; 159250276Speter 1593166124Srafan case C_DIFFERENCE: 1594166124Srafan if (itrace) 1595174993Srafan (void) fprintf(stderr, "%s: dumping differences\n", _nc_progname); 1596166124Srafan (void) printf("comparing %s to %s.\n", tname[0], tname[1]); 1597166124Srafan compare_entry(compare_predicate, &entries->tterm, quiet); 1598166124Srafan break; 159950276Speter 1600166124Srafan case C_COMMON: 1601166124Srafan if (itrace) 1602166124Srafan (void) fprintf(stderr, 1603174993Srafan "%s: dumping common capabilities\n", 1604174993Srafan _nc_progname); 1605166124Srafan (void) printf("comparing %s to %s.\n", tname[0], tname[1]); 1606166124Srafan compare_entry(compare_predicate, &entries->tterm, quiet); 1607166124Srafan break; 160850276Speter 1609166124Srafan case C_NAND: 1610166124Srafan if (itrace) 1611166124Srafan (void) fprintf(stderr, 1612174993Srafan "%s: dumping differences\n", 1613174993Srafan _nc_progname); 1614166124Srafan (void) printf("comparing %s to %s.\n", tname[0], tname[1]); 1615166124Srafan compare_entry(compare_predicate, &entries->tterm, quiet); 1616166124Srafan break; 161750276Speter 1618166124Srafan case C_USEALL: 1619166124Srafan if (itrace) 1620174993Srafan (void) fprintf(stderr, "%s: dumping use entry\n", _nc_progname); 1621166124Srafan dump_entry(&entries[0].tterm, 1622166124Srafan suppress_untranslatable, 1623166124Srafan limited, 1624166124Srafan numbers, 1625166124Srafan use_predicate); 1626166124Srafan for (i = 1; i < termcount; i++) 1627166124Srafan dump_uses(tname[i], !(outform == F_TERMCAP 1628166124Srafan || outform == F_TCONVERR)); 1629166124Srafan len = show_entry(); 1630166124Srafan if (itrace) 1631174993Srafan (void) fprintf(stderr, "%s: length %d\n", _nc_progname, len); 1632166124Srafan break; 1633166124Srafan } 163450276Speter } 163562449Speter } else if (compare == C_USEALL) 163662449Speter (void) fprintf(stderr, "Sorry, -u doesn't work with -F\n"); 163762449Speter else if (compare == C_DEFAULT) 163862449Speter (void) fprintf(stderr, "Use `tic -[CI] <file>' for this.\n"); 163962449Speter else if (argc - optind != 2) 164062449Speter (void) fprintf(stderr, 164166963Speter "File comparison needs exactly two file arguments.\n"); 164262449Speter else 164362449Speter file_comparison(argc - optind, argv + optind); 164450276Speter 1645174993Srafan#if NO_LEAKS 1646174993Srafan free(myargv); 1647166124Srafan free(tfile); 1648174993Srafan free(tname); 1649174993Srafan#endif 165062449Speter ExitProgram(EXIT_SUCCESS); 165150276Speter} 165250276Speter 165350276Speter/* infocmp.c ends here */ 1654