10e3d5408SPeter Wemm /**************************************************************************** 2*e1865124SBaptiste Daroussin * Copyright 2018-2019,2020 Thomas E. Dickey * 3*e1865124SBaptiste Daroussin * Copyright 1998-2017,2018 Free Software Foundation, Inc. * 40e3d5408SPeter Wemm * * 50e3d5408SPeter Wemm * Permission is hereby granted, free of charge, to any person obtaining a * 60e3d5408SPeter Wemm * copy of this software and associated documentation files (the * 70e3d5408SPeter Wemm * "Software"), to deal in the Software without restriction, including * 80e3d5408SPeter Wemm * without limitation the rights to use, copy, modify, merge, publish, * 90e3d5408SPeter Wemm * distribute, distribute with modifications, sublicense, and/or sell * 100e3d5408SPeter Wemm * copies of the Software, and to permit persons to whom the Software is * 110e3d5408SPeter Wemm * furnished to do so, subject to the following conditions: * 120e3d5408SPeter Wemm * * 130e3d5408SPeter Wemm * The above copyright notice and this permission notice shall be included * 140e3d5408SPeter Wemm * in all copies or substantial portions of the Software. * 150e3d5408SPeter Wemm * * 160e3d5408SPeter Wemm * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 170e3d5408SPeter Wemm * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 180e3d5408SPeter Wemm * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 190e3d5408SPeter Wemm * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 200e3d5408SPeter Wemm * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 210e3d5408SPeter Wemm * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 220e3d5408SPeter Wemm * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 230e3d5408SPeter Wemm * * 240e3d5408SPeter Wemm * Except as contained in this notice, the name(s) of the above copyright * 250e3d5408SPeter Wemm * holders shall not be used in advertising or otherwise to promote the * 260e3d5408SPeter Wemm * sale, use or other dealings in this Software without prior written * 270e3d5408SPeter Wemm * authorization. * 280e3d5408SPeter Wemm ****************************************************************************/ 290e3d5408SPeter Wemm 300e3d5408SPeter Wemm /**************************************************************************** 310e3d5408SPeter Wemm * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 320e3d5408SPeter Wemm * and: Eric S. Raymond <esr@snark.thyrsus.com> * 33b82face1SPeter Wemm * and: Thomas E. Dickey 1996 on * 340e3d5408SPeter Wemm ****************************************************************************/ 350e3d5408SPeter Wemm 360e3d5408SPeter Wemm /* 370e3d5408SPeter Wemm * tic.c --- Main program for terminfo compiler 380e3d5408SPeter Wemm * by Eric S. Raymond 3973f0a83dSXin LI * and Thomas E Dickey 400e3d5408SPeter Wemm * 410e3d5408SPeter Wemm */ 420e3d5408SPeter Wemm 430e3d5408SPeter Wemm #include <progs.priv.h> 4418259542SPeter Wemm #include <sys/stat.h> 450e3d5408SPeter Wemm 460e3d5408SPeter Wemm #include <dump_entry.h> 47aae38d10SBaptiste Daroussin #include <tparm_type.h> 4873f0a83dSXin LI #include <hashed_db.h> 49aae38d10SBaptiste Daroussin #include <parametrized.h> 5018259542SPeter Wemm #include <transform.h> 510e3d5408SPeter Wemm 52*e1865124SBaptiste Daroussin MODULE_ID("$Id: tic.c,v 1.282 2020/02/02 23:34:34 tom Exp $") 5373f0a83dSXin LI 5473f0a83dSXin LI #define STDIN_NAME "<stdin>" 550e3d5408SPeter Wemm 560e3d5408SPeter Wemm const char *_nc_progname = "tic"; 570e3d5408SPeter Wemm 580e3d5408SPeter Wemm static FILE *log_fp; 590e3d5408SPeter Wemm static FILE *tmp_fp; 604a1a9510SRong-En Fan static bool capdump = FALSE; /* running as infotocap? */ 614a1a9510SRong-En Fan static bool infodump = FALSE; /* running as captoinfo? */ 620e3d5408SPeter Wemm static bool showsummary = FALSE; 63aae38d10SBaptiste Daroussin static unsigned debug_level; 6473f0a83dSXin LI static char **namelst = 0; 650e3d5408SPeter Wemm static const char *to_remove; 660e3d5408SPeter Wemm 67aae38d10SBaptiste Daroussin #if NCURSES_XNAMES 68aae38d10SBaptiste Daroussin static bool using_extensions = FALSE; 69aae38d10SBaptiste Daroussin #endif 70aae38d10SBaptiste Daroussin 71aae38d10SBaptiste Daroussin static void (*save_check_termtype) (TERMTYPE2 *, bool); 72aae38d10SBaptiste Daroussin static void check_termtype(TERMTYPE2 *tt, bool); 730e3d5408SPeter Wemm 744a1a9510SRong-En Fan static const char usage_string[] = "\ 754a1a9510SRong-En Fan [-e names] \ 764a1a9510SRong-En Fan [-o dir] \ 774a1a9510SRong-En Fan [-R name] \ 784a1a9510SRong-En Fan [-v[n]] \ 794a1a9510SRong-En Fan [-V] \ 804a1a9510SRong-En Fan [-w[n]] \ 814a1a9510SRong-En Fan [-\ 824a1a9510SRong-En Fan 1\ 834a1a9510SRong-En Fan a\ 844a1a9510SRong-En Fan C\ 8573f0a83dSXin LI D\ 864a1a9510SRong-En Fan c\ 874a1a9510SRong-En Fan f\ 884a1a9510SRong-En Fan G\ 894a1a9510SRong-En Fan g\ 904a1a9510SRong-En Fan I\ 9173f0a83dSXin LI K\ 924a1a9510SRong-En Fan L\ 934a1a9510SRong-En Fan N\ 944a1a9510SRong-En Fan r\ 954a1a9510SRong-En Fan s\ 964a1a9510SRong-En Fan T\ 974a1a9510SRong-En Fan t\ 984a1a9510SRong-En Fan U\ 994a1a9510SRong-En Fan x\ 1004a1a9510SRong-En Fan ] \ 1014a1a9510SRong-En Fan source-file\n"; 1020e3d5408SPeter Wemm 1035d08fb1fSRong-En Fan #if NO_LEAKS 10415589c42SPeter Wemm static void 1055d08fb1fSRong-En Fan free_namelist(char **src) 1060e3d5408SPeter Wemm { 1075d08fb1fSRong-En Fan if (src != 0) { 1085d08fb1fSRong-En Fan int n; 1095d08fb1fSRong-En Fan for (n = 0; src[n] != 0; ++n) 1105d08fb1fSRong-En Fan free(src[n]); 1115d08fb1fSRong-En Fan free(src); 1125d08fb1fSRong-En Fan } 1135d08fb1fSRong-En Fan } 1145d08fb1fSRong-En Fan #endif 1155d08fb1fSRong-En Fan 1165d08fb1fSRong-En Fan static void 11773f0a83dSXin LI cleanup(void) 1185d08fb1fSRong-En Fan { 11973f0a83dSXin LI int rc; 12073f0a83dSXin LI 1215d08fb1fSRong-En Fan #if NO_LEAKS 1225d08fb1fSRong-En Fan free_namelist(namelst); 123aae38d10SBaptiste Daroussin _nc_leaks_dump_entry(); 1245d08fb1fSRong-En Fan #endif 1250e3d5408SPeter Wemm if (tmp_fp != 0) 1260e3d5408SPeter Wemm fclose(tmp_fp); 1270e3d5408SPeter Wemm if (to_remove != 0) { 1280e3d5408SPeter Wemm #if HAVE_REMOVE 12973f0a83dSXin LI rc = remove(to_remove); 1300e3d5408SPeter Wemm #else 13173f0a83dSXin LI rc = unlink(to_remove); 1320e3d5408SPeter Wemm #endif 13373f0a83dSXin LI if (rc != 0) 13473f0a83dSXin LI perror(to_remove); 1350e3d5408SPeter Wemm } 1360e3d5408SPeter Wemm } 1370e3d5408SPeter Wemm 13815589c42SPeter Wemm static void 13915589c42SPeter Wemm failed(const char *msg) 1400e3d5408SPeter Wemm { 1410e3d5408SPeter Wemm perror(msg); 1424a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 1430e3d5408SPeter Wemm } 1440e3d5408SPeter Wemm 14515589c42SPeter Wemm static void 14615589c42SPeter Wemm usage(void) 1470e3d5408SPeter Wemm { 148aae38d10SBaptiste Daroussin #define DATA(s) s "\n" 149aae38d10SBaptiste Daroussin static const char options_string[] = 15015589c42SPeter Wemm { 151aae38d10SBaptiste Daroussin DATA("Options:") 152aae38d10SBaptiste Daroussin DATA(" -0 format translation output all capabilities on one line") 153aae38d10SBaptiste Daroussin DATA(" -1 format translation output one capability per line") 15415589c42SPeter Wemm #if NCURSES_XNAMES 155aae38d10SBaptiste Daroussin DATA(" -a retain commented-out capabilities (sets -x also)") 15615589c42SPeter Wemm #endif 157aae38d10SBaptiste Daroussin DATA(" -C translate entries to termcap source form") 158aae38d10SBaptiste Daroussin DATA(" -D print list of tic's database locations (first must be writable)") 159aae38d10SBaptiste Daroussin DATA(" -c check only, validate input without compiling or translating") 160aae38d10SBaptiste Daroussin DATA(" -e<names> translate/compile only entries named by comma-separated list") 161aae38d10SBaptiste Daroussin DATA(" -f format complex strings for readability") 162aae38d10SBaptiste Daroussin DATA(" -G format %{number} to %'char'") 163aae38d10SBaptiste Daroussin DATA(" -g format %'char' to %{number}") 164aae38d10SBaptiste Daroussin DATA(" -I translate entries to terminfo source form") 165aae38d10SBaptiste Daroussin DATA(" -K translate entries to termcap source form with BSD syntax") 166aae38d10SBaptiste Daroussin DATA(" -L translate entries to full terminfo source form") 167aae38d10SBaptiste Daroussin DATA(" -N disable smart defaults for source translation") 168aae38d10SBaptiste Daroussin DATA(" -o<dir> set output directory for compiled entry writes") 169aae38d10SBaptiste Daroussin DATA(" -Q[n] dump compiled description") 170aae38d10SBaptiste Daroussin DATA(" -q brief listing, removes headers") 171aae38d10SBaptiste Daroussin DATA(" -R<name> restrict translation to given terminfo/termcap version") 172aae38d10SBaptiste Daroussin DATA(" -r force resolution of all use entries in source translation") 173aae38d10SBaptiste Daroussin DATA(" -s print summary statistics") 174aae38d10SBaptiste Daroussin DATA(" -T remove size-restrictions on compiled description") 1754a1a9510SRong-En Fan #if NCURSES_XNAMES 176aae38d10SBaptiste Daroussin DATA(" -t suppress commented-out capabilities") 1774a1a9510SRong-En Fan #endif 178aae38d10SBaptiste Daroussin DATA(" -U suppress post-processing of entries") 179aae38d10SBaptiste Daroussin DATA(" -V print version") 180aae38d10SBaptiste Daroussin DATA(" -W wrap long strings according to -w[n] option") 181aae38d10SBaptiste Daroussin DATA(" -v[n] set verbosity level") 182aae38d10SBaptiste Daroussin DATA(" -w[n] set format width for translation output") 1830e3d5408SPeter Wemm #if NCURSES_XNAMES 184aae38d10SBaptiste Daroussin DATA(" -x treat unknown capabilities as user-defined") 1850e3d5408SPeter Wemm #endif 186aae38d10SBaptiste Daroussin DATA("") 187aae38d10SBaptiste Daroussin DATA("Parameters:") 188aae38d10SBaptiste Daroussin DATA(" <file> file to translate or compile") 1890e3d5408SPeter Wemm }; 190aae38d10SBaptiste Daroussin #undef DATA 1910e3d5408SPeter Wemm 19215589c42SPeter Wemm fprintf(stderr, "Usage: %s %s\n", _nc_progname, usage_string); 193aae38d10SBaptiste Daroussin fputs(options_string, stderr); 1944a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 1950e3d5408SPeter Wemm } 1960e3d5408SPeter Wemm 1970e3d5408SPeter Wemm #define L_BRACE '{' 1980e3d5408SPeter Wemm #define R_BRACE '}' 19973f0a83dSXin LI #define S_QUOTE '\'' 2000e3d5408SPeter Wemm 20115589c42SPeter Wemm static void 20215589c42SPeter Wemm write_it(ENTRY * ep) 2030e3d5408SPeter Wemm { 2040e3d5408SPeter Wemm unsigned n; 2050e3d5408SPeter Wemm int ch; 2060e3d5408SPeter Wemm char *s, *d, *t; 2070e3d5408SPeter Wemm char result[MAX_ENTRY_SIZE]; 2080e3d5408SPeter Wemm 2090e3d5408SPeter Wemm /* 2100e3d5408SPeter Wemm * Look for strings that contain %{number}, convert them to %'char', 2110e3d5408SPeter Wemm * which is shorter and runs a little faster. 2120e3d5408SPeter Wemm */ 2130e3d5408SPeter Wemm for (n = 0; n < STRCOUNT; n++) { 2140e3d5408SPeter Wemm s = ep->tterm.Strings[n]; 2150e3d5408SPeter Wemm if (VALID_STRING(s) 2160e3d5408SPeter Wemm && strchr(s, L_BRACE) != 0) { 2170e3d5408SPeter Wemm d = result; 2180e3d5408SPeter Wemm t = s; 2190e3d5408SPeter Wemm while ((ch = *t++) != 0) { 2205d08fb1fSRong-En Fan *d++ = (char) ch; 2210e3d5408SPeter Wemm if (ch == '\\') { 222aae38d10SBaptiste Daroussin if ((*d++ = *t++) == '\0') 223aae38d10SBaptiste Daroussin break; 2240e3d5408SPeter Wemm } else if ((ch == '%') 2250e3d5408SPeter Wemm && (*t == L_BRACE)) { 2260e3d5408SPeter Wemm char *v = 0; 2270e3d5408SPeter Wemm long value = strtol(t + 1, &v, 0); 2280e3d5408SPeter Wemm if (v != 0 2290e3d5408SPeter Wemm && *v == R_BRACE 2300e3d5408SPeter Wemm && value > 0 2310e3d5408SPeter Wemm && value != '\\' /* FIXME */ 2320e3d5408SPeter Wemm && value < 127 2330e3d5408SPeter Wemm && isprint((int) value)) { 2340e3d5408SPeter Wemm *d++ = S_QUOTE; 2355d08fb1fSRong-En Fan *d++ = (char) value; 2360e3d5408SPeter Wemm *d++ = S_QUOTE; 2370e3d5408SPeter Wemm t = (v + 1); 2380e3d5408SPeter Wemm } 2390e3d5408SPeter Wemm } 2400e3d5408SPeter Wemm } 2410e3d5408SPeter Wemm *d = 0; 2420e3d5408SPeter Wemm if (strlen(result) < strlen(s)) 24373f0a83dSXin LI _nc_STRCPY(s, result, strlen(s) + 1); 2440e3d5408SPeter Wemm } 2450e3d5408SPeter Wemm } 2460e3d5408SPeter Wemm 2470e3d5408SPeter Wemm _nc_set_type(_nc_first_name(ep->tterm.term_names)); 24873f0a83dSXin LI _nc_curr_line = (int) ep->startline; 2490e3d5408SPeter Wemm _nc_write_entry(&ep->tterm); 2500e3d5408SPeter Wemm } 2510e3d5408SPeter Wemm 25215589c42SPeter Wemm static bool 25315589c42SPeter Wemm immedhook(ENTRY * ep GCC_UNUSED) 2540e3d5408SPeter Wemm /* write out entries with no use capabilities immediately to save storage */ 2550e3d5408SPeter Wemm { 25618259542SPeter Wemm #if !HAVE_BIG_CORE 2570e3d5408SPeter Wemm /* 2580e3d5408SPeter Wemm * This is strictly a core-economy kluge. The really clean way to handle 2590e3d5408SPeter Wemm * compilation is to slurp the whole file into core and then do all the 2600e3d5408SPeter Wemm * name-collision checks and entry writes in one swell foop. But the 2610e3d5408SPeter Wemm * terminfo master file is large enough that some core-poor systems swap 2620e3d5408SPeter Wemm * like crazy when you compile it this way...there have been reports of 2630e3d5408SPeter Wemm * this process taking *three hours*, rather than the twenty seconds or 2640e3d5408SPeter Wemm * less typical on my development box. 2650e3d5408SPeter Wemm * 2660e3d5408SPeter Wemm * So. This hook *immediately* writes out the referenced entry if it 2670e3d5408SPeter Wemm * has no use capabilities. The compiler main loop refrains from 2680e3d5408SPeter Wemm * adding the entry to the in-core list when this hook fires. If some 2690e3d5408SPeter Wemm * other entry later needs to reference an entry that got written 2700e3d5408SPeter Wemm * immediately, that's OK; the resolution code will fetch it off disk 2710e3d5408SPeter Wemm * when it can't find it in core. 2720e3d5408SPeter Wemm * 2730e3d5408SPeter Wemm * Name collisions will still be detected, just not as cleanly. The 2740e3d5408SPeter Wemm * write_entry() code complains before overwriting an entry that 2750e3d5408SPeter Wemm * postdates the time of tic's first call to write_entry(). Thus 2760e3d5408SPeter Wemm * it will complain about overwriting entries newly made during the 2770e3d5408SPeter Wemm * tic run, but not about overwriting ones that predate it. 2780e3d5408SPeter Wemm * 2790e3d5408SPeter Wemm * The reason this is a hook, and not in line with the rest of the 2800e3d5408SPeter Wemm * compiler code, is that the support for termcap fallback cannot assume 2810e3d5408SPeter Wemm * it has anywhere to spool out these entries! 2820e3d5408SPeter Wemm * 2830e3d5408SPeter Wemm * The _nc_set_type() call here requires a compensating one in 2840e3d5408SPeter Wemm * _nc_parse_entry(). 2850e3d5408SPeter Wemm * 2860e3d5408SPeter Wemm * If you define HAVE_BIG_CORE, you'll disable this kluge. This will 2870e3d5408SPeter Wemm * make tic a bit faster (because the resolution code won't have to do 2880e3d5408SPeter Wemm * disk I/O nearly as often). 2890e3d5408SPeter Wemm */ 29015589c42SPeter Wemm if (ep->nuses == 0) { 2910e3d5408SPeter Wemm int oldline = _nc_curr_line; 2920e3d5408SPeter Wemm 2930e3d5408SPeter Wemm write_it(ep); 2940e3d5408SPeter Wemm _nc_curr_line = oldline; 2950e3d5408SPeter Wemm free(ep->tterm.str_table); 2960e3d5408SPeter Wemm return (TRUE); 2970e3d5408SPeter Wemm } 2980e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */ 2990e3d5408SPeter Wemm return (FALSE); 3000e3d5408SPeter Wemm } 3010e3d5408SPeter Wemm 30215589c42SPeter Wemm static void 30315589c42SPeter Wemm put_translate(int c) 3040e3d5408SPeter Wemm /* emit a comment char, translating terminfo names to termcap names */ 3050e3d5408SPeter Wemm { 3060e3d5408SPeter Wemm static bool in_name = FALSE; 30715589c42SPeter Wemm static size_t have, used; 30815589c42SPeter Wemm static char *namebuf, *suffix; 3090e3d5408SPeter Wemm 31015589c42SPeter Wemm if (in_name) { 31115589c42SPeter Wemm if (used + 1 >= have) { 31215589c42SPeter Wemm have += 132; 31373f0a83dSXin LI if ((namebuf = typeRealloc(char, have, namebuf)) == 0) 31473f0a83dSXin LI failed("put_translate namebuf"); 31573f0a83dSXin LI if ((suffix = typeRealloc(char, have, suffix)) == 0) 31673f0a83dSXin LI failed("put_translate suffix"); 3170e3d5408SPeter Wemm } 31815589c42SPeter Wemm if (c == '\n' || c == '@') { 31915589c42SPeter Wemm namebuf[used++] = '\0'; 3200e3d5408SPeter Wemm (void) putchar('<'); 3210e3d5408SPeter Wemm (void) fputs(namebuf, stdout); 3220e3d5408SPeter Wemm putchar(c); 3230e3d5408SPeter Wemm in_name = FALSE; 32415589c42SPeter Wemm } else if (c != '>') { 3255d08fb1fSRong-En Fan namebuf[used++] = (char) c; 32615589c42SPeter Wemm } else { /* ah! candidate name! */ 3270e3d5408SPeter Wemm char *up; 3280e3d5408SPeter Wemm NCURSES_CONST char *tp; 3290e3d5408SPeter Wemm 33015589c42SPeter Wemm namebuf[used++] = '\0'; 3310e3d5408SPeter Wemm in_name = FALSE; 3320e3d5408SPeter Wemm 3330e3d5408SPeter Wemm suffix[0] = '\0'; 3340e3d5408SPeter Wemm if ((up = strchr(namebuf, '#')) != 0 3350e3d5408SPeter Wemm || (up = strchr(namebuf, '=')) != 0 33615589c42SPeter Wemm || ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) { 33773f0a83dSXin LI _nc_STRCPY(suffix, up, have); 3380e3d5408SPeter Wemm *up = '\0'; 3390e3d5408SPeter Wemm } 3400e3d5408SPeter Wemm 34115589c42SPeter Wemm if ((tp = nametrans(namebuf)) != 0) { 3420e3d5408SPeter Wemm (void) putchar(':'); 3430e3d5408SPeter Wemm (void) fputs(tp, stdout); 3440e3d5408SPeter Wemm (void) fputs(suffix, stdout); 3450e3d5408SPeter Wemm (void) putchar(':'); 34615589c42SPeter Wemm } else { 3470e3d5408SPeter Wemm /* couldn't find a translation, just dump the name */ 3480e3d5408SPeter Wemm (void) putchar('<'); 3490e3d5408SPeter Wemm (void) fputs(namebuf, stdout); 3500e3d5408SPeter Wemm (void) fputs(suffix, stdout); 3510e3d5408SPeter Wemm (void) putchar('>'); 3520e3d5408SPeter Wemm } 35315589c42SPeter Wemm } 35415589c42SPeter Wemm } else { 35515589c42SPeter Wemm used = 0; 35615589c42SPeter Wemm if (c == '<') { 35715589c42SPeter Wemm in_name = TRUE; 35815589c42SPeter Wemm } else { 35915589c42SPeter Wemm putchar(c); 36015589c42SPeter Wemm } 3610e3d5408SPeter Wemm } 3620e3d5408SPeter Wemm } 3630e3d5408SPeter Wemm 3640e3d5408SPeter Wemm /* Returns a string, stripped of leading/trailing whitespace */ 36515589c42SPeter Wemm static char * 36615589c42SPeter Wemm stripped(char *src) 3670e3d5408SPeter Wemm { 36873f0a83dSXin LI char *dst = 0; 36973f0a83dSXin LI 37039f2269fSPeter Wemm while (isspace(UChar(*src))) 3710e3d5408SPeter Wemm src++; 37273f0a83dSXin LI 3730e3d5408SPeter Wemm if (*src != '\0') { 37406bfebdeSXin LI size_t len; 37506bfebdeSXin LI 37673f0a83dSXin LI if ((dst = strdup(src)) == NULL) { 37706bfebdeSXin LI failed("strdup"); 37873f0a83dSXin LI } else { 37906bfebdeSXin LI len = strlen(dst); 38039f2269fSPeter Wemm while (--len != 0 && isspace(UChar(dst[len]))) 3810e3d5408SPeter Wemm dst[len] = '\0'; 3820e3d5408SPeter Wemm } 38373f0a83dSXin LI } 38473f0a83dSXin LI return dst; 3850e3d5408SPeter Wemm } 3860e3d5408SPeter Wemm 38718259542SPeter Wemm static FILE * 38873f0a83dSXin LI open_tempfile(char *filename) 38918259542SPeter Wemm { 39073f0a83dSXin LI FILE *result = 0; 39173f0a83dSXin LI 39273f0a83dSXin LI _nc_STRCPY(filename, "/tmp/XXXXXX", PATH_MAX); 39373f0a83dSXin LI #if HAVE_MKSTEMP 39473f0a83dSXin LI { 39573f0a83dSXin LI int oldmask = (int) umask(077); 39673f0a83dSXin LI int fd = mkstemp(filename); 39773f0a83dSXin LI if (fd >= 0) 39873f0a83dSXin LI result = fdopen(fd, "w"); 39973f0a83dSXin LI umask((mode_t) oldmask); 40073f0a83dSXin LI } 40173f0a83dSXin LI #else 40273f0a83dSXin LI if (tmpnam(filename) != 0) 40373f0a83dSXin LI result = fopen(filename, "w"); 40473f0a83dSXin LI #endif 40573f0a83dSXin LI return result; 40673f0a83dSXin LI } 40773f0a83dSXin LI 40873f0a83dSXin LI static FILE * 40973f0a83dSXin LI copy_input(FILE *source, const char *filename, char *alt_file) 41073f0a83dSXin LI { 41173f0a83dSXin LI char my_altfile[PATH_MAX]; 41273f0a83dSXin LI FILE *result = 0; 41373f0a83dSXin LI FILE *target = 0; 41473f0a83dSXin LI int ch; 41573f0a83dSXin LI 41673f0a83dSXin LI if (alt_file == 0) 41773f0a83dSXin LI alt_file = my_altfile; 41873f0a83dSXin LI 41973f0a83dSXin LI if (source == 0) { 42073f0a83dSXin LI failed("copy_input (source)"); 42173f0a83dSXin LI } else if ((target = open_tempfile(alt_file)) == 0) { 42273f0a83dSXin LI failed("copy_input (target)"); 42373f0a83dSXin LI } else { 42473f0a83dSXin LI clearerr(source); 42573f0a83dSXin LI for (;;) { 42673f0a83dSXin LI ch = fgetc(source); 42773f0a83dSXin LI if (feof(source)) { 42873f0a83dSXin LI break; 42973f0a83dSXin LI } else if (ferror(source)) { 43073f0a83dSXin LI failed(filename); 43173f0a83dSXin LI } else if (ch == 0) { 43273f0a83dSXin LI /* don't loop in case someone wants to convert /dev/zero */ 43373f0a83dSXin LI fprintf(stderr, "%s: %s is not a text-file\n", _nc_progname, filename); 43473f0a83dSXin LI ExitProgram(EXIT_FAILURE); 43573f0a83dSXin LI } 43673f0a83dSXin LI fputc(ch, target); 43773f0a83dSXin LI } 43873f0a83dSXin LI fclose(source); 43973f0a83dSXin LI /* 44073f0a83dSXin LI * rewind() does not force the target file's data to disk (not does 44173f0a83dSXin LI * fflush()...). So open a second stream on the data and then close 44273f0a83dSXin LI * the one that we were writing on before starting to read from the 44373f0a83dSXin LI * second stream. 44473f0a83dSXin LI */ 44573f0a83dSXin LI result = fopen(alt_file, "r+"); 44673f0a83dSXin LI fclose(target); 44773f0a83dSXin LI to_remove = strdup(alt_file); 44873f0a83dSXin LI } 44973f0a83dSXin LI return result; 45073f0a83dSXin LI } 45173f0a83dSXin LI 45273f0a83dSXin LI static FILE * 45373f0a83dSXin LI open_input(const char *filename, char *alt_file) 45473f0a83dSXin LI { 45573f0a83dSXin LI FILE *fp; 45618259542SPeter Wemm struct stat sb; 45773f0a83dSXin LI int mode; 45873f0a83dSXin LI 45973f0a83dSXin LI if (!strcmp(filename, "-")) { 46073f0a83dSXin LI fp = copy_input(stdin, STDIN_NAME, alt_file); 46173f0a83dSXin LI } else if (stat(filename, &sb) < 0) { 46273f0a83dSXin LI fprintf(stderr, "%s: %s %s\n", _nc_progname, filename, strerror(errno)); 46373f0a83dSXin LI ExitProgram(EXIT_FAILURE); 46473f0a83dSXin LI } else if ((mode = (sb.st_mode & S_IFMT)) == S_IFDIR 465aae38d10SBaptiste Daroussin || (mode != S_IFREG && mode != S_IFCHR && mode != S_IFIFO)) { 46673f0a83dSXin LI fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename); 46773f0a83dSXin LI ExitProgram(EXIT_FAILURE); 46873f0a83dSXin LI } else { 46973f0a83dSXin LI fp = fopen(filename, "r"); 47018259542SPeter Wemm 47118259542SPeter Wemm if (fp == 0) { 47218259542SPeter Wemm fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename); 4734a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 47418259542SPeter Wemm } 47573f0a83dSXin LI if (mode != S_IFREG) { 47673f0a83dSXin LI if (alt_file != 0) { 47773f0a83dSXin LI FILE *fp2 = copy_input(fp, filename, alt_file); 47873f0a83dSXin LI fp = fp2; 47973f0a83dSXin LI } else { 48018259542SPeter Wemm fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename); 4814a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 48218259542SPeter Wemm } 48373f0a83dSXin LI } 48473f0a83dSXin LI } 48518259542SPeter Wemm return fp; 48618259542SPeter Wemm } 48718259542SPeter Wemm 4880e3d5408SPeter Wemm /* Parse the "-e" option-value into a list of names */ 4895ca44d1cSRong-En Fan static char ** 49015589c42SPeter Wemm make_namelist(char *src) 4910e3d5408SPeter Wemm { 4925ca44d1cSRong-En Fan char **dst = 0; 4930e3d5408SPeter Wemm 4940e3d5408SPeter Wemm char *s, *base; 4950e3d5408SPeter Wemm unsigned pass, n, nn; 4960e3d5408SPeter Wemm char buffer[BUFSIZ]; 4970e3d5408SPeter Wemm 4980e3d5408SPeter Wemm if (src == 0) { 4990e3d5408SPeter Wemm /* EMPTY */ ; 5000e3d5408SPeter Wemm } else if (strchr(src, '/') != 0) { /* a filename */ 50173f0a83dSXin LI FILE *fp = open_input(src, (char *) 0); 5020e3d5408SPeter Wemm 5030e3d5408SPeter Wemm for (pass = 1; pass <= 2; pass++) { 5040e3d5408SPeter Wemm nn = 0; 5050e3d5408SPeter Wemm while (fgets(buffer, sizeof(buffer), fp) != 0) { 5060e3d5408SPeter Wemm if ((s = stripped(buffer)) != 0) { 5070e3d5408SPeter Wemm if (dst != 0) 5080e3d5408SPeter Wemm dst[nn] = s; 5095ca44d1cSRong-En Fan else 5105ca44d1cSRong-En Fan free(s); 5110e3d5408SPeter Wemm nn++; 5120e3d5408SPeter Wemm } 5130e3d5408SPeter Wemm } 5140e3d5408SPeter Wemm if (pass == 1) { 51573f0a83dSXin LI if ((dst = typeCalloc(char *, nn + 1)) == 0) 51673f0a83dSXin LI failed("make_namelist"); 5170e3d5408SPeter Wemm rewind(fp); 5180e3d5408SPeter Wemm } 5190e3d5408SPeter Wemm } 5200e3d5408SPeter Wemm fclose(fp); 5210e3d5408SPeter Wemm } else { /* literal list of names */ 5220e3d5408SPeter Wemm for (pass = 1; pass <= 2; pass++) { 5230e3d5408SPeter Wemm for (n = nn = 0, base = src;; n++) { 5240e3d5408SPeter Wemm int mark = src[n]; 5250e3d5408SPeter Wemm if (mark == ',' || mark == '\0') { 5260e3d5408SPeter Wemm if (pass == 1) { 5270e3d5408SPeter Wemm nn++; 5280e3d5408SPeter Wemm } else { 5290e3d5408SPeter Wemm src[n] = '\0'; 5300e3d5408SPeter Wemm if ((s = stripped(base)) != 0) 5310e3d5408SPeter Wemm dst[nn++] = s; 5320e3d5408SPeter Wemm base = &src[n + 1]; 5330e3d5408SPeter Wemm } 5340e3d5408SPeter Wemm } 5350e3d5408SPeter Wemm if (mark == '\0') 5360e3d5408SPeter Wemm break; 5370e3d5408SPeter Wemm } 53873f0a83dSXin LI if (pass == 1) { 53973f0a83dSXin LI if ((dst = typeCalloc(char *, nn + 1)) == 0) 54073f0a83dSXin LI failed("make_namelist"); 54173f0a83dSXin LI } 5420e3d5408SPeter Wemm } 5430e3d5408SPeter Wemm } 5445ca44d1cSRong-En Fan if (showsummary && (dst != 0)) { 5450e3d5408SPeter Wemm fprintf(log_fp, "Entries that will be compiled:\n"); 5460e3d5408SPeter Wemm for (n = 0; dst[n] != 0; n++) 5474a1a9510SRong-En Fan fprintf(log_fp, "%u:%s\n", n + 1, dst[n]); 5480e3d5408SPeter Wemm } 5490e3d5408SPeter Wemm return dst; 5500e3d5408SPeter Wemm } 5510e3d5408SPeter Wemm 55215589c42SPeter Wemm static bool 5535ca44d1cSRong-En Fan matches(char **needle, const char *haystack) 5540e3d5408SPeter Wemm /* does entry in needle list match |-separated field in haystack? */ 5550e3d5408SPeter Wemm { 5560e3d5408SPeter Wemm bool code = FALSE; 5570e3d5408SPeter Wemm size_t n; 5580e3d5408SPeter Wemm 55915589c42SPeter Wemm if (needle != 0) { 56015589c42SPeter Wemm for (n = 0; needle[n] != 0; n++) { 56115589c42SPeter Wemm if (_nc_name_match(haystack, needle[n], "|")) { 5620e3d5408SPeter Wemm code = TRUE; 5630e3d5408SPeter Wemm break; 5640e3d5408SPeter Wemm } 5650e3d5408SPeter Wemm } 56615589c42SPeter Wemm } else 5670e3d5408SPeter Wemm code = TRUE; 5680e3d5408SPeter Wemm return (code); 5690e3d5408SPeter Wemm } 5700e3d5408SPeter Wemm 57173f0a83dSXin LI static char * 57273f0a83dSXin LI valid_db_path(const char *nominal) 57315589c42SPeter Wemm { 57473f0a83dSXin LI struct stat sb; 57573f0a83dSXin LI #if USE_HASHED_DB 57673f0a83dSXin LI char suffix[] = DBM_SUFFIX; 57773f0a83dSXin LI size_t need = strlen(nominal) + sizeof(suffix); 57873f0a83dSXin LI char *result = malloc(need); 57973f0a83dSXin LI 58073f0a83dSXin LI if (result == 0) 58173f0a83dSXin LI failed("valid_db_path"); 58273f0a83dSXin LI _nc_STRCPY(result, nominal, need); 58373f0a83dSXin LI if (strcmp(result + need - sizeof(suffix), suffix)) { 58473f0a83dSXin LI _nc_STRCAT(result, suffix, need); 58573f0a83dSXin LI } 58615589c42SPeter Wemm #else 58773f0a83dSXin LI char *result = strdup(nominal); 58815589c42SPeter Wemm #endif 58973f0a83dSXin LI 59073f0a83dSXin LI DEBUG(1, ("** stat(%s)", result)); 59173f0a83dSXin LI if (stat(result, &sb) >= 0) { 59273f0a83dSXin LI #if USE_HASHED_DB 59373f0a83dSXin LI if (!S_ISREG(sb.st_mode) 59473f0a83dSXin LI || access(result, R_OK | W_OK) != 0) { 59573f0a83dSXin LI DEBUG(1, ("...not a writable file")); 59673f0a83dSXin LI free(result); 59773f0a83dSXin LI result = 0; 59873f0a83dSXin LI } 59973f0a83dSXin LI #else 60073f0a83dSXin LI if (!S_ISDIR(sb.st_mode) 60173f0a83dSXin LI || access(result, R_OK | W_OK | X_OK) != 0) { 60273f0a83dSXin LI DEBUG(1, ("...not a writable directory")); 60373f0a83dSXin LI free(result); 60473f0a83dSXin LI result = 0; 60573f0a83dSXin LI } 60673f0a83dSXin LI #endif 60773f0a83dSXin LI } else { 60873f0a83dSXin LI /* check if parent is directory and is writable */ 60973f0a83dSXin LI unsigned leaf = _nc_pathlast(result); 61073f0a83dSXin LI 61173f0a83dSXin LI DEBUG(1, ("...not found")); 61273f0a83dSXin LI if (leaf) { 61373f0a83dSXin LI char save = result[leaf]; 61473f0a83dSXin LI result[leaf] = 0; 61573f0a83dSXin LI if (stat(result, &sb) >= 0 61673f0a83dSXin LI && S_ISDIR(sb.st_mode) 61773f0a83dSXin LI && access(result, R_OK | W_OK | X_OK) == 0) { 61873f0a83dSXin LI result[leaf] = save; 61973f0a83dSXin LI } else { 62073f0a83dSXin LI DEBUG(1, ("...parent directory %s is not writable", result)); 62173f0a83dSXin LI free(result); 62273f0a83dSXin LI result = 0; 62373f0a83dSXin LI } 62473f0a83dSXin LI } else { 62573f0a83dSXin LI DEBUG(1, ("... no parent directory")); 62673f0a83dSXin LI free(result); 62773f0a83dSXin LI result = 0; 62873f0a83dSXin LI } 62973f0a83dSXin LI } 63015589c42SPeter Wemm return result; 63115589c42SPeter Wemm } 63215589c42SPeter Wemm 63373f0a83dSXin LI /* 63473f0a83dSXin LI * Show the databases to which tic could write. The location to which it 63573f0a83dSXin LI * writes is always the first one. If none are writable, print an error 63673f0a83dSXin LI * message. 63773f0a83dSXin LI */ 63873f0a83dSXin LI static void 63973f0a83dSXin LI show_databases(const char *outdir) 64073f0a83dSXin LI { 64173f0a83dSXin LI bool specific = (outdir != 0) || getenv("TERMINFO") != 0; 64273f0a83dSXin LI char *result; 64373f0a83dSXin LI const char *tried = 0; 64473f0a83dSXin LI 64573f0a83dSXin LI if (outdir == 0) { 64673f0a83dSXin LI outdir = _nc_tic_dir(0); 64773f0a83dSXin LI } 64873f0a83dSXin LI if ((result = valid_db_path(outdir)) != 0) { 64973f0a83dSXin LI printf("%s\n", result); 65073f0a83dSXin LI free(result); 65173f0a83dSXin LI } else { 65273f0a83dSXin LI tried = outdir; 65373f0a83dSXin LI } 65473f0a83dSXin LI 65573f0a83dSXin LI if ((outdir = _nc_home_terminfo())) { 65673f0a83dSXin LI if ((result = valid_db_path(outdir)) != 0) { 65773f0a83dSXin LI printf("%s\n", result); 65873f0a83dSXin LI free(result); 65973f0a83dSXin LI } else if (!specific) { 66073f0a83dSXin LI tried = outdir; 66173f0a83dSXin LI } 66273f0a83dSXin LI } 66373f0a83dSXin LI 66473f0a83dSXin LI /* 66573f0a83dSXin LI * If we can write in neither location, give an error message. 66673f0a83dSXin LI */ 66773f0a83dSXin LI if (tried) { 66873f0a83dSXin LI fflush(stdout); 66973f0a83dSXin LI fprintf(stderr, "%s: %s (no permission)\n", _nc_progname, tried); 67073f0a83dSXin LI ExitProgram(EXIT_FAILURE); 67173f0a83dSXin LI } 67273f0a83dSXin LI } 67373f0a83dSXin LI 674aae38d10SBaptiste Daroussin static void 675aae38d10SBaptiste Daroussin add_digit(int *target, int source) 676aae38d10SBaptiste Daroussin { 677aae38d10SBaptiste Daroussin *target = (*target * 10) + (source - '0'); 678aae38d10SBaptiste Daroussin } 67973f0a83dSXin LI 68015589c42SPeter Wemm int 68115589c42SPeter Wemm main(int argc, char *argv[]) 6820e3d5408SPeter Wemm { 6830e3d5408SPeter Wemm char my_tmpname[PATH_MAX]; 68473f0a83dSXin LI char my_altfile[PATH_MAX]; 68573f0a83dSXin LI int v_opt = -1; 6860e3d5408SPeter Wemm int smart_defaults = TRUE; 6870e3d5408SPeter Wemm char *termcap; 6880e3d5408SPeter Wemm ENTRY *qp; 6890e3d5408SPeter Wemm 6900e3d5408SPeter Wemm int this_opt, last_opt = '?'; 6910e3d5408SPeter Wemm 6920e3d5408SPeter Wemm int outform = F_TERMINFO; /* output format */ 6930e3d5408SPeter Wemm int sortmode = S_TERMINFO; /* sort_mode */ 6940e3d5408SPeter Wemm 6950e3d5408SPeter Wemm int width = 60; 69673f0a83dSXin LI int height = 65535; 6970e3d5408SPeter Wemm bool formatted = FALSE; /* reformat complex strings? */ 6984a1a9510SRong-En Fan bool literal = FALSE; /* suppress post-processing? */ 6990e3d5408SPeter Wemm int numbers = 0; /* format "%'char'" to/from "%{number}" */ 7000e3d5408SPeter Wemm bool forceresolve = FALSE; /* force resolution */ 7010e3d5408SPeter Wemm bool limited = TRUE; 7020e3d5408SPeter Wemm char *tversion = (char *) NULL; 7030e3d5408SPeter Wemm const char *source_file = "terminfo"; 7040e3d5408SPeter Wemm char *outdir = (char *) NULL; 7050e3d5408SPeter Wemm bool check_only = FALSE; 7064a1a9510SRong-En Fan bool suppress_untranslatable = FALSE; 707aae38d10SBaptiste Daroussin int quickdump = 0; 708aae38d10SBaptiste Daroussin bool quiet = FALSE; 709aae38d10SBaptiste Daroussin bool wrap_strings = FALSE; 7100e3d5408SPeter Wemm 7110e3d5408SPeter Wemm log_fp = stderr; 7120e3d5408SPeter Wemm 71339f2269fSPeter Wemm _nc_progname = _nc_rootname(argv[0]); 71473f0a83dSXin LI atexit(cleanup); 7150e3d5408SPeter Wemm 71606bfebdeSXin LI if ((infodump = same_program(_nc_progname, PROG_CAPTOINFO)) != FALSE) { 71715589c42SPeter Wemm outform = F_TERMINFO; 71815589c42SPeter Wemm sortmode = S_TERMINFO; 71915589c42SPeter Wemm } 72006bfebdeSXin LI if ((capdump = same_program(_nc_progname, PROG_INFOTOCAP)) != FALSE) { 72115589c42SPeter Wemm outform = F_TERMCAP; 72215589c42SPeter Wemm sortmode = S_TERMCAP; 72315589c42SPeter Wemm } 7240e3d5408SPeter Wemm #if NCURSES_XNAMES 7250e3d5408SPeter Wemm use_extended_names(FALSE); 7260e3d5408SPeter Wemm #endif 72773f0a83dSXin LI _nc_strict_bsd = 0; 7280e3d5408SPeter Wemm 7290e3d5408SPeter Wemm /* 7300e3d5408SPeter Wemm * Processing arguments is a little complicated, since someone made a 7310e3d5408SPeter Wemm * design decision to allow the numeric values for -w, -v options to 7320e3d5408SPeter Wemm * be optional. 7330e3d5408SPeter Wemm */ 73415589c42SPeter Wemm while ((this_opt = getopt(argc, argv, 735aae38d10SBaptiste Daroussin "0123456789CDIKLNQR:TUVWace:fGgo:qrstvwx")) != -1) { 7360e3d5408SPeter Wemm if (isdigit(this_opt)) { 7370e3d5408SPeter Wemm switch (last_opt) { 738aae38d10SBaptiste Daroussin case 'Q': 739aae38d10SBaptiste Daroussin add_digit(&quickdump, this_opt); 740aae38d10SBaptiste Daroussin break; 7410e3d5408SPeter Wemm case 'v': 742aae38d10SBaptiste Daroussin add_digit(&v_opt, this_opt); 7430e3d5408SPeter Wemm break; 7440e3d5408SPeter Wemm case 'w': 745aae38d10SBaptiste Daroussin add_digit(&width, this_opt); 7460e3d5408SPeter Wemm break; 7470e3d5408SPeter Wemm default: 74873f0a83dSXin LI switch (this_opt) { 74973f0a83dSXin LI case '0': 75073f0a83dSXin LI last_opt = this_opt; 75173f0a83dSXin LI width = 65535; 75273f0a83dSXin LI height = 1; 75373f0a83dSXin LI break; 75473f0a83dSXin LI case '1': 7550e3d5408SPeter Wemm last_opt = this_opt; 7560e3d5408SPeter Wemm width = 0; 75773f0a83dSXin LI break; 75873f0a83dSXin LI default: 75973f0a83dSXin LI usage(); 76073f0a83dSXin LI } 7610e3d5408SPeter Wemm } 7620e3d5408SPeter Wemm continue; 7630e3d5408SPeter Wemm } 7640e3d5408SPeter Wemm switch (this_opt) { 76573f0a83dSXin LI case 'K': 76673f0a83dSXin LI _nc_strict_bsd = 1; 76773f0a83dSXin LI /* the initial version of -K in 20110730 fell-thru here, but the 76873f0a83dSXin LI * same flag is useful when reading sources -TD 76973f0a83dSXin LI */ 77073f0a83dSXin LI break; 7710e3d5408SPeter Wemm case 'C': 7720e3d5408SPeter Wemm capdump = TRUE; 7730e3d5408SPeter Wemm outform = F_TERMCAP; 7740e3d5408SPeter Wemm sortmode = S_TERMCAP; 7750e3d5408SPeter Wemm break; 77673f0a83dSXin LI case 'D': 77773f0a83dSXin LI debug_level = VtoTrace(v_opt); 77873f0a83dSXin LI set_trace_level(debug_level); 77973f0a83dSXin LI show_databases(outdir); 78073f0a83dSXin LI ExitProgram(EXIT_SUCCESS); 78173f0a83dSXin LI break; 7820e3d5408SPeter Wemm case 'I': 7830e3d5408SPeter Wemm infodump = TRUE; 7840e3d5408SPeter Wemm outform = F_TERMINFO; 7850e3d5408SPeter Wemm sortmode = S_TERMINFO; 7860e3d5408SPeter Wemm break; 7870e3d5408SPeter Wemm case 'L': 7880e3d5408SPeter Wemm infodump = TRUE; 7890e3d5408SPeter Wemm outform = F_VARIABLE; 7900e3d5408SPeter Wemm sortmode = S_VARIABLE; 7910e3d5408SPeter Wemm break; 7920e3d5408SPeter Wemm case 'N': 7930e3d5408SPeter Wemm smart_defaults = FALSE; 7944a1a9510SRong-En Fan literal = TRUE; 7950e3d5408SPeter Wemm break; 796aae38d10SBaptiste Daroussin case 'Q': 797aae38d10SBaptiste Daroussin quickdump = 0; 798aae38d10SBaptiste Daroussin break; 7990e3d5408SPeter Wemm case 'R': 8000e3d5408SPeter Wemm tversion = optarg; 8010e3d5408SPeter Wemm break; 8020e3d5408SPeter Wemm case 'T': 8030e3d5408SPeter Wemm limited = FALSE; 8040e3d5408SPeter Wemm break; 8054a1a9510SRong-En Fan case 'U': 8064a1a9510SRong-En Fan literal = TRUE; 8074a1a9510SRong-En Fan break; 8080e3d5408SPeter Wemm case 'V': 80918259542SPeter Wemm puts(curses_version()); 8105d08fb1fSRong-En Fan ExitProgram(EXIT_SUCCESS); 811aae38d10SBaptiste Daroussin case 'W': 812aae38d10SBaptiste Daroussin wrap_strings = TRUE; 813aae38d10SBaptiste Daroussin break; 8140e3d5408SPeter Wemm case 'c': 8150e3d5408SPeter Wemm check_only = TRUE; 8160e3d5408SPeter Wemm break; 8170e3d5408SPeter Wemm case 'e': 8180e3d5408SPeter Wemm namelst = make_namelist(optarg); 8190e3d5408SPeter Wemm break; 8200e3d5408SPeter Wemm case 'f': 8210e3d5408SPeter Wemm formatted = TRUE; 8220e3d5408SPeter Wemm break; 8230e3d5408SPeter Wemm case 'G': 8240e3d5408SPeter Wemm numbers = 1; 8250e3d5408SPeter Wemm break; 8260e3d5408SPeter Wemm case 'g': 8270e3d5408SPeter Wemm numbers = -1; 8280e3d5408SPeter Wemm break; 8290e3d5408SPeter Wemm case 'o': 8300e3d5408SPeter Wemm outdir = optarg; 8310e3d5408SPeter Wemm break; 832aae38d10SBaptiste Daroussin case 'q': 833aae38d10SBaptiste Daroussin quiet = TRUE; 834aae38d10SBaptiste Daroussin break; 8350e3d5408SPeter Wemm case 'r': 8360e3d5408SPeter Wemm forceresolve = TRUE; 8370e3d5408SPeter Wemm break; 8380e3d5408SPeter Wemm case 's': 8390e3d5408SPeter Wemm showsummary = TRUE; 8400e3d5408SPeter Wemm break; 8410e3d5408SPeter Wemm case 'v': 8420e3d5408SPeter Wemm v_opt = 0; 8430e3d5408SPeter Wemm break; 8440e3d5408SPeter Wemm case 'w': 8450e3d5408SPeter Wemm width = 0; 8460e3d5408SPeter Wemm break; 8470e3d5408SPeter Wemm #if NCURSES_XNAMES 8484a1a9510SRong-En Fan case 't': 8494a1a9510SRong-En Fan _nc_disable_period = FALSE; 8504a1a9510SRong-En Fan suppress_untranslatable = TRUE; 8514a1a9510SRong-En Fan break; 85215589c42SPeter Wemm case 'a': 85315589c42SPeter Wemm _nc_disable_period = TRUE; 85415589c42SPeter Wemm /* FALLTHRU */ 8550e3d5408SPeter Wemm case 'x': 8560e3d5408SPeter Wemm use_extended_names(TRUE); 857aae38d10SBaptiste Daroussin using_extensions = TRUE; 8580e3d5408SPeter Wemm break; 8590e3d5408SPeter Wemm #endif 8600e3d5408SPeter Wemm default: 8610e3d5408SPeter Wemm usage(); 8620e3d5408SPeter Wemm } 8630e3d5408SPeter Wemm last_opt = this_opt; 8640e3d5408SPeter Wemm } 8650e3d5408SPeter Wemm 86673f0a83dSXin LI debug_level = VtoTrace(v_opt); 86715589c42SPeter Wemm set_trace_level(debug_level); 8680e3d5408SPeter Wemm 86915589c42SPeter Wemm if (_nc_tracing) { 8704a1a9510SRong-En Fan save_check_termtype = _nc_check_termtype2; 8714a1a9510SRong-En Fan _nc_check_termtype2 = check_termtype; 8720e3d5408SPeter Wemm } 87318259542SPeter Wemm #if !HAVE_BIG_CORE 8740e3d5408SPeter Wemm /* 8750e3d5408SPeter Wemm * Aaargh! immedhook seriously hoses us! 8760e3d5408SPeter Wemm * 8770e3d5408SPeter Wemm * One problem with immedhook is it means we can't do -e. Problem 8780e3d5408SPeter Wemm * is that we can't guarantee that for each terminal listed, all the 8790e3d5408SPeter Wemm * terminals it depends on will have been kept in core for reference 8800e3d5408SPeter Wemm * resolution -- in fact it's certain the primitive types at the end 8810e3d5408SPeter Wemm * of reference chains *won't* be in core unless they were explicitly 8820e3d5408SPeter Wemm * in the select list themselves. 8830e3d5408SPeter Wemm */ 88415589c42SPeter Wemm if (namelst && (!infodump && !capdump)) { 8850e3d5408SPeter Wemm (void) fprintf(stderr, 88673f0a83dSXin LI "%s: Sorry, -e can't be used without -I or -C\n", 88773f0a83dSXin LI _nc_progname); 8884a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 8890e3d5408SPeter Wemm } 8900e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */ 8910e3d5408SPeter Wemm 8920e3d5408SPeter Wemm if (optind < argc) { 8930e3d5408SPeter Wemm source_file = argv[optind++]; 8940e3d5408SPeter Wemm if (optind < argc) { 8950e3d5408SPeter Wemm fprintf(stderr, 8960e3d5408SPeter Wemm "%s: Too many file names. Usage:\n\t%s %s", 8970e3d5408SPeter Wemm _nc_progname, 8980e3d5408SPeter Wemm _nc_progname, 8990e3d5408SPeter Wemm usage_string); 9004a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 9010e3d5408SPeter Wemm } 9020e3d5408SPeter Wemm } else { 9030e3d5408SPeter Wemm if (infodump == TRUE) { 9040e3d5408SPeter Wemm /* captoinfo's no-argument case */ 9050e3d5408SPeter Wemm source_file = "/etc/termcap"; 9060e3d5408SPeter Wemm if ((termcap = getenv("TERMCAP")) != 0 9070e3d5408SPeter Wemm && (namelst = make_namelist(getenv("TERM"))) != 0) { 9080e3d5408SPeter Wemm if (access(termcap, F_OK) == 0) { 9090e3d5408SPeter Wemm /* file exists */ 9100e3d5408SPeter Wemm source_file = termcap; 91173f0a83dSXin LI } else { 91273f0a83dSXin LI if ((tmp_fp = open_tempfile(my_tmpname)) != 0) { 91315589c42SPeter Wemm source_file = my_tmpname; 9140e3d5408SPeter Wemm fprintf(tmp_fp, "%s\n", termcap); 9150e3d5408SPeter Wemm fclose(tmp_fp); 91673f0a83dSXin LI tmp_fp = open_input(source_file, (char *) 0); 9170e3d5408SPeter Wemm to_remove = source_file; 9180e3d5408SPeter Wemm } else { 9190e3d5408SPeter Wemm failed("tmpnam"); 9200e3d5408SPeter Wemm } 9210e3d5408SPeter Wemm } 92273f0a83dSXin LI } 9230e3d5408SPeter Wemm } else { 9240e3d5408SPeter Wemm /* tic */ 9250e3d5408SPeter Wemm fprintf(stderr, 9260e3d5408SPeter Wemm "%s: File name needed. Usage:\n\t%s %s", 9270e3d5408SPeter Wemm _nc_progname, 9280e3d5408SPeter Wemm _nc_progname, 9290e3d5408SPeter Wemm usage_string); 9304a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 9310e3d5408SPeter Wemm } 9320e3d5408SPeter Wemm } 9330e3d5408SPeter Wemm 93473f0a83dSXin LI if (tmp_fp == 0) { 93573f0a83dSXin LI tmp_fp = open_input(source_file, my_altfile); 93673f0a83dSXin LI if (!strcmp(source_file, "-")) { 93773f0a83dSXin LI source_file = STDIN_NAME; 93873f0a83dSXin LI } 93973f0a83dSXin LI } 9400e3d5408SPeter Wemm 941aae38d10SBaptiste Daroussin if (infodump || check_only) { 9420e3d5408SPeter Wemm dump_init(tversion, 943aae38d10SBaptiste Daroussin (smart_defaults 9440e3d5408SPeter Wemm ? outform 945aae38d10SBaptiste Daroussin : F_LITERAL), 946aae38d10SBaptiste Daroussin sortmode, 947aae38d10SBaptiste Daroussin wrap_strings, width, height, 948aae38d10SBaptiste Daroussin debug_level, formatted || check_only, check_only, quickdump); 94973f0a83dSXin LI } else if (capdump) { 9500e3d5408SPeter Wemm dump_init(tversion, 9510e3d5408SPeter Wemm outform, 952aae38d10SBaptiste Daroussin sortmode, 953aae38d10SBaptiste Daroussin wrap_strings, width, height, 954aae38d10SBaptiste Daroussin debug_level, FALSE, FALSE, FALSE); 95573f0a83dSXin LI } 9560e3d5408SPeter Wemm 9570e3d5408SPeter Wemm /* parse entries out of the source file */ 9580e3d5408SPeter Wemm _nc_set_source(source_file); 95918259542SPeter Wemm #if !HAVE_BIG_CORE 9600e3d5408SPeter Wemm if (!(check_only || infodump || capdump)) 9610e3d5408SPeter Wemm _nc_set_writedir(outdir); 9620e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */ 9630e3d5408SPeter Wemm _nc_read_entry_source(tmp_fp, (char *) NULL, 9644a1a9510SRong-En Fan !smart_defaults || literal, FALSE, 9654a1a9510SRong-En Fan ((check_only || infodump || capdump) 9664a1a9510SRong-En Fan ? NULLHOOK 9674a1a9510SRong-En Fan : immedhook)); 9680e3d5408SPeter Wemm 9690e3d5408SPeter Wemm /* do use resolution */ 9700e3d5408SPeter Wemm if (check_only || (!infodump && !capdump) || forceresolve) { 9714a1a9510SRong-En Fan if (!_nc_resolve_uses2(TRUE, literal) && !check_only) { 9724a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 9730e3d5408SPeter Wemm } 9740e3d5408SPeter Wemm } 9750e3d5408SPeter Wemm 9760e3d5408SPeter Wemm /* length check */ 977aae38d10SBaptiste Daroussin if (check_only && limited && (capdump || infodump)) { 97815589c42SPeter Wemm for_entry_list(qp) { 97915589c42SPeter Wemm if (matches(namelst, qp->tterm.term_names)) { 9804a1a9510SRong-En Fan int len = fmt_entry(&qp->tterm, NULL, FALSE, TRUE, infodump, numbers); 9810e3d5408SPeter Wemm 9820e3d5408SPeter Wemm if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH)) 9830e3d5408SPeter Wemm (void) fprintf(stderr, 984aae38d10SBaptiste Daroussin "%s: resolved %s entry is %d bytes long\n", 985aae38d10SBaptiste Daroussin _nc_progname, 9860e3d5408SPeter Wemm _nc_first_name(qp->tterm.term_names), 9870e3d5408SPeter Wemm len); 9880e3d5408SPeter Wemm } 9890e3d5408SPeter Wemm } 9900e3d5408SPeter Wemm } 9910e3d5408SPeter Wemm 9920e3d5408SPeter Wemm /* write or dump all entries */ 993aae38d10SBaptiste Daroussin if (check_only) { 994aae38d10SBaptiste Daroussin /* this is in case infotocap() generates warnings */ 995aae38d10SBaptiste Daroussin _nc_curr_col = _nc_curr_line = -1; 996aae38d10SBaptiste Daroussin 997aae38d10SBaptiste Daroussin for_entry_list(qp) { 998aae38d10SBaptiste Daroussin if (matches(namelst, qp->tterm.term_names)) { 999aae38d10SBaptiste Daroussin /* this is in case infotocap() generates warnings */ 1000aae38d10SBaptiste Daroussin _nc_set_type(_nc_first_name(qp->tterm.term_names)); 1001aae38d10SBaptiste Daroussin _nc_curr_line = (int) qp->startline; 1002aae38d10SBaptiste Daroussin repair_acsc(&qp->tterm); 1003aae38d10SBaptiste Daroussin dump_entry(&qp->tterm, suppress_untranslatable, 1004aae38d10SBaptiste Daroussin limited, numbers, NULL); 1005aae38d10SBaptiste Daroussin } 1006aae38d10SBaptiste Daroussin } 1007aae38d10SBaptiste Daroussin } else { 100815589c42SPeter Wemm if (!infodump && !capdump) { 10090e3d5408SPeter Wemm _nc_set_writedir(outdir); 101015589c42SPeter Wemm for_entry_list(qp) { 10110e3d5408SPeter Wemm if (matches(namelst, qp->tterm.term_names)) 10120e3d5408SPeter Wemm write_it(qp); 10130e3d5408SPeter Wemm } 101415589c42SPeter Wemm } else { 10150e3d5408SPeter Wemm /* this is in case infotocap() generates warnings */ 10160e3d5408SPeter Wemm _nc_curr_col = _nc_curr_line = -1; 10170e3d5408SPeter Wemm 101815589c42SPeter Wemm for_entry_list(qp) { 101915589c42SPeter Wemm if (matches(namelst, qp->tterm.term_names)) { 102073f0a83dSXin LI long j = qp->cend - qp->cstart; 10210e3d5408SPeter Wemm int len = 0; 10220e3d5408SPeter Wemm 10230e3d5408SPeter Wemm /* this is in case infotocap() generates warnings */ 10240e3d5408SPeter Wemm _nc_set_type(_nc_first_name(qp->tterm.term_names)); 10250e3d5408SPeter Wemm 1026aae38d10SBaptiste Daroussin if (!quiet) { 10270e3d5408SPeter Wemm (void) fseek(tmp_fp, qp->cstart, SEEK_SET); 10284a1a9510SRong-En Fan while (j-- > 0) { 1029aae38d10SBaptiste Daroussin int ch = fgetc(tmp_fp); 1030aae38d10SBaptiste Daroussin if (ch == EOF || ferror(tmp_fp)) { 1031aae38d10SBaptiste Daroussin break; 1032aae38d10SBaptiste Daroussin } else if (infodump) { 1033aae38d10SBaptiste Daroussin (void) putchar(ch); 1034aae38d10SBaptiste Daroussin } else { 1035aae38d10SBaptiste Daroussin put_translate(ch); 1036aae38d10SBaptiste Daroussin } 1037aae38d10SBaptiste Daroussin } 103815589c42SPeter Wemm } 10390e3d5408SPeter Wemm 104006bfebdeSXin LI repair_acsc(&qp->tterm); 10414a1a9510SRong-En Fan dump_entry(&qp->tterm, suppress_untranslatable, 10424a1a9510SRong-En Fan limited, numbers, NULL); 104373f0a83dSXin LI for (j = 0; j < (long) qp->nuses; j++) 10444a1a9510SRong-En Fan dump_uses(qp->uses[j].name, !capdump); 10454a1a9510SRong-En Fan len = show_entry(); 10460e3d5408SPeter Wemm if (debug_level != 0 && !limited) 10470e3d5408SPeter Wemm printf("# length=%d\n", len); 10480e3d5408SPeter Wemm } 104915589c42SPeter Wemm } 1050aae38d10SBaptiste Daroussin if (!namelst && _nc_tail && !quiet) { 10510e3d5408SPeter Wemm int c, oldc = '\0'; 10520e3d5408SPeter Wemm bool in_comment = FALSE; 10530e3d5408SPeter Wemm bool trailing_comment = FALSE; 10540e3d5408SPeter Wemm 10550e3d5408SPeter Wemm (void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET); 105615589c42SPeter Wemm while ((c = fgetc(tmp_fp)) != EOF) { 10570e3d5408SPeter Wemm if (oldc == '\n') { 10580e3d5408SPeter Wemm if (c == '#') { 10590e3d5408SPeter Wemm trailing_comment = TRUE; 10600e3d5408SPeter Wemm in_comment = TRUE; 10610e3d5408SPeter Wemm } else { 10620e3d5408SPeter Wemm in_comment = FALSE; 10630e3d5408SPeter Wemm } 10640e3d5408SPeter Wemm } 10650e3d5408SPeter Wemm if (trailing_comment 10660e3d5408SPeter Wemm && (in_comment || (oldc == '\n' && c == '\n'))) 10670e3d5408SPeter Wemm putchar(c); 10680e3d5408SPeter Wemm oldc = c; 10690e3d5408SPeter Wemm } 10700e3d5408SPeter Wemm } 10710e3d5408SPeter Wemm } 10720e3d5408SPeter Wemm } 10730e3d5408SPeter Wemm 10740e3d5408SPeter Wemm /* Show the directory into which entries were written, and the total 10750e3d5408SPeter Wemm * number of entries 10760e3d5408SPeter Wemm */ 10770e3d5408SPeter Wemm if (showsummary 10780e3d5408SPeter Wemm && (!(check_only || infodump || capdump))) { 10790e3d5408SPeter Wemm int total = _nc_tic_written(); 10800e3d5408SPeter Wemm if (total != 0) 10810e3d5408SPeter Wemm fprintf(log_fp, "%d entries written to %s\n", 10820e3d5408SPeter Wemm total, 10830e3d5408SPeter Wemm _nc_tic_dir((char *) 0)); 10840e3d5408SPeter Wemm else 10850e3d5408SPeter Wemm fprintf(log_fp, "No entries written\n"); 10860e3d5408SPeter Wemm } 10874a1a9510SRong-En Fan ExitProgram(EXIT_SUCCESS); 10880e3d5408SPeter Wemm } 10890e3d5408SPeter Wemm 10900e3d5408SPeter Wemm /* 10910e3d5408SPeter Wemm * This bit of legerdemain turns all the terminfo variable names into 10920e3d5408SPeter Wemm * references to locations in the arrays Booleans, Numbers, and Strings --- 10930e3d5408SPeter Wemm * precisely what's needed (see comp_parse.c). 10940e3d5408SPeter Wemm */ 10950e3d5408SPeter Wemm #undef CUR 10960e3d5408SPeter Wemm #define CUR tp-> 10970e3d5408SPeter Wemm 109815589c42SPeter Wemm /* 10994a1a9510SRong-En Fan * Check if the alternate character-set capabilities are consistent. 11004a1a9510SRong-En Fan */ 11014a1a9510SRong-En Fan static void 1102aae38d10SBaptiste Daroussin check_acs(TERMTYPE2 *tp) 11034a1a9510SRong-En Fan { 1104aae38d10SBaptiste Daroussin int vt100_smacs = 0; 1105aae38d10SBaptiste Daroussin int vt100_rmacs = 0; 1106aae38d10SBaptiste Daroussin int vt100_enacs = 0; 1107aae38d10SBaptiste Daroussin 1108aae38d10SBaptiste Daroussin /* 1109aae38d10SBaptiste Daroussin * ena_acs is not always necessary, but if it is present, the enter/exit 1110aae38d10SBaptiste Daroussin * capabilities should be. 1111aae38d10SBaptiste Daroussin */ 1112aae38d10SBaptiste Daroussin ANDMISSING(ena_acs, enter_alt_charset_mode); 1113aae38d10SBaptiste Daroussin ANDMISSING(ena_acs, exit_alt_charset_mode); 1114aae38d10SBaptiste Daroussin PAIRED(exit_alt_charset_mode, exit_alt_charset_mode); 1115aae38d10SBaptiste Daroussin 1116aae38d10SBaptiste Daroussin /* 1117aae38d10SBaptiste Daroussin * vt100-like is frequently used, but perhaps ena_acs is missing, etc. 1118aae38d10SBaptiste Daroussin */ 1119aae38d10SBaptiste Daroussin if (VALID_STRING(enter_alt_charset_mode)) { 1120aae38d10SBaptiste Daroussin vt100_smacs = (!strcmp("\033(0", enter_alt_charset_mode) 1121aae38d10SBaptiste Daroussin ? 2 1122aae38d10SBaptiste Daroussin : (!strcmp("\016", enter_alt_charset_mode) 1123aae38d10SBaptiste Daroussin ? 1 1124aae38d10SBaptiste Daroussin : 0)); 1125aae38d10SBaptiste Daroussin } 1126aae38d10SBaptiste Daroussin if (VALID_STRING(exit_alt_charset_mode)) { 1127aae38d10SBaptiste Daroussin vt100_rmacs = (!strcmp("\033(B", exit_alt_charset_mode) 1128aae38d10SBaptiste Daroussin ? 2 1129aae38d10SBaptiste Daroussin : (!strcmp("\017", exit_alt_charset_mode) 1130aae38d10SBaptiste Daroussin ? 1 1131aae38d10SBaptiste Daroussin : 0)); 1132aae38d10SBaptiste Daroussin } 1133aae38d10SBaptiste Daroussin if (VALID_STRING(ena_acs)) { 1134aae38d10SBaptiste Daroussin vt100_enacs = (!strcmp("\033(B\033)0", ena_acs) 1135aae38d10SBaptiste Daroussin ? 2 1136aae38d10SBaptiste Daroussin : 0); 1137aae38d10SBaptiste Daroussin } 1138aae38d10SBaptiste Daroussin if (vt100_rmacs && vt100_smacs && (vt100_rmacs != vt100_smacs)) { 1139aae38d10SBaptiste Daroussin _nc_warning("rmacs/smacs are inconsistent"); 1140aae38d10SBaptiste Daroussin } 1141aae38d10SBaptiste Daroussin if ((vt100_rmacs == 2) && (vt100_smacs == 2) && vt100_enacs) { 1142aae38d10SBaptiste Daroussin _nc_warning("rmacs/smacs make enacs redundant"); 1143aae38d10SBaptiste Daroussin } 1144aae38d10SBaptiste Daroussin if ((vt100_rmacs == 1) && (vt100_smacs == 1) && !vt100_enacs) { 1145aae38d10SBaptiste Daroussin _nc_warning("VT100-style rmacs/smacs require enacs"); 1146aae38d10SBaptiste Daroussin } 1147aae38d10SBaptiste Daroussin 11484a1a9510SRong-En Fan if (VALID_STRING(acs_chars)) { 11494a1a9510SRong-En Fan const char *boxes = "lmkjtuvwqxn"; 11504a1a9510SRong-En Fan char mapped[256]; 11514a1a9510SRong-En Fan char missing[256]; 11524a1a9510SRong-En Fan const char *p; 11534a1a9510SRong-En Fan char *q; 11544a1a9510SRong-En Fan 11554a1a9510SRong-En Fan memset(mapped, 0, sizeof(mapped)); 11564a1a9510SRong-En Fan for (p = acs_chars; *p != '\0'; p += 2) { 11574a1a9510SRong-En Fan if (p[1] == '\0') { 11584a1a9510SRong-En Fan _nc_warning("acsc has odd number of characters"); 11594a1a9510SRong-En Fan break; 11604a1a9510SRong-En Fan } 11614a1a9510SRong-En Fan mapped[UChar(p[0])] = p[1]; 11624a1a9510SRong-En Fan } 11635d08fb1fSRong-En Fan 11644a1a9510SRong-En Fan if (mapped[UChar('I')] && !mapped[UChar('i')]) { 11654a1a9510SRong-En Fan _nc_warning("acsc refers to 'I', which is probably an error"); 11664a1a9510SRong-En Fan } 11675d08fb1fSRong-En Fan 11684a1a9510SRong-En Fan for (p = boxes, q = missing; *p != '\0'; ++p) { 11694a1a9510SRong-En Fan if (!mapped[UChar(p[0])]) { 11704a1a9510SRong-En Fan *q++ = p[0]; 11714a1a9510SRong-En Fan } 11724a1a9510SRong-En Fan } 11735d08fb1fSRong-En Fan *q = '\0'; 11745d08fb1fSRong-En Fan 11755d08fb1fSRong-En Fan assert(strlen(missing) <= strlen(boxes)); 11764a1a9510SRong-En Fan if (*missing != '\0' && strcmp(missing, boxes)) { 11774a1a9510SRong-En Fan _nc_warning("acsc is missing some line-drawing mapping: %s", missing); 11784a1a9510SRong-En Fan } 11794a1a9510SRong-En Fan } 11804a1a9510SRong-En Fan } 11814a1a9510SRong-En Fan 1182aae38d10SBaptiste Daroussin static bool 1183aae38d10SBaptiste Daroussin same_color(NCURSES_CONST char *oldcap, NCURSES_CONST char *newcap, int limit) 1184aae38d10SBaptiste Daroussin { 1185aae38d10SBaptiste Daroussin bool result = FALSE; 1186aae38d10SBaptiste Daroussin if (limit > 16) 1187aae38d10SBaptiste Daroussin limit = 16; 1188aae38d10SBaptiste Daroussin if (limit >= 8) { 1189aae38d10SBaptiste Daroussin int n; 1190aae38d10SBaptiste Daroussin int same; 1191aae38d10SBaptiste Daroussin for (n = same = 0; n < limit; ++n) { 1192aae38d10SBaptiste Daroussin char *oldvalue = strdup(TPARM_1(oldcap, n)); 1193aae38d10SBaptiste Daroussin char *newvalue = strdup(TPARM_1(newcap, n)); 1194aae38d10SBaptiste Daroussin same += !strcmp(oldvalue, newvalue); 1195aae38d10SBaptiste Daroussin free(oldvalue); 1196aae38d10SBaptiste Daroussin free(newvalue); 1197aae38d10SBaptiste Daroussin } 1198aae38d10SBaptiste Daroussin result = (same == limit); 1199aae38d10SBaptiste Daroussin } 1200aae38d10SBaptiste Daroussin return result; 1201aae38d10SBaptiste Daroussin } 1202aae38d10SBaptiste Daroussin 12034a1a9510SRong-En Fan /* 12044a1a9510SRong-En Fan * Check if the color capabilities are consistent 12054a1a9510SRong-En Fan */ 12064a1a9510SRong-En Fan static void 1207aae38d10SBaptiste Daroussin check_colors(TERMTYPE2 *tp) 12084a1a9510SRong-En Fan { 1209aae38d10SBaptiste Daroussin char *value; 1210aae38d10SBaptiste Daroussin 12114a1a9510SRong-En Fan if ((max_colors > 0) != (max_pairs > 0) 12124a1a9510SRong-En Fan || ((max_colors > max_pairs) && (initialize_pair == 0))) 12134a1a9510SRong-En Fan _nc_warning("inconsistent values for max_colors (%d) and max_pairs (%d)", 12144a1a9510SRong-En Fan max_colors, max_pairs); 12154a1a9510SRong-En Fan 12164a1a9510SRong-En Fan PAIRED(set_foreground, set_background); 12174a1a9510SRong-En Fan PAIRED(set_a_foreground, set_a_background); 12184a1a9510SRong-En Fan PAIRED(set_color_pair, initialize_pair); 12194a1a9510SRong-En Fan 12204a1a9510SRong-En Fan if (VALID_STRING(set_foreground) 1221aae38d10SBaptiste Daroussin && VALID_STRING(set_a_foreground)) { 1222aae38d10SBaptiste Daroussin if (!_nc_capcmp(set_foreground, set_a_foreground)) { 12234a1a9510SRong-En Fan _nc_warning("expected setf/setaf to be different"); 1224aae38d10SBaptiste Daroussin } else if (same_color(set_foreground, set_a_foreground, max_colors)) { 1225aae38d10SBaptiste Daroussin _nc_warning("setf/setaf are equivalent"); 1226aae38d10SBaptiste Daroussin } 1227aae38d10SBaptiste Daroussin } 12284a1a9510SRong-En Fan 12294a1a9510SRong-En Fan if (VALID_STRING(set_background) 1230aae38d10SBaptiste Daroussin && VALID_STRING(set_a_background)) { 1231aae38d10SBaptiste Daroussin if (!_nc_capcmp(set_background, set_a_background)) { 12324a1a9510SRong-En Fan _nc_warning("expected setb/setab to be different"); 1233aae38d10SBaptiste Daroussin } else if (same_color(set_background, set_a_background, max_colors)) { 1234aae38d10SBaptiste Daroussin _nc_warning("setb/setab are equivalent"); 1235aae38d10SBaptiste Daroussin } 1236aae38d10SBaptiste Daroussin } 12374a1a9510SRong-En Fan 12384a1a9510SRong-En Fan /* see: has_colors() */ 12394a1a9510SRong-En Fan if (VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs) 1240aae38d10SBaptiste Daroussin && ((VALID_STRING(set_foreground) 1241aae38d10SBaptiste Daroussin && VALID_STRING(set_background)) 1242aae38d10SBaptiste Daroussin || (VALID_STRING(set_a_foreground) 1243aae38d10SBaptiste Daroussin && VALID_STRING(set_a_background)) 12444a1a9510SRong-En Fan || set_color_pair)) { 12454a1a9510SRong-En Fan if (!VALID_STRING(orig_pair) && !VALID_STRING(orig_colors)) 12464a1a9510SRong-En Fan _nc_warning("expected either op/oc string for resetting colors"); 12474a1a9510SRong-En Fan } 1248aae38d10SBaptiste Daroussin if (can_change) { 1249aae38d10SBaptiste Daroussin if (!VALID_STRING(initialize_pair) && 1250aae38d10SBaptiste Daroussin !VALID_STRING(initialize_color)) { 1251aae38d10SBaptiste Daroussin _nc_warning("expected initc or initp because ccc is given"); 1252aae38d10SBaptiste Daroussin } 1253aae38d10SBaptiste Daroussin } else { 1254aae38d10SBaptiste Daroussin if (VALID_STRING(initialize_pair) || 1255aae38d10SBaptiste Daroussin VALID_STRING(initialize_color)) { 1256aae38d10SBaptiste Daroussin _nc_warning("expected ccc because initc is given"); 1257aae38d10SBaptiste Daroussin } 1258aae38d10SBaptiste Daroussin } 1259aae38d10SBaptiste Daroussin value = tigetstr("RGB"); 1260aae38d10SBaptiste Daroussin if (VALID_STRING(value)) { 1261aae38d10SBaptiste Daroussin int r, g, b; 1262aae38d10SBaptiste Daroussin char bad; 1263aae38d10SBaptiste Daroussin int code = sscanf(value, "%d/%d/%d%c", &r, &g, &b, &bad); 1264aae38d10SBaptiste Daroussin if (code != 3 || r <= 0 || g <= 0 || b <= 0) { 1265aae38d10SBaptiste Daroussin _nc_warning("unexpected value for RGB capability: %s", value); 1266aae38d10SBaptiste Daroussin } 1267aae38d10SBaptiste Daroussin } 1268aae38d10SBaptiste Daroussin } 1269aae38d10SBaptiste Daroussin 1270aae38d10SBaptiste Daroussin static int 1271aae38d10SBaptiste Daroussin csi_length(const char *value) 1272aae38d10SBaptiste Daroussin { 1273aae38d10SBaptiste Daroussin int result = 0; 1274aae38d10SBaptiste Daroussin 1275aae38d10SBaptiste Daroussin if (value[0] == '\033' && value[1] == '[') { 1276aae38d10SBaptiste Daroussin result = 2; 1277aae38d10SBaptiste Daroussin } else if (UChar(value[0]) == 0x9a) { 1278aae38d10SBaptiste Daroussin result = 1; 1279aae38d10SBaptiste Daroussin } 1280aae38d10SBaptiste Daroussin return result; 12814a1a9510SRong-En Fan } 12824a1a9510SRong-En Fan 12835d08fb1fSRong-En Fan static char 12844a1a9510SRong-En Fan keypad_final(const char *string) 12854a1a9510SRong-En Fan { 12865d08fb1fSRong-En Fan char result = '\0'; 12874a1a9510SRong-En Fan 12884a1a9510SRong-En Fan if (VALID_STRING(string) 12894a1a9510SRong-En Fan && *string++ == '\033' 12904a1a9510SRong-En Fan && *string++ == 'O' 12914a1a9510SRong-En Fan && strlen(string) == 1) { 12924a1a9510SRong-En Fan result = *string; 12934a1a9510SRong-En Fan } 12944a1a9510SRong-En Fan 12954a1a9510SRong-En Fan return result; 12964a1a9510SRong-En Fan } 12974a1a9510SRong-En Fan 129873f0a83dSXin LI static long 12994a1a9510SRong-En Fan keypad_index(const char *string) 13004a1a9510SRong-En Fan { 13014a1a9510SRong-En Fan char *test; 13024a1a9510SRong-En Fan const char *list = "PQRSwxymtuvlqrsPpn"; /* app-keypad except "Enter" */ 13034a1a9510SRong-En Fan int ch; 130473f0a83dSXin LI long result = -1; 13054a1a9510SRong-En Fan 13064a1a9510SRong-En Fan if ((ch = keypad_final(string)) != '\0') { 130773f0a83dSXin LI test = (strchr) (list, ch); 13084a1a9510SRong-En Fan if (test != 0) 130973f0a83dSXin LI result = (long) (test - list); 13104a1a9510SRong-En Fan } 13114a1a9510SRong-En Fan return result; 13124a1a9510SRong-En Fan } 13134a1a9510SRong-En Fan 131406bfebdeSXin LI /* 131506bfebdeSXin LI * list[] is down, up, left, right 131606bfebdeSXin LI * "left" may be ^H rather than \E[D 131706bfebdeSXin LI * "down" may be ^J rather than \E[B 131806bfebdeSXin LI * But up/right are generally consistently escape sequences for ANSI terminals. 131906bfebdeSXin LI */ 132006bfebdeSXin LI static void 132106bfebdeSXin LI check_ansi_cursor(char *list[4]) 132206bfebdeSXin LI { 132306bfebdeSXin LI int j, k; 132406bfebdeSXin LI int want; 132506bfebdeSXin LI size_t suffix; 132606bfebdeSXin LI bool skip[4]; 132706bfebdeSXin LI bool repeated = FALSE; 132806bfebdeSXin LI 132906bfebdeSXin LI for (j = 0; j < 4; ++j) { 133006bfebdeSXin LI skip[j] = FALSE; 133106bfebdeSXin LI for (k = 0; k < j; ++k) { 133206bfebdeSXin LI if (j != k 133306bfebdeSXin LI && !strcmp(list[j], list[k])) { 133406bfebdeSXin LI char *value = _nc_tic_expand(list[k], TRUE, 0); 133506bfebdeSXin LI _nc_warning("repeated cursor control %s\n", value); 133606bfebdeSXin LI repeated = TRUE; 133706bfebdeSXin LI } 133806bfebdeSXin LI } 133906bfebdeSXin LI } 134006bfebdeSXin LI if (!repeated) { 134106bfebdeSXin LI char *up = list[1]; 1342aae38d10SBaptiste Daroussin size_t prefix = (size_t) csi_length(up); 134306bfebdeSXin LI 134406bfebdeSXin LI if (prefix) { 134506bfebdeSXin LI suffix = prefix; 134606bfebdeSXin LI while (up[suffix] && isdigit(UChar(up[suffix]))) 134706bfebdeSXin LI ++suffix; 134806bfebdeSXin LI } 134906bfebdeSXin LI if (prefix && up[suffix] == 'A') { 135006bfebdeSXin LI skip[1] = TRUE; 135106bfebdeSXin LI if (!strcmp(list[0], "\n")) 135206bfebdeSXin LI skip[0] = TRUE; 135306bfebdeSXin LI if (!strcmp(list[2], "\b")) 135406bfebdeSXin LI skip[2] = TRUE; 135506bfebdeSXin LI 135606bfebdeSXin LI for (j = 0; j < 4; ++j) { 135706bfebdeSXin LI if (skip[j] || strlen(list[j]) == 1) 135806bfebdeSXin LI continue; 135906bfebdeSXin LI if (memcmp(list[j], up, prefix)) { 136006bfebdeSXin LI char *value = _nc_tic_expand(list[j], TRUE, 0); 136106bfebdeSXin LI _nc_warning("inconsistent prefix for %s\n", value); 136206bfebdeSXin LI continue; 136306bfebdeSXin LI } 136406bfebdeSXin LI if (strlen(list[j]) < suffix) { 136506bfebdeSXin LI char *value = _nc_tic_expand(list[j], TRUE, 0); 136606bfebdeSXin LI _nc_warning("inconsistent length for %s, expected %d\n", 136706bfebdeSXin LI value, (int) suffix + 1); 136806bfebdeSXin LI continue; 136906bfebdeSXin LI } 137006bfebdeSXin LI want = "BADC"[j]; 137106bfebdeSXin LI if (list[j][suffix] != want) { 137206bfebdeSXin LI char *value = _nc_tic_expand(list[j], TRUE, 0); 137306bfebdeSXin LI _nc_warning("inconsistent suffix for %s, expected %c, have %c\n", 137406bfebdeSXin LI value, want, list[j][suffix]); 137506bfebdeSXin LI } 137606bfebdeSXin LI } 137706bfebdeSXin LI } 137806bfebdeSXin LI } 137906bfebdeSXin LI } 138006bfebdeSXin LI 138106bfebdeSXin LI #define EXPECTED(name) if (!PRESENT(name)) _nc_warning("expected " #name) 138273f0a83dSXin LI #define UNEXPECTED(name) if (PRESENT(name)) _nc_warning("unexpected " #name ", for %s", why) 138373f0a83dSXin LI 138473f0a83dSXin LI static void 1385aae38d10SBaptiste Daroussin check_noaddress(TERMTYPE2 *tp, const char *why) 138673f0a83dSXin LI { 138773f0a83dSXin LI UNEXPECTED(column_address); 138873f0a83dSXin LI UNEXPECTED(cursor_address); 138973f0a83dSXin LI UNEXPECTED(cursor_home); 139073f0a83dSXin LI UNEXPECTED(cursor_mem_address); 139173f0a83dSXin LI UNEXPECTED(cursor_to_ll); 139273f0a83dSXin LI UNEXPECTED(row_address); 139373f0a83dSXin LI UNEXPECTED(row_address); 139473f0a83dSXin LI } 139506bfebdeSXin LI 139606bfebdeSXin LI static void 1397aae38d10SBaptiste Daroussin check_cursor(TERMTYPE2 *tp) 139806bfebdeSXin LI { 139906bfebdeSXin LI int count; 140006bfebdeSXin LI char *list[4]; 140106bfebdeSXin LI 140273f0a83dSXin LI if (hard_copy) { 140373f0a83dSXin LI check_noaddress(tp, "hard_copy"); 140473f0a83dSXin LI } else if (generic_type) { 140573f0a83dSXin LI check_noaddress(tp, "generic_type"); 140673f0a83dSXin LI } else if (strchr(tp->term_names, '+') == 0) { 140773f0a83dSXin LI int y = 0; 140873f0a83dSXin LI int x = 0; 140973f0a83dSXin LI if (PRESENT(column_address)) 141073f0a83dSXin LI ++y; 141173f0a83dSXin LI if (PRESENT(cursor_address)) 141273f0a83dSXin LI y = x = 10; 141373f0a83dSXin LI if (PRESENT(cursor_home)) 141473f0a83dSXin LI ++y, ++x; 141573f0a83dSXin LI if (PRESENT(cursor_mem_address)) 141673f0a83dSXin LI y = x = 10; 141773f0a83dSXin LI if (PRESENT(cursor_to_ll)) 141873f0a83dSXin LI ++y, ++x; 141973f0a83dSXin LI if (PRESENT(row_address)) 142073f0a83dSXin LI ++x; 142173f0a83dSXin LI if (PRESENT(cursor_down)) 142273f0a83dSXin LI ++y; 142373f0a83dSXin LI if (PRESENT(cursor_up)) 142473f0a83dSXin LI ++y; 142573f0a83dSXin LI if (PRESENT(cursor_left)) 142673f0a83dSXin LI ++x; 142773f0a83dSXin LI if (PRESENT(cursor_right)) 142873f0a83dSXin LI ++x; 142973f0a83dSXin LI if (x < 2 && y < 2) { 143073f0a83dSXin LI _nc_warning("terminal lacks cursor addressing"); 143173f0a83dSXin LI } else { 143273f0a83dSXin LI if (x < 2) 143373f0a83dSXin LI _nc_warning("terminal lacks cursor column-addressing"); 143473f0a83dSXin LI if (y < 2) 143573f0a83dSXin LI _nc_warning("terminal lacks cursor row-addressing"); 143673f0a83dSXin LI } 143773f0a83dSXin LI } 143873f0a83dSXin LI 143973f0a83dSXin LI /* it is rare to have an insert-line feature without a matching delete */ 144073f0a83dSXin LI ANDMISSING(parm_insert_line, insert_line); 144173f0a83dSXin LI ANDMISSING(parm_delete_line, delete_line); 144273f0a83dSXin LI ANDMISSING(parm_insert_line, parm_delete_line); 144373f0a83dSXin LI 144406bfebdeSXin LI /* if we have a parameterized form, then the non-parameterized is easy */ 144506bfebdeSXin LI ANDMISSING(parm_down_cursor, cursor_down); 144606bfebdeSXin LI ANDMISSING(parm_up_cursor, cursor_up); 144706bfebdeSXin LI ANDMISSING(parm_left_cursor, cursor_left); 144806bfebdeSXin LI ANDMISSING(parm_right_cursor, cursor_right); 144906bfebdeSXin LI 145006bfebdeSXin LI /* Given any of a set of cursor movement, the whole set should be present. 145106bfebdeSXin LI * Technically this is not true (we could use cursor_address to fill in 145206bfebdeSXin LI * unsupported controls), but it is likely. 145306bfebdeSXin LI */ 145406bfebdeSXin LI count = 0; 145506bfebdeSXin LI if (PRESENT(parm_down_cursor)) { 145606bfebdeSXin LI list[count++] = parm_down_cursor; 145706bfebdeSXin LI } 145806bfebdeSXin LI if (PRESENT(parm_up_cursor)) { 145906bfebdeSXin LI list[count++] = parm_up_cursor; 146006bfebdeSXin LI } 146106bfebdeSXin LI if (PRESENT(parm_left_cursor)) { 146206bfebdeSXin LI list[count++] = parm_left_cursor; 146306bfebdeSXin LI } 146406bfebdeSXin LI if (PRESENT(parm_right_cursor)) { 146506bfebdeSXin LI list[count++] = parm_right_cursor; 146606bfebdeSXin LI } 146706bfebdeSXin LI if (count == 4) { 146806bfebdeSXin LI check_ansi_cursor(list); 146906bfebdeSXin LI } else if (count != 0) { 147006bfebdeSXin LI EXPECTED(parm_down_cursor); 147106bfebdeSXin LI EXPECTED(parm_up_cursor); 147206bfebdeSXin LI EXPECTED(parm_left_cursor); 147306bfebdeSXin LI EXPECTED(parm_right_cursor); 147406bfebdeSXin LI } 147506bfebdeSXin LI 147606bfebdeSXin LI count = 0; 147706bfebdeSXin LI if (PRESENT(cursor_down)) { 147806bfebdeSXin LI list[count++] = cursor_down; 147906bfebdeSXin LI } 148006bfebdeSXin LI if (PRESENT(cursor_up)) { 148106bfebdeSXin LI list[count++] = cursor_up; 148206bfebdeSXin LI } 148306bfebdeSXin LI if (PRESENT(cursor_left)) { 148406bfebdeSXin LI list[count++] = cursor_left; 148506bfebdeSXin LI } 148606bfebdeSXin LI if (PRESENT(cursor_right)) { 148706bfebdeSXin LI list[count++] = cursor_right; 148806bfebdeSXin LI } 148906bfebdeSXin LI if (count == 4) { 149006bfebdeSXin LI check_ansi_cursor(list); 149106bfebdeSXin LI } else if (count != 0) { 149206bfebdeSXin LI count = 0; 149306bfebdeSXin LI if (PRESENT(cursor_down) && strcmp(cursor_down, "\n")) 149406bfebdeSXin LI ++count; 149506bfebdeSXin LI if (PRESENT(cursor_left) && strcmp(cursor_left, "\b")) 149606bfebdeSXin LI ++count; 149706bfebdeSXin LI if (PRESENT(cursor_up) && strlen(cursor_up) > 1) 149806bfebdeSXin LI ++count; 149906bfebdeSXin LI if (PRESENT(cursor_right) && strlen(cursor_right) > 1) 150006bfebdeSXin LI ++count; 150106bfebdeSXin LI if (count) { 150206bfebdeSXin LI EXPECTED(cursor_down); 150306bfebdeSXin LI EXPECTED(cursor_up); 150406bfebdeSXin LI EXPECTED(cursor_left); 150506bfebdeSXin LI EXPECTED(cursor_right); 150606bfebdeSXin LI } 150706bfebdeSXin LI } 150806bfebdeSXin LI } 150906bfebdeSXin LI 15105d08fb1fSRong-En Fan #define MAX_KP 5 15114a1a9510SRong-En Fan /* 15124a1a9510SRong-En Fan * Do a quick sanity-check for vt100-style keypads to see if the 5-key keypad 15134a1a9510SRong-En Fan * is mapped inconsistently. 15144a1a9510SRong-En Fan */ 15154a1a9510SRong-En Fan static void 1516aae38d10SBaptiste Daroussin check_keypad(TERMTYPE2 *tp) 15174a1a9510SRong-En Fan { 15184a1a9510SRong-En Fan char show[80]; 15194a1a9510SRong-En Fan 15204a1a9510SRong-En Fan if (VALID_STRING(key_a1) && 15214a1a9510SRong-En Fan VALID_STRING(key_a3) && 15224a1a9510SRong-En Fan VALID_STRING(key_b2) && 15234a1a9510SRong-En Fan VALID_STRING(key_c1) && 15244a1a9510SRong-En Fan VALID_STRING(key_c3)) { 15255d08fb1fSRong-En Fan char final[MAX_KP + 1]; 152673f0a83dSXin LI long list[MAX_KP]; 15274a1a9510SRong-En Fan int increase = 0; 15284a1a9510SRong-En Fan int j, k, kk; 152973f0a83dSXin LI long last; 153073f0a83dSXin LI long test; 15314a1a9510SRong-En Fan 15324a1a9510SRong-En Fan final[0] = keypad_final(key_a1); 15334a1a9510SRong-En Fan final[1] = keypad_final(key_a3); 15344a1a9510SRong-En Fan final[2] = keypad_final(key_b2); 15354a1a9510SRong-En Fan final[3] = keypad_final(key_c1); 15364a1a9510SRong-En Fan final[4] = keypad_final(key_c3); 15374a1a9510SRong-En Fan final[5] = '\0'; 15384a1a9510SRong-En Fan 15394a1a9510SRong-En Fan /* special case: legacy coding using 1,2,3,0,. on the bottom */ 15405d08fb1fSRong-En Fan assert(strlen(final) <= MAX_KP); 15414a1a9510SRong-En Fan if (!strcmp(final, "qsrpn")) 15424a1a9510SRong-En Fan return; 15434a1a9510SRong-En Fan 15444a1a9510SRong-En Fan list[0] = keypad_index(key_a1); 15454a1a9510SRong-En Fan list[1] = keypad_index(key_a3); 15464a1a9510SRong-En Fan list[2] = keypad_index(key_b2); 15474a1a9510SRong-En Fan list[3] = keypad_index(key_c1); 15484a1a9510SRong-En Fan list[4] = keypad_index(key_c3); 15494a1a9510SRong-En Fan 15504a1a9510SRong-En Fan /* check that they're all vt100 keys */ 15515d08fb1fSRong-En Fan for (j = 0; j < MAX_KP; ++j) { 15524a1a9510SRong-En Fan if (list[j] < 0) { 15534a1a9510SRong-En Fan return; 15544a1a9510SRong-En Fan } 15554a1a9510SRong-En Fan } 15564a1a9510SRong-En Fan 15574a1a9510SRong-En Fan /* check if they're all in increasing order */ 15585d08fb1fSRong-En Fan for (j = 1; j < MAX_KP; ++j) { 15594a1a9510SRong-En Fan if (list[j] > list[j - 1]) { 15604a1a9510SRong-En Fan ++increase; 15614a1a9510SRong-En Fan } 15624a1a9510SRong-En Fan } 15635d08fb1fSRong-En Fan if (increase != (MAX_KP - 1)) { 15644a1a9510SRong-En Fan show[0] = '\0'; 15654a1a9510SRong-En Fan 15665d08fb1fSRong-En Fan for (j = 0, last = -1; j < MAX_KP; ++j) { 15674a1a9510SRong-En Fan for (k = 0, kk = -1, test = 100; k < 5; ++k) { 15684a1a9510SRong-En Fan if (list[k] > last && 15694a1a9510SRong-En Fan list[k] < test) { 15704a1a9510SRong-En Fan test = list[k]; 15714a1a9510SRong-En Fan kk = k; 15724a1a9510SRong-En Fan } 15734a1a9510SRong-En Fan } 15744a1a9510SRong-En Fan last = test; 15755d08fb1fSRong-En Fan assert(strlen(show) < (MAX_KP * 4)); 15764a1a9510SRong-En Fan switch (kk) { 15774a1a9510SRong-En Fan case 0: 157873f0a83dSXin LI _nc_STRCAT(show, " ka1", sizeof(show)); 15794a1a9510SRong-En Fan break; 15804a1a9510SRong-En Fan case 1: 158173f0a83dSXin LI _nc_STRCAT(show, " ka3", sizeof(show)); 15824a1a9510SRong-En Fan break; 15834a1a9510SRong-En Fan case 2: 158473f0a83dSXin LI _nc_STRCAT(show, " kb2", sizeof(show)); 15854a1a9510SRong-En Fan break; 15864a1a9510SRong-En Fan case 3: 158773f0a83dSXin LI _nc_STRCAT(show, " kc1", sizeof(show)); 15884a1a9510SRong-En Fan break; 15894a1a9510SRong-En Fan case 4: 159073f0a83dSXin LI _nc_STRCAT(show, " kc3", sizeof(show)); 15914a1a9510SRong-En Fan break; 15924a1a9510SRong-En Fan } 15934a1a9510SRong-En Fan } 15944a1a9510SRong-En Fan 15954a1a9510SRong-En Fan _nc_warning("vt100 keypad order inconsistent: %s", show); 15964a1a9510SRong-En Fan } 15974a1a9510SRong-En Fan 15984a1a9510SRong-En Fan } else if (VALID_STRING(key_a1) || 15994a1a9510SRong-En Fan VALID_STRING(key_a3) || 16004a1a9510SRong-En Fan VALID_STRING(key_b2) || 16014a1a9510SRong-En Fan VALID_STRING(key_c1) || 16024a1a9510SRong-En Fan VALID_STRING(key_c3)) { 16034a1a9510SRong-En Fan show[0] = '\0'; 16044a1a9510SRong-En Fan if (keypad_index(key_a1) >= 0) 160573f0a83dSXin LI _nc_STRCAT(show, " ka1", sizeof(show)); 16064a1a9510SRong-En Fan if (keypad_index(key_a3) >= 0) 160773f0a83dSXin LI _nc_STRCAT(show, " ka3", sizeof(show)); 16084a1a9510SRong-En Fan if (keypad_index(key_b2) >= 0) 160973f0a83dSXin LI _nc_STRCAT(show, " kb2", sizeof(show)); 16104a1a9510SRong-En Fan if (keypad_index(key_c1) >= 0) 161173f0a83dSXin LI _nc_STRCAT(show, " kc1", sizeof(show)); 16124a1a9510SRong-En Fan if (keypad_index(key_c3) >= 0) 161373f0a83dSXin LI _nc_STRCAT(show, " kc3", sizeof(show)); 16144a1a9510SRong-En Fan if (*show != '\0') 16154a1a9510SRong-En Fan _nc_warning("vt100 keypad map incomplete:%s", show); 16164a1a9510SRong-En Fan } 161773f0a83dSXin LI 161873f0a83dSXin LI /* 161973f0a83dSXin LI * These warnings are useful for consistency checks - it is possible that 162073f0a83dSXin LI * there are real terminals with mismatches in these 162173f0a83dSXin LI */ 162273f0a83dSXin LI ANDMISSING(key_ic, key_dc); 16234a1a9510SRong-En Fan } 16244a1a9510SRong-En Fan 162506bfebdeSXin LI static void 1626aae38d10SBaptiste Daroussin check_printer(TERMTYPE2 *tp) 162706bfebdeSXin LI { 1628aae38d10SBaptiste Daroussin (void) tp; 1629aae38d10SBaptiste Daroussin #if defined(enter_doublewide_mode) && defined(exit_doublewide_mode) 163006bfebdeSXin LI PAIRED(enter_doublewide_mode, exit_doublewide_mode); 1631aae38d10SBaptiste Daroussin #endif 1632aae38d10SBaptiste Daroussin #if defined(enter_italics_mode) && defined(exit_italics_mode) 163306bfebdeSXin LI PAIRED(enter_italics_mode, exit_italics_mode); 1634aae38d10SBaptiste Daroussin #endif 1635aae38d10SBaptiste Daroussin #if defined(enter_leftward_mode) && defined(exit_leftward_mode) 163606bfebdeSXin LI PAIRED(enter_leftward_mode, exit_leftward_mode); 1637aae38d10SBaptiste Daroussin #endif 1638aae38d10SBaptiste Daroussin #if defined(enter_micro_mode) && defined(exit_micro_mode) 163906bfebdeSXin LI PAIRED(enter_micro_mode, exit_micro_mode); 1640aae38d10SBaptiste Daroussin #endif 1641aae38d10SBaptiste Daroussin #if defined(enter_shadow_mode) && defined(exit_shadow_mode) 164206bfebdeSXin LI PAIRED(enter_shadow_mode, exit_shadow_mode); 1643aae38d10SBaptiste Daroussin #endif 1644aae38d10SBaptiste Daroussin #if defined(enter_subscript_mode) && defined(exit_subscript_mode) 164506bfebdeSXin LI PAIRED(enter_subscript_mode, exit_subscript_mode); 1646aae38d10SBaptiste Daroussin #endif 1647aae38d10SBaptiste Daroussin #if defined(enter_superscript_mode) && defined(exit_superscript_mode) 164806bfebdeSXin LI PAIRED(enter_superscript_mode, exit_superscript_mode); 1649aae38d10SBaptiste Daroussin #endif 1650aae38d10SBaptiste Daroussin #if defined(enter_upward_mode) && defined(exit_upward_mode) 165106bfebdeSXin LI PAIRED(enter_upward_mode, exit_upward_mode); 1652aae38d10SBaptiste Daroussin #endif 165306bfebdeSXin LI 1654aae38d10SBaptiste Daroussin #if defined(start_char_set_def) && defined(stop_char_set_def) 165506bfebdeSXin LI ANDMISSING(start_char_set_def, stop_char_set_def); 1656aae38d10SBaptiste Daroussin #endif 165706bfebdeSXin LI 165806bfebdeSXin LI /* if we have a parameterized form, then the non-parameterized is easy */ 1659aae38d10SBaptiste Daroussin #if defined(set_bottom_margin_parm) && defined(set_bottom_margin) 166006bfebdeSXin LI ANDMISSING(set_bottom_margin_parm, set_bottom_margin); 1661aae38d10SBaptiste Daroussin #endif 1662aae38d10SBaptiste Daroussin #if defined(set_left_margin_parm) && defined(set_left_margin) 166306bfebdeSXin LI ANDMISSING(set_left_margin_parm, set_left_margin); 1664aae38d10SBaptiste Daroussin #endif 1665aae38d10SBaptiste Daroussin #if defined(set_right_margin_parm) && defined(set_right_margin) 166606bfebdeSXin LI ANDMISSING(set_right_margin_parm, set_right_margin); 1667aae38d10SBaptiste Daroussin #endif 1668aae38d10SBaptiste Daroussin #if defined(set_top_margin_parm) && defined(set_top_margin) 166906bfebdeSXin LI ANDMISSING(set_top_margin_parm, set_top_margin); 1670aae38d10SBaptiste Daroussin #endif 167106bfebdeSXin LI 1672aae38d10SBaptiste Daroussin #if defined(parm_down_micro) && defined(micro_down) 167306bfebdeSXin LI ANDMISSING(parm_down_micro, micro_down); 1674aae38d10SBaptiste Daroussin #endif 1675aae38d10SBaptiste Daroussin #if defined(parm_left_micro) && defined(micro_left) 167606bfebdeSXin LI ANDMISSING(parm_left_micro, micro_left); 1677aae38d10SBaptiste Daroussin #endif 1678aae38d10SBaptiste Daroussin #if defined(parm_right_micro) && defined(micro_right) 167906bfebdeSXin LI ANDMISSING(parm_right_micro, micro_right); 1680aae38d10SBaptiste Daroussin #endif 1681aae38d10SBaptiste Daroussin #if defined(parm_up_micro) && defined(micro_up) 168206bfebdeSXin LI ANDMISSING(parm_up_micro, micro_up); 1683aae38d10SBaptiste Daroussin #endif 168406bfebdeSXin LI } 168506bfebdeSXin LI 1686aae38d10SBaptiste Daroussin #if NCURSES_XNAMES 168773f0a83dSXin LI static bool 168873f0a83dSXin LI uses_SGR_39_49(const char *value) 168973f0a83dSXin LI { 169073f0a83dSXin LI return (strstr(value, "39;49") != 0 169173f0a83dSXin LI || strstr(value, "49;39") != 0); 169273f0a83dSXin LI } 169373f0a83dSXin LI 169473f0a83dSXin LI /* 169573f0a83dSXin LI * Check consistency of termcap extensions related to "screen". 169673f0a83dSXin LI */ 169773f0a83dSXin LI static void 1698aae38d10SBaptiste Daroussin check_screen(TERMTYPE2 *tp) 169973f0a83dSXin LI { 170073f0a83dSXin LI if (_nc_user_definable) { 170173f0a83dSXin LI int have_XT = tigetflag("XT"); 170273f0a83dSXin LI int have_XM = tigetflag("XM"); 170373f0a83dSXin LI int have_bce = back_color_erase; 170473f0a83dSXin LI bool have_kmouse = FALSE; 170573f0a83dSXin LI bool use_sgr_39_49 = FALSE; 170673f0a83dSXin LI char *name = _nc_first_name(tp->term_names); 1707aae38d10SBaptiste Daroussin bool is_screen = !strncmp(name, "screen", 6); 1708aae38d10SBaptiste Daroussin bool screen_base = (is_screen 1709aae38d10SBaptiste Daroussin && strchr(name, '.') == 0); 171073f0a83dSXin LI 171173f0a83dSXin LI if (!VALID_BOOLEAN(have_bce)) { 171273f0a83dSXin LI have_bce = FALSE; 171373f0a83dSXin LI } 171473f0a83dSXin LI if (!VALID_BOOLEAN(have_XM)) { 171573f0a83dSXin LI have_XM = FALSE; 171673f0a83dSXin LI } 171773f0a83dSXin LI if (!VALID_BOOLEAN(have_XT)) { 171873f0a83dSXin LI have_XT = FALSE; 171973f0a83dSXin LI } 172073f0a83dSXin LI if (VALID_STRING(key_mouse)) { 172173f0a83dSXin LI have_kmouse = !strcmp("\033[M", key_mouse); 172273f0a83dSXin LI } 172373f0a83dSXin LI if (VALID_STRING(orig_colors)) { 172473f0a83dSXin LI use_sgr_39_49 = uses_SGR_39_49(orig_colors); 172573f0a83dSXin LI } else if (VALID_STRING(orig_pair)) { 172673f0a83dSXin LI use_sgr_39_49 = uses_SGR_39_49(orig_pair); 172773f0a83dSXin LI } 172873f0a83dSXin LI 172973f0a83dSXin LI if (have_XM && have_XT) { 1730aae38d10SBaptiste Daroussin _nc_warning("screen's XT capability conflicts with XM"); 1731aae38d10SBaptiste Daroussin } else if (have_XT && screen_base) { 1732aae38d10SBaptiste Daroussin _nc_warning("screen's \"screen\" entries should not have XT set"); 173373f0a83dSXin LI } else if (have_XT) { 1734aae38d10SBaptiste Daroussin if (!have_kmouse && is_screen) { 173573f0a83dSXin LI if (VALID_STRING(key_mouse)) { 1736aae38d10SBaptiste Daroussin _nc_warning("value of kmous inconsistent with screen's usage"); 173773f0a83dSXin LI } else { 1738aae38d10SBaptiste Daroussin _nc_warning("expected kmous capability with XT"); 173973f0a83dSXin LI } 174073f0a83dSXin LI } 174173f0a83dSXin LI if (!have_bce && max_colors > 0) 1742aae38d10SBaptiste Daroussin _nc_warning("expected bce capability with XT"); 174373f0a83dSXin LI if (!use_sgr_39_49 && have_bce && max_colors > 0) 1744aae38d10SBaptiste Daroussin _nc_warning("expected orig_colors capability with XT to have 39/49 parameters"); 174573f0a83dSXin LI if (VALID_STRING(to_status_line)) 174673f0a83dSXin LI _nc_warning("\"tsl\" capability is redundant, given XT"); 174773f0a83dSXin LI } else { 1748aae38d10SBaptiste Daroussin if (have_kmouse 1749aae38d10SBaptiste Daroussin && !have_XM 1750aae38d10SBaptiste Daroussin && !screen_base && strchr(name, '+') == 0) { 1751aae38d10SBaptiste Daroussin _nc_warning("expected XT to be set, given kmous"); 175273f0a83dSXin LI } 175373f0a83dSXin LI } 1754aae38d10SBaptiste Daroussin } 1755aae38d10SBaptiste Daroussin } 1756aae38d10SBaptiste Daroussin #else 1757aae38d10SBaptiste Daroussin #define check_screen(tp) /* nothing */ 175873f0a83dSXin LI #endif 175973f0a83dSXin LI 17604a1a9510SRong-En Fan /* 176118259542SPeter Wemm * Returns the expected number of parameters for the given capability. 176218259542SPeter Wemm */ 176318259542SPeter Wemm static int 17647a69bbfbSPeter Wemm expected_params(const char *name) 176518259542SPeter Wemm { 1766aae38d10SBaptiste Daroussin #define DATA(name,count) { { name }, count } 176718259542SPeter Wemm /* *INDENT-OFF* */ 176818259542SPeter Wemm static const struct { 1769aae38d10SBaptiste Daroussin const char name[9]; 177018259542SPeter Wemm int count; 177118259542SPeter Wemm } table[] = { 1772aae38d10SBaptiste Daroussin DATA( "S0", 1 ), /* 'screen' extension */ 1773aae38d10SBaptiste Daroussin DATA( "birep", 2 ), 1774aae38d10SBaptiste Daroussin DATA( "chr", 1 ), 1775aae38d10SBaptiste Daroussin DATA( "colornm", 1 ), 1776aae38d10SBaptiste Daroussin DATA( "cpi", 1 ), 1777aae38d10SBaptiste Daroussin DATA( "csnm", 1 ), 1778aae38d10SBaptiste Daroussin DATA( "csr", 2 ), 1779aae38d10SBaptiste Daroussin DATA( "cub", 1 ), 1780aae38d10SBaptiste Daroussin DATA( "cud", 1 ), 1781aae38d10SBaptiste Daroussin DATA( "cuf", 1 ), 1782aae38d10SBaptiste Daroussin DATA( "cup", 2 ), 1783aae38d10SBaptiste Daroussin DATA( "cuu", 1 ), 1784aae38d10SBaptiste Daroussin DATA( "cvr", 1 ), 1785aae38d10SBaptiste Daroussin DATA( "cwin", 5 ), 1786aae38d10SBaptiste Daroussin DATA( "dch", 1 ), 1787aae38d10SBaptiste Daroussin DATA( "defc", 3 ), 1788aae38d10SBaptiste Daroussin DATA( "dial", 1 ), 1789aae38d10SBaptiste Daroussin DATA( "dispc", 1 ), 1790aae38d10SBaptiste Daroussin DATA( "dl", 1 ), 1791aae38d10SBaptiste Daroussin DATA( "ech", 1 ), 1792aae38d10SBaptiste Daroussin DATA( "getm", 1 ), 1793aae38d10SBaptiste Daroussin DATA( "hpa", 1 ), 1794aae38d10SBaptiste Daroussin DATA( "ich", 1 ), 1795aae38d10SBaptiste Daroussin DATA( "il", 1 ), 1796aae38d10SBaptiste Daroussin DATA( "indn", 1 ), 1797aae38d10SBaptiste Daroussin DATA( "initc", 4 ), 1798aae38d10SBaptiste Daroussin DATA( "initp", 7 ), 1799aae38d10SBaptiste Daroussin DATA( "lpi", 1 ), 1800aae38d10SBaptiste Daroussin DATA( "mc5p", 1 ), 1801aae38d10SBaptiste Daroussin DATA( "mrcup", 2 ), 1802aae38d10SBaptiste Daroussin DATA( "mvpa", 1 ), 1803aae38d10SBaptiste Daroussin DATA( "pfkey", 2 ), 1804aae38d10SBaptiste Daroussin DATA( "pfloc", 2 ), 1805aae38d10SBaptiste Daroussin DATA( "pfx", 2 ), 1806aae38d10SBaptiste Daroussin DATA( "pfxl", 3 ), 1807aae38d10SBaptiste Daroussin DATA( "pln", 2 ), 1808aae38d10SBaptiste Daroussin DATA( "qdial", 1 ), 1809aae38d10SBaptiste Daroussin DATA( "rcsd", 1 ), 1810aae38d10SBaptiste Daroussin DATA( "rep", 2 ), 1811aae38d10SBaptiste Daroussin DATA( "rin", 1 ), 1812aae38d10SBaptiste Daroussin DATA( "sclk", 3 ), 1813aae38d10SBaptiste Daroussin DATA( "scp", 1 ), 1814aae38d10SBaptiste Daroussin DATA( "scs", 1 ), 1815aae38d10SBaptiste Daroussin DATA( "scsd", 2 ), 1816aae38d10SBaptiste Daroussin DATA( "setab", 1 ), 1817aae38d10SBaptiste Daroussin DATA( "setaf", 1 ), 1818aae38d10SBaptiste Daroussin DATA( "setb", 1 ), 1819aae38d10SBaptiste Daroussin DATA( "setcolor", 1 ), 1820aae38d10SBaptiste Daroussin DATA( "setf", 1 ), 1821aae38d10SBaptiste Daroussin DATA( "sgr", 9 ), 1822aae38d10SBaptiste Daroussin DATA( "sgr1", 6 ), 1823aae38d10SBaptiste Daroussin DATA( "slength", 1 ), 1824aae38d10SBaptiste Daroussin DATA( "slines", 1 ), 1825aae38d10SBaptiste Daroussin DATA( "smgbp", 1 ), /* 2 if smgtp is not given */ 1826aae38d10SBaptiste Daroussin DATA( "smglp", 1 ), 1827aae38d10SBaptiste Daroussin DATA( "smglr", 2 ), 1828aae38d10SBaptiste Daroussin DATA( "smgrp", 1 ), 1829aae38d10SBaptiste Daroussin DATA( "smgtb", 2 ), 1830aae38d10SBaptiste Daroussin DATA( "smgtp", 1 ), 1831aae38d10SBaptiste Daroussin DATA( "tsl", 1 ), 1832aae38d10SBaptiste Daroussin DATA( "u6", -1 ), 1833aae38d10SBaptiste Daroussin DATA( "vpa", 1 ), 1834aae38d10SBaptiste Daroussin DATA( "wind", 4 ), 1835aae38d10SBaptiste Daroussin DATA( "wingo", 1 ), 183618259542SPeter Wemm }; 183718259542SPeter Wemm /* *INDENT-ON* */ 183818259542SPeter Wemm 1839aae38d10SBaptiste Daroussin #undef DATA 1840aae38d10SBaptiste Daroussin 184118259542SPeter Wemm unsigned n; 184218259542SPeter Wemm int result = 0; /* function-keys, etc., use none */ 184318259542SPeter Wemm 184418259542SPeter Wemm for (n = 0; n < SIZEOF(table); n++) { 184518259542SPeter Wemm if (!strcmp(name, table[n].name)) { 184618259542SPeter Wemm result = table[n].count; 184718259542SPeter Wemm break; 184818259542SPeter Wemm } 184918259542SPeter Wemm } 185018259542SPeter Wemm 185118259542SPeter Wemm return result; 185218259542SPeter Wemm } 185318259542SPeter Wemm 185418259542SPeter Wemm /* 1855aae38d10SBaptiste Daroussin * Check for user-capabilities that happen to be used in ncurses' terminal 1856aae38d10SBaptiste Daroussin * database. 1857aae38d10SBaptiste Daroussin */ 1858aae38d10SBaptiste Daroussin #if NCURSES_XNAMES 1859aae38d10SBaptiste Daroussin static struct user_table_entry const * 1860aae38d10SBaptiste Daroussin lookup_user_capability(const char *name) 1861aae38d10SBaptiste Daroussin { 1862aae38d10SBaptiste Daroussin struct user_table_entry const *result = 0; 1863aae38d10SBaptiste Daroussin if (*name != 'k') { 1864aae38d10SBaptiste Daroussin result = _nc_find_user_entry(name); 1865aae38d10SBaptiste Daroussin } 1866aae38d10SBaptiste Daroussin return result; 1867aae38d10SBaptiste Daroussin } 1868aae38d10SBaptiste Daroussin #endif 1869aae38d10SBaptiste Daroussin 1870aae38d10SBaptiste Daroussin /* 1871aae38d10SBaptiste Daroussin * If a given name is likely to be a user-capability, return the number of 1872aae38d10SBaptiste Daroussin * parameters it would be used with. If not, return -1. 1873aae38d10SBaptiste Daroussin * 1874aae38d10SBaptiste Daroussin * ncurses assumes that u6 could be used for getting the cursor-position, but 1875aae38d10SBaptiste Daroussin * that is not implemented. Make a special case for that, to quiet needless 1876aae38d10SBaptiste Daroussin * warnings. 1877aae38d10SBaptiste Daroussin * 1878aae38d10SBaptiste Daroussin * The other string-capability extensions (see terminfo.src) which could have 1879aae38d10SBaptiste Daroussin * parameters such as "Ss", "%u", are not used by ncurses. But we check those 1880aae38d10SBaptiste Daroussin * anyway, to validate the terminfo database. 1881aae38d10SBaptiste Daroussin */ 1882aae38d10SBaptiste Daroussin static int 1883aae38d10SBaptiste Daroussin is_user_capability(const char *name) 1884aae38d10SBaptiste Daroussin { 1885aae38d10SBaptiste Daroussin int result = -1; 1886aae38d10SBaptiste Daroussin if (name[0] == 'u' && 1887aae38d10SBaptiste Daroussin (name[1] >= '0' && name[1] <= '9') && 1888aae38d10SBaptiste Daroussin name[2] == '\0') { 1889aae38d10SBaptiste Daroussin result = (name[1] == '6') ? 2 : 0; 1890aae38d10SBaptiste Daroussin } 1891aae38d10SBaptiste Daroussin #if NCURSES_XNAMES 1892aae38d10SBaptiste Daroussin else if (using_extensions) { 1893aae38d10SBaptiste Daroussin struct user_table_entry const *p = lookup_user_capability(name); 1894aae38d10SBaptiste Daroussin if (p != 0) { 1895aae38d10SBaptiste Daroussin result = (int) p->ute_argc; 1896aae38d10SBaptiste Daroussin } 1897aae38d10SBaptiste Daroussin } 1898aae38d10SBaptiste Daroussin #endif 1899aae38d10SBaptiste Daroussin return result; 1900aae38d10SBaptiste Daroussin } 1901aae38d10SBaptiste Daroussin 1902aae38d10SBaptiste Daroussin /* 190318259542SPeter Wemm * Make a quick sanity check for the parameters which are used in the given 190418259542SPeter Wemm * strings. If there are no "%p" tokens, then there should be no other "%" 190518259542SPeter Wemm * markers. 190618259542SPeter Wemm */ 190718259542SPeter Wemm static void 1908aae38d10SBaptiste Daroussin check_params(TERMTYPE2 *tp, const char *name, char *value, int extended) 190918259542SPeter Wemm { 191018259542SPeter Wemm int expected = expected_params(name); 191118259542SPeter Wemm int actual = 0; 191218259542SPeter Wemm int n; 1913aae38d10SBaptiste Daroussin bool params[NUM_PARM]; 191418259542SPeter Wemm char *s = value; 191518259542SPeter Wemm 19164a1a9510SRong-En Fan #ifdef set_top_margin_parm 1917b82face1SPeter Wemm if (!strcmp(name, "smgbp") 1918b82face1SPeter Wemm && set_top_margin_parm == 0) 1919b82face1SPeter Wemm expected = 2; 19204a1a9510SRong-En Fan #endif 1921b82face1SPeter Wemm 1922aae38d10SBaptiste Daroussin for (n = 0; n < NUM_PARM; n++) 192318259542SPeter Wemm params[n] = FALSE; 192418259542SPeter Wemm 192518259542SPeter Wemm while (*s != 0) { 192618259542SPeter Wemm if (*s == '%') { 192718259542SPeter Wemm if (*++s == '\0') { 192818259542SPeter Wemm _nc_warning("expected character after %% in %s", name); 192918259542SPeter Wemm break; 193018259542SPeter Wemm } else if (*s == 'p') { 193118259542SPeter Wemm if (*++s == '\0' || !isdigit((int) *s)) { 193218259542SPeter Wemm _nc_warning("expected digit after %%p in %s", name); 193318259542SPeter Wemm return; 193418259542SPeter Wemm } else { 193518259542SPeter Wemm n = (*s - '0'); 193618259542SPeter Wemm if (n > actual) 193718259542SPeter Wemm actual = n; 193818259542SPeter Wemm params[n] = TRUE; 193918259542SPeter Wemm } 194018259542SPeter Wemm } 194118259542SPeter Wemm } 194218259542SPeter Wemm s++; 194318259542SPeter Wemm } 194418259542SPeter Wemm 1945aae38d10SBaptiste Daroussin #if NCURSES_XNAMES 1946aae38d10SBaptiste Daroussin if (extended) { 1947aae38d10SBaptiste Daroussin int check = is_user_capability(name); 1948aae38d10SBaptiste Daroussin if (check != actual && (check >= 0 && actual >= 0)) { 1949aae38d10SBaptiste Daroussin _nc_warning("extended %s capability has %d parameters, expected %d", 1950aae38d10SBaptiste Daroussin name, actual, check); 1951aae38d10SBaptiste Daroussin } else if (debug_level > 1) { 1952aae38d10SBaptiste Daroussin _nc_warning("extended %s capability has %d parameters, as expected", 1953aae38d10SBaptiste Daroussin name, actual); 1954aae38d10SBaptiste Daroussin } 1955aae38d10SBaptiste Daroussin expected = actual; 1956aae38d10SBaptiste Daroussin } 1957aae38d10SBaptiste Daroussin #else 1958aae38d10SBaptiste Daroussin (void) extended; 1959aae38d10SBaptiste Daroussin #endif 1960aae38d10SBaptiste Daroussin 196118259542SPeter Wemm if (params[0]) { 196218259542SPeter Wemm _nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name); 196318259542SPeter Wemm } 196418259542SPeter Wemm if (value == set_attributes || expected < 0) { 196518259542SPeter Wemm ; 196618259542SPeter Wemm } else if (expected != actual) { 196718259542SPeter Wemm _nc_warning("%s uses %d parameters, expected %d", name, 196818259542SPeter Wemm actual, expected); 196918259542SPeter Wemm for (n = 1; n < actual; n++) { 197018259542SPeter Wemm if (!params[n]) 197118259542SPeter Wemm _nc_warning("%s omits parameter %d", name, n); 197218259542SPeter Wemm } 197318259542SPeter Wemm } 1974aae38d10SBaptiste Daroussin 1975aae38d10SBaptiste Daroussin /* 1976aae38d10SBaptiste Daroussin * Counting "%p" markers does not account for termcap expressions which 1977aae38d10SBaptiste Daroussin * may not have been fully translated. Also, tparm does its own analysis. 1978aae38d10SBaptiste Daroussin * Report differences here. 1979aae38d10SBaptiste Daroussin */ 1980aae38d10SBaptiste Daroussin if (actual >= 0) { 1981aae38d10SBaptiste Daroussin char *p_is_s[NUM_PARM]; 1982aae38d10SBaptiste Daroussin int popcount; 1983aae38d10SBaptiste Daroussin int analyzed = _nc_tparm_analyze(value, p_is_s, &popcount); 1984aae38d10SBaptiste Daroussin if (analyzed < popcount) { 1985aae38d10SBaptiste Daroussin analyzed = popcount; 1986aae38d10SBaptiste Daroussin } 1987aae38d10SBaptiste Daroussin if (actual != analyzed && expected != analyzed) { 1988aae38d10SBaptiste Daroussin #if NCURSES_XNAMES 1989aae38d10SBaptiste Daroussin int user_cap = is_user_capability(name); 1990aae38d10SBaptiste Daroussin if ((user_cap == analyzed) && using_extensions) { 1991aae38d10SBaptiste Daroussin ; /* ignore */ 1992aae38d10SBaptiste Daroussin } else if (user_cap >= 0) { 1993aae38d10SBaptiste Daroussin _nc_warning("tparm will use %d parameters for %s, expected %d", 1994aae38d10SBaptiste Daroussin analyzed, name, user_cap); 1995aae38d10SBaptiste Daroussin } else 1996aae38d10SBaptiste Daroussin #endif 1997aae38d10SBaptiste Daroussin { 1998aae38d10SBaptiste Daroussin _nc_warning("tparm analyzed %d parameters for %s, expected %d", 1999aae38d10SBaptiste Daroussin analyzed, name, actual); 2000aae38d10SBaptiste Daroussin } 2001aae38d10SBaptiste Daroussin } 2002aae38d10SBaptiste Daroussin } 2003aae38d10SBaptiste Daroussin } 2004aae38d10SBaptiste Daroussin 2005aae38d10SBaptiste Daroussin static bool 2006aae38d10SBaptiste Daroussin line_capability(const char *name) 2007aae38d10SBaptiste Daroussin { 2008aae38d10SBaptiste Daroussin bool result = FALSE; 2009aae38d10SBaptiste Daroussin static const char *table[] = 2010aae38d10SBaptiste Daroussin { 2011aae38d10SBaptiste Daroussin "csr", /* change_scroll_region */ 2012aae38d10SBaptiste Daroussin "clear", /* clear_screen */ 2013aae38d10SBaptiste Daroussin "ed", /* clr_eos */ 2014aae38d10SBaptiste Daroussin "cwin", /* create_window */ 2015aae38d10SBaptiste Daroussin "cup", /* cursor_address */ 2016aae38d10SBaptiste Daroussin "cud1", /* cursor_down */ 2017aae38d10SBaptiste Daroussin "home", /* cursor_home */ 2018aae38d10SBaptiste Daroussin "mrcup", /* cursor_mem_address */ 2019aae38d10SBaptiste Daroussin "ll", /* cursor_to_ll */ 2020aae38d10SBaptiste Daroussin "cuu1", /* cursor_up */ 2021aae38d10SBaptiste Daroussin "dl1", /* delete_line */ 2022aae38d10SBaptiste Daroussin "hd", /* down_half_line */ 2023aae38d10SBaptiste Daroussin "flash", /* flash_screen */ 2024aae38d10SBaptiste Daroussin "ff", /* form_feed */ 2025aae38d10SBaptiste Daroussin "il1", /* insert_line */ 2026aae38d10SBaptiste Daroussin "nel", /* newline */ 2027aae38d10SBaptiste Daroussin "dl", /* parm_delete_line */ 2028aae38d10SBaptiste Daroussin "cud", /* parm_down_cursor */ 2029aae38d10SBaptiste Daroussin "indn", /* parm_index */ 2030aae38d10SBaptiste Daroussin "il", /* parm_insert_line */ 2031aae38d10SBaptiste Daroussin "rin", /* parm_rindex */ 2032aae38d10SBaptiste Daroussin "cuu", /* parm_up_cursor */ 2033aae38d10SBaptiste Daroussin "mc0", /* print_screen */ 2034aae38d10SBaptiste Daroussin "vpa", /* row_address */ 2035aae38d10SBaptiste Daroussin "ind", /* scroll_forward */ 2036aae38d10SBaptiste Daroussin "ri", /* scroll_reverse */ 2037aae38d10SBaptiste Daroussin "hu", /* up_half_line */ 2038aae38d10SBaptiste Daroussin }; 2039aae38d10SBaptiste Daroussin size_t n; 2040aae38d10SBaptiste Daroussin for (n = 0; n < SIZEOF(table); ++n) { 2041aae38d10SBaptiste Daroussin if (!strcmp(name, table[n])) { 2042aae38d10SBaptiste Daroussin result = TRUE; 2043aae38d10SBaptiste Daroussin break; 2044aae38d10SBaptiste Daroussin } 2045aae38d10SBaptiste Daroussin } 2046aae38d10SBaptiste Daroussin return result; 2047aae38d10SBaptiste Daroussin } 2048aae38d10SBaptiste Daroussin 2049aae38d10SBaptiste Daroussin /* 2050aae38d10SBaptiste Daroussin * Check for DEC VT100 private mode for reverse video. 2051aae38d10SBaptiste Daroussin */ 2052aae38d10SBaptiste Daroussin static const char * 2053aae38d10SBaptiste Daroussin skip_DECSCNM(const char *value, int *flag) 2054aae38d10SBaptiste Daroussin { 2055aae38d10SBaptiste Daroussin *flag = -1; 2056aae38d10SBaptiste Daroussin if (value != 0) { 2057aae38d10SBaptiste Daroussin int skip = csi_length(value); 2058aae38d10SBaptiste Daroussin if (skip > 0 && 2059aae38d10SBaptiste Daroussin value[skip++] == '?' && 2060aae38d10SBaptiste Daroussin value[skip++] == '5') { 2061aae38d10SBaptiste Daroussin if (value[skip] == 'h') { 2062aae38d10SBaptiste Daroussin *flag = 1; 2063aae38d10SBaptiste Daroussin } else if (value[skip] == 'l') { 2064aae38d10SBaptiste Daroussin *flag = 0; 2065aae38d10SBaptiste Daroussin } 2066aae38d10SBaptiste Daroussin value += skip + 1; 2067aae38d10SBaptiste Daroussin } 2068aae38d10SBaptiste Daroussin } 2069aae38d10SBaptiste Daroussin return value; 2070aae38d10SBaptiste Daroussin } 2071aae38d10SBaptiste Daroussin 2072aae38d10SBaptiste Daroussin static void 2073aae38d10SBaptiste Daroussin check_delays(TERMTYPE2 *tp, const char *name, const char *value) 2074aae38d10SBaptiste Daroussin { 2075aae38d10SBaptiste Daroussin const char *p, *q; 2076aae38d10SBaptiste Daroussin const char *first = 0; 2077aae38d10SBaptiste Daroussin const char *last = 0; 2078aae38d10SBaptiste Daroussin 2079aae38d10SBaptiste Daroussin for (p = value; *p != '\0'; ++p) { 2080aae38d10SBaptiste Daroussin if (p[0] == '$' && p[1] == '<') { 2081aae38d10SBaptiste Daroussin const char *base = p + 2; 2082aae38d10SBaptiste Daroussin const char *mark = 0; 2083aae38d10SBaptiste Daroussin bool maybe = TRUE; 2084aae38d10SBaptiste Daroussin bool mixed = FALSE; 2085aae38d10SBaptiste Daroussin int proportional = 0; 2086aae38d10SBaptiste Daroussin int mandatory = 0; 2087aae38d10SBaptiste Daroussin 2088aae38d10SBaptiste Daroussin first = p; 2089aae38d10SBaptiste Daroussin 2090aae38d10SBaptiste Daroussin for (q = base; *q != '\0'; ++q) { 2091aae38d10SBaptiste Daroussin if (*q == '>') { 2092aae38d10SBaptiste Daroussin if (mark == 0) 2093aae38d10SBaptiste Daroussin mark = q; 2094aae38d10SBaptiste Daroussin break; 2095aae38d10SBaptiste Daroussin } else if (*q == '*' || *q == '/') { 2096aae38d10SBaptiste Daroussin if (*q == '*') 2097aae38d10SBaptiste Daroussin ++proportional; 2098aae38d10SBaptiste Daroussin if (*q == '/') 2099aae38d10SBaptiste Daroussin ++mandatory; 2100aae38d10SBaptiste Daroussin if (mark == 0) 2101aae38d10SBaptiste Daroussin mark = q; 2102aae38d10SBaptiste Daroussin } else if (!(isalnum(UChar(*q)) || strchr("+-.", *q) != 0)) { 2103aae38d10SBaptiste Daroussin maybe = FALSE; 2104aae38d10SBaptiste Daroussin break; 2105aae38d10SBaptiste Daroussin } else if (proportional || mandatory) { 2106aae38d10SBaptiste Daroussin mixed = TRUE; 2107aae38d10SBaptiste Daroussin } 2108aae38d10SBaptiste Daroussin } 2109aae38d10SBaptiste Daroussin last = *q ? (q + 1) : q; 2110aae38d10SBaptiste Daroussin if (*q == '\0') { 2111aae38d10SBaptiste Daroussin maybe = FALSE; /* just an isolated "$<" */ 2112aae38d10SBaptiste Daroussin } else if (maybe) { 2113aae38d10SBaptiste Daroussin float check_f; 2114aae38d10SBaptiste Daroussin char check_c; 2115aae38d10SBaptiste Daroussin int rc = sscanf(base, "%f%c", &check_f, &check_c); 2116aae38d10SBaptiste Daroussin if ((rc != 2) || (check_c != *mark) || mixed) { 2117aae38d10SBaptiste Daroussin _nc_warning("syntax error in %s delay '%.*s'", name, 2118aae38d10SBaptiste Daroussin (int) (q - base), base); 2119aae38d10SBaptiste Daroussin } else if (*name == 'k') { 2120aae38d10SBaptiste Daroussin _nc_warning("function-key %s has delay", name); 2121aae38d10SBaptiste Daroussin } else if (proportional && !line_capability(name)) { 2122aae38d10SBaptiste Daroussin _nc_warning("non-line capability using proportional delay: %s", name); 2123aae38d10SBaptiste Daroussin } else if (!xon_xoff && 2124aae38d10SBaptiste Daroussin !mandatory && 2125aae38d10SBaptiste Daroussin strchr(_nc_first_name(tp->term_names), '+') == 0) { 2126aae38d10SBaptiste Daroussin _nc_warning("%s in %s is used since no xon/xoff", 2127aae38d10SBaptiste Daroussin (proportional 2128aae38d10SBaptiste Daroussin ? "proportional delay" 2129aae38d10SBaptiste Daroussin : "delay"), 2130aae38d10SBaptiste Daroussin name); 2131aae38d10SBaptiste Daroussin } 2132aae38d10SBaptiste Daroussin } else { 2133aae38d10SBaptiste Daroussin p = q - 1; /* restart scan */ 2134aae38d10SBaptiste Daroussin } 2135aae38d10SBaptiste Daroussin } 2136aae38d10SBaptiste Daroussin } 2137aae38d10SBaptiste Daroussin 2138aae38d10SBaptiste Daroussin if (!strcmp(name, "flash") || 2139aae38d10SBaptiste Daroussin !strcmp(name, "beep")) { 2140aae38d10SBaptiste Daroussin 2141aae38d10SBaptiste Daroussin if (first != 0) { 2142aae38d10SBaptiste Daroussin if (first == value || *last == 0) { 2143aae38d10SBaptiste Daroussin /* 2144aae38d10SBaptiste Daroussin * Delay is on one end or the other. 2145aae38d10SBaptiste Daroussin */ 2146aae38d10SBaptiste Daroussin _nc_warning("expected delay embedded within %s", name); 2147aae38d10SBaptiste Daroussin } 2148aae38d10SBaptiste Daroussin } else { 2149aae38d10SBaptiste Daroussin int flag; 2150aae38d10SBaptiste Daroussin 2151aae38d10SBaptiste Daroussin /* 2152aae38d10SBaptiste Daroussin * Check for missing delay when using VT100 reverse-video. 2153aae38d10SBaptiste Daroussin * A real VT100 might not need this, but terminal emulators do. 2154aae38d10SBaptiste Daroussin */ 2155aae38d10SBaptiste Daroussin if ((p = skip_DECSCNM(value, &flag)) != 0 && 2156aae38d10SBaptiste Daroussin flag > 0 && 2157aae38d10SBaptiste Daroussin (q = skip_DECSCNM(p, &flag)) != 0 && 2158aae38d10SBaptiste Daroussin flag == 0) { 2159aae38d10SBaptiste Daroussin _nc_warning("expected a delay in %s", name); 2160aae38d10SBaptiste Daroussin } 2161aae38d10SBaptiste Daroussin } 2162aae38d10SBaptiste Daroussin } 2163aae38d10SBaptiste Daroussin } 2164aae38d10SBaptiste Daroussin 2165aae38d10SBaptiste Daroussin static char * 2166aae38d10SBaptiste Daroussin check_1_infotocap(const char *name, NCURSES_CONST char *value, int count) 2167aae38d10SBaptiste Daroussin { 2168aae38d10SBaptiste Daroussin int k; 2169aae38d10SBaptiste Daroussin int ignored; 2170aae38d10SBaptiste Daroussin long numbers[1 + NUM_PARM]; 2171aae38d10SBaptiste Daroussin char *strings[1 + NUM_PARM]; 2172aae38d10SBaptiste Daroussin char *p_is_s[NUM_PARM]; 2173aae38d10SBaptiste Daroussin char *result; 2174aae38d10SBaptiste Daroussin char blob[NUM_PARM * 10]; 2175aae38d10SBaptiste Daroussin char *next = blob; 2176aae38d10SBaptiste Daroussin 2177aae38d10SBaptiste Daroussin *next++ = '\0'; 2178aae38d10SBaptiste Daroussin for (k = 1; k <= NUM_PARM; k++) { 2179aae38d10SBaptiste Daroussin numbers[k] = count; 2180aae38d10SBaptiste Daroussin _nc_SPRINTF(next, 2181aae38d10SBaptiste Daroussin _nc_SLIMIT(sizeof(blob) - (size_t) (next - blob)) 2182aae38d10SBaptiste Daroussin "XYZ%d", count); 2183aae38d10SBaptiste Daroussin strings[k] = next; 2184aae38d10SBaptiste Daroussin next += strlen(next) + 1; 2185aae38d10SBaptiste Daroussin } 2186aae38d10SBaptiste Daroussin 2187aae38d10SBaptiste Daroussin switch (tparm_type(name)) { 2188aae38d10SBaptiste Daroussin case Num_Str: 2189aae38d10SBaptiste Daroussin result = TPARM_2(value, numbers[1], strings[2]); 2190aae38d10SBaptiste Daroussin break; 2191aae38d10SBaptiste Daroussin case Num_Str_Str: 2192aae38d10SBaptiste Daroussin result = TPARM_3(value, numbers[1], strings[2], strings[3]); 2193aae38d10SBaptiste Daroussin break; 2194aae38d10SBaptiste Daroussin case Numbers: 2195aae38d10SBaptiste Daroussin default: 2196aae38d10SBaptiste Daroussin (void) _nc_tparm_analyze(value, p_is_s, &ignored); 2197aae38d10SBaptiste Daroussin #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n]) 2198aae38d10SBaptiste Daroussin result = TPARM_9(value, 2199aae38d10SBaptiste Daroussin myParam(1), 2200aae38d10SBaptiste Daroussin myParam(2), 2201aae38d10SBaptiste Daroussin myParam(3), 2202aae38d10SBaptiste Daroussin myParam(4), 2203aae38d10SBaptiste Daroussin myParam(5), 2204aae38d10SBaptiste Daroussin myParam(6), 2205aae38d10SBaptiste Daroussin myParam(7), 2206aae38d10SBaptiste Daroussin myParam(8), 2207aae38d10SBaptiste Daroussin myParam(9)); 2208aae38d10SBaptiste Daroussin break; 2209aae38d10SBaptiste Daroussin } 2210aae38d10SBaptiste Daroussin return strdup(result); 2211aae38d10SBaptiste Daroussin } 2212aae38d10SBaptiste Daroussin 2213aae38d10SBaptiste Daroussin #define IsDelay(ch) ((ch) == '.' || isdigit(UChar(ch))) 2214aae38d10SBaptiste Daroussin 2215aae38d10SBaptiste Daroussin static const char * 2216aae38d10SBaptiste Daroussin parse_delay_value(const char *src, double *delays, int *always) 2217aae38d10SBaptiste Daroussin { 2218aae38d10SBaptiste Daroussin int star = 0; 2219aae38d10SBaptiste Daroussin 2220aae38d10SBaptiste Daroussin *delays = 0.0; 2221aae38d10SBaptiste Daroussin if (always) 2222aae38d10SBaptiste Daroussin *always = 0; 2223aae38d10SBaptiste Daroussin 2224aae38d10SBaptiste Daroussin while (isdigit(UChar(*src))) { 2225aae38d10SBaptiste Daroussin (*delays) = (*delays) * 10 + (*src++ - '0'); 2226aae38d10SBaptiste Daroussin } 2227aae38d10SBaptiste Daroussin if (*src == '.') { 2228aae38d10SBaptiste Daroussin int gotdot = 1; 2229aae38d10SBaptiste Daroussin 2230aae38d10SBaptiste Daroussin ++src; 2231aae38d10SBaptiste Daroussin while (isdigit(UChar(*src))) { 2232aae38d10SBaptiste Daroussin gotdot *= 10; 2233aae38d10SBaptiste Daroussin (*delays) += (*src++ - '0') / gotdot; 2234aae38d10SBaptiste Daroussin } 2235aae38d10SBaptiste Daroussin } 2236aae38d10SBaptiste Daroussin while (*src == '*' || *src == '/') { 2237aae38d10SBaptiste Daroussin if (always == 0 && *src == '/') 2238aae38d10SBaptiste Daroussin break; 2239aae38d10SBaptiste Daroussin if (*src++ == '*') { 2240aae38d10SBaptiste Daroussin star = 1; 2241aae38d10SBaptiste Daroussin } else { 2242aae38d10SBaptiste Daroussin *always = 1; 2243aae38d10SBaptiste Daroussin } 2244aae38d10SBaptiste Daroussin } 2245aae38d10SBaptiste Daroussin if (star) 2246aae38d10SBaptiste Daroussin *delays = -(*delays); 2247aae38d10SBaptiste Daroussin return src; 2248aae38d10SBaptiste Daroussin } 2249aae38d10SBaptiste Daroussin 2250aae38d10SBaptiste Daroussin static const char * 2251aae38d10SBaptiste Daroussin parse_ti_delay(const char *ti, double *delays) 2252aae38d10SBaptiste Daroussin { 2253aae38d10SBaptiste Daroussin *delays = 0.0; 2254aae38d10SBaptiste Daroussin while (*ti != '\0') { 2255aae38d10SBaptiste Daroussin if (*ti == '\\') { 2256aae38d10SBaptiste Daroussin ++ti; 2257aae38d10SBaptiste Daroussin } 2258aae38d10SBaptiste Daroussin if (ti[0] == '$' 2259aae38d10SBaptiste Daroussin && ti[1] == '<' 2260aae38d10SBaptiste Daroussin && IsDelay(UChar(ti[2]))) { 2261aae38d10SBaptiste Daroussin int ignored; 2262aae38d10SBaptiste Daroussin const char *last = parse_delay_value(ti + 2, delays, &ignored); 2263aae38d10SBaptiste Daroussin if (*last == '>') { 2264aae38d10SBaptiste Daroussin ti = last; 2265aae38d10SBaptiste Daroussin } 2266aae38d10SBaptiste Daroussin } else { 2267aae38d10SBaptiste Daroussin ++ti; 2268aae38d10SBaptiste Daroussin } 2269aae38d10SBaptiste Daroussin } 2270aae38d10SBaptiste Daroussin return ti; 2271aae38d10SBaptiste Daroussin } 2272aae38d10SBaptiste Daroussin 2273aae38d10SBaptiste Daroussin static const char * 2274aae38d10SBaptiste Daroussin parse_tc_delay(const char *tc, double *delays) 2275aae38d10SBaptiste Daroussin { 2276aae38d10SBaptiste Daroussin return parse_delay_value(tc, delays, (int *) 0); 2277aae38d10SBaptiste Daroussin } 2278aae38d10SBaptiste Daroussin 2279aae38d10SBaptiste Daroussin /* 2280aae38d10SBaptiste Daroussin * Compare terminfo- and termcap-strings, factoring out delays. 2281aae38d10SBaptiste Daroussin */ 2282aae38d10SBaptiste Daroussin static bool 2283aae38d10SBaptiste Daroussin same_ti_tc(const char *ti, const char *tc, bool * embedded) 2284aae38d10SBaptiste Daroussin { 2285aae38d10SBaptiste Daroussin bool same = TRUE; 2286aae38d10SBaptiste Daroussin double ti_delay = 0.0; 2287aae38d10SBaptiste Daroussin double tc_delay = 0.0; 2288aae38d10SBaptiste Daroussin const char *ti_last; 2289aae38d10SBaptiste Daroussin 2290aae38d10SBaptiste Daroussin *embedded = FALSE; 2291aae38d10SBaptiste Daroussin ti_last = parse_ti_delay(ti, &ti_delay); 2292aae38d10SBaptiste Daroussin tc = parse_tc_delay(tc, &tc_delay); 2293aae38d10SBaptiste Daroussin 2294aae38d10SBaptiste Daroussin while ((ti < ti_last) && *tc) { 2295aae38d10SBaptiste Daroussin if (*ti == '\\' && ispunct(UChar(ti[1]))) { 2296aae38d10SBaptiste Daroussin ++ti; 2297aae38d10SBaptiste Daroussin if ((*ti == '^') && !strncmp(tc, "\\136", 4)) { 2298aae38d10SBaptiste Daroussin ti += 1; 2299aae38d10SBaptiste Daroussin tc += 4; 2300aae38d10SBaptiste Daroussin continue; 2301aae38d10SBaptiste Daroussin } 2302aae38d10SBaptiste Daroussin } else if (ti[0] == '$' && ti[1] == '<') { 2303aae38d10SBaptiste Daroussin double no_delay; 2304aae38d10SBaptiste Daroussin const char *ss = parse_ti_delay(ti, &no_delay); 2305aae38d10SBaptiste Daroussin if (ss != ti) { 2306aae38d10SBaptiste Daroussin *embedded = TRUE; 2307aae38d10SBaptiste Daroussin ti = ss; 2308aae38d10SBaptiste Daroussin continue; 2309aae38d10SBaptiste Daroussin } 2310aae38d10SBaptiste Daroussin } 2311aae38d10SBaptiste Daroussin if (*tc == '\\' && ispunct(UChar(tc[1]))) { 2312aae38d10SBaptiste Daroussin ++tc; 2313aae38d10SBaptiste Daroussin } 2314aae38d10SBaptiste Daroussin if (*ti++ != *tc++) { 2315aae38d10SBaptiste Daroussin same = FALSE; 2316aae38d10SBaptiste Daroussin break; 2317aae38d10SBaptiste Daroussin } 2318aae38d10SBaptiste Daroussin } 2319aae38d10SBaptiste Daroussin 2320aae38d10SBaptiste Daroussin if (*embedded) { 2321aae38d10SBaptiste Daroussin if (same) { 2322aae38d10SBaptiste Daroussin same = FALSE; 2323aae38d10SBaptiste Daroussin } else { 2324aae38d10SBaptiste Daroussin *embedded = FALSE; /* report only one problem */ 2325aae38d10SBaptiste Daroussin } 2326aae38d10SBaptiste Daroussin } 2327aae38d10SBaptiste Daroussin 2328aae38d10SBaptiste Daroussin return same; 2329aae38d10SBaptiste Daroussin } 2330aae38d10SBaptiste Daroussin 2331aae38d10SBaptiste Daroussin /* 2332aae38d10SBaptiste Daroussin * Check terminfo to termcap translation. 2333aae38d10SBaptiste Daroussin */ 2334aae38d10SBaptiste Daroussin static void 2335aae38d10SBaptiste Daroussin check_infotocap(TERMTYPE2 *tp, int i, const char *value) 2336aae38d10SBaptiste Daroussin { 2337aae38d10SBaptiste Daroussin const char *name = ExtStrname(tp, i, strnames); 2338aae38d10SBaptiste Daroussin int params = ((i < (int) SIZEOF(parametrized)) 2339aae38d10SBaptiste Daroussin ? parametrized[i] 2340aae38d10SBaptiste Daroussin : ((*value == 'k') 2341aae38d10SBaptiste Daroussin ? 0 2342aae38d10SBaptiste Daroussin : has_params(value))); 2343aae38d10SBaptiste Daroussin int to_char = 0; 2344aae38d10SBaptiste Daroussin char *ti_value; 2345aae38d10SBaptiste Daroussin char *tc_value; 2346aae38d10SBaptiste Daroussin bool embedded; 2347aae38d10SBaptiste Daroussin 2348aae38d10SBaptiste Daroussin assert(SIZEOF(parametrized) == STRCOUNT); 2349aae38d10SBaptiste Daroussin if ((ti_value = _nc_tic_expand(value, TRUE, to_char)) == ABSENT_STRING) { 2350aae38d10SBaptiste Daroussin _nc_warning("tic-expansion of %s failed", name); 2351aae38d10SBaptiste Daroussin } else if ((tc_value = _nc_infotocap(name, ti_value, params)) == ABSENT_STRING) { 2352aae38d10SBaptiste Daroussin _nc_warning("tic-conversion of %s failed", name); 2353aae38d10SBaptiste Daroussin } else if (params > 0) { 2354aae38d10SBaptiste Daroussin int limit = 5; 2355aae38d10SBaptiste Daroussin int count; 2356aae38d10SBaptiste Daroussin bool first = TRUE; 2357aae38d10SBaptiste Daroussin 2358aae38d10SBaptiste Daroussin if (!strcmp(name, "setf") 2359aae38d10SBaptiste Daroussin || !strcmp(name, "setb") 2360aae38d10SBaptiste Daroussin || !strcmp(name, "setaf") 2361aae38d10SBaptiste Daroussin || !strcmp(name, "setab")) { 2362aae38d10SBaptiste Daroussin if ((limit = max_colors) > 16) 2363aae38d10SBaptiste Daroussin limit = 16; 2364aae38d10SBaptiste Daroussin } 2365aae38d10SBaptiste Daroussin for (count = 0; count < limit; ++count) { 2366aae38d10SBaptiste Daroussin char *ti_check = check_1_infotocap(name, ti_value, count); 2367aae38d10SBaptiste Daroussin char *tc_check = check_1_infotocap(name, tc_value, count); 2368aae38d10SBaptiste Daroussin 2369aae38d10SBaptiste Daroussin if (strcmp(ti_check, tc_check)) { 2370aae38d10SBaptiste Daroussin if (first) { 2371aae38d10SBaptiste Daroussin fprintf(stderr, "check_infotocap(%s)\n", name); 2372aae38d10SBaptiste Daroussin fprintf(stderr, "...ti '%s'\n", ti_value); 2373aae38d10SBaptiste Daroussin fprintf(stderr, "...tc '%s'\n", tc_value); 2374aae38d10SBaptiste Daroussin first = FALSE; 2375aae38d10SBaptiste Daroussin } 2376aae38d10SBaptiste Daroussin _nc_warning("tparm-conversion of %s(%d) differs between\n\tterminfo %s\n\ttermcap %s", 2377aae38d10SBaptiste Daroussin name, count, ti_check, tc_check); 2378aae38d10SBaptiste Daroussin } 2379aae38d10SBaptiste Daroussin free(ti_check); 2380aae38d10SBaptiste Daroussin free(tc_check); 2381aae38d10SBaptiste Daroussin } 2382aae38d10SBaptiste Daroussin } else if (params == 0 && !same_ti_tc(ti_value, tc_value, &embedded)) { 2383aae38d10SBaptiste Daroussin if (embedded) { 2384aae38d10SBaptiste Daroussin _nc_warning("termcap equivalent of %s cannot use embedded delay", name); 2385aae38d10SBaptiste Daroussin } else { 2386aae38d10SBaptiste Daroussin _nc_warning("tic-conversion of %s changed value\n\tfrom %s\n\tto %s", 2387aae38d10SBaptiste Daroussin name, ti_value, tc_value); 2388aae38d10SBaptiste Daroussin } 2389aae38d10SBaptiste Daroussin } 239018259542SPeter Wemm } 239118259542SPeter Wemm 2392b82face1SPeter Wemm static char * 2393b82face1SPeter Wemm skip_delay(char *s) 2394b82face1SPeter Wemm { 2395b82face1SPeter Wemm while (*s == '/' || isdigit(UChar(*s))) 2396b82face1SPeter Wemm ++s; 2397b82face1SPeter Wemm return s; 2398b82face1SPeter Wemm } 2399b82face1SPeter Wemm 240018259542SPeter Wemm /* 24014a1a9510SRong-En Fan * Skip a delay altogether, e.g., when comparing a simple string to sgr, 24024a1a9510SRong-En Fan * the latter may have a worst-case delay on the end. 24034a1a9510SRong-En Fan */ 24044a1a9510SRong-En Fan static char * 24054a1a9510SRong-En Fan ignore_delays(char *s) 24064a1a9510SRong-En Fan { 24074a1a9510SRong-En Fan int delaying = 0; 24084a1a9510SRong-En Fan 24094a1a9510SRong-En Fan do { 24104a1a9510SRong-En Fan switch (*s) { 24114a1a9510SRong-En Fan case '$': 24124a1a9510SRong-En Fan if (delaying == 0) 24134a1a9510SRong-En Fan delaying = 1; 24144a1a9510SRong-En Fan break; 24154a1a9510SRong-En Fan case '<': 24164a1a9510SRong-En Fan if (delaying == 1) 24174a1a9510SRong-En Fan delaying = 2; 24184a1a9510SRong-En Fan break; 24194a1a9510SRong-En Fan case '\0': 24204a1a9510SRong-En Fan delaying = 0; 24214a1a9510SRong-En Fan break; 24224a1a9510SRong-En Fan default: 24234a1a9510SRong-En Fan if (delaying) { 24244a1a9510SRong-En Fan s = skip_delay(s); 24254a1a9510SRong-En Fan if (*s == '>') 24264a1a9510SRong-En Fan ++s; 24274a1a9510SRong-En Fan delaying = 0; 24284a1a9510SRong-En Fan } 24294a1a9510SRong-En Fan break; 24304a1a9510SRong-En Fan } 24314a1a9510SRong-En Fan if (delaying) 24324a1a9510SRong-En Fan ++s; 24334a1a9510SRong-En Fan } while (delaying); 24344a1a9510SRong-En Fan return s; 24354a1a9510SRong-En Fan } 24364a1a9510SRong-En Fan 2437aae38d10SBaptiste Daroussin #define DATA(name) { #name } 2438aae38d10SBaptiste Daroussin static const char sgr_names[][11] = 2439aae38d10SBaptiste Daroussin { 2440aae38d10SBaptiste Daroussin DATA(none), 2441aae38d10SBaptiste Daroussin DATA(standout), 2442aae38d10SBaptiste Daroussin DATA(underline), 2443aae38d10SBaptiste Daroussin DATA(reverse), 2444aae38d10SBaptiste Daroussin DATA(blink), 2445aae38d10SBaptiste Daroussin DATA(dim), 2446aae38d10SBaptiste Daroussin DATA(bold), 2447aae38d10SBaptiste Daroussin DATA(invis), 2448aae38d10SBaptiste Daroussin DATA(protect), 2449aae38d10SBaptiste Daroussin DATA(altcharset), 2450aae38d10SBaptiste Daroussin "" 2451aae38d10SBaptiste Daroussin }; 2452aae38d10SBaptiste Daroussin #undef DATA 2453aae38d10SBaptiste Daroussin 24544a1a9510SRong-En Fan /* 245515589c42SPeter Wemm * An sgr string may contain several settings other than the one we're 245615589c42SPeter Wemm * interested in, essentially sgr0 + rmacs + whatever. As long as the 245715589c42SPeter Wemm * "whatever" is contained in the sgr string, that is close enough for our 245815589c42SPeter Wemm * sanity check. 245915589c42SPeter Wemm */ 246015589c42SPeter Wemm static bool 2461b82face1SPeter Wemm similar_sgr(int num, char *a, char *b) 246215589c42SPeter Wemm { 2463b82face1SPeter Wemm char *base_a = a; 2464b82face1SPeter Wemm char *base_b = b; 2465b82face1SPeter Wemm int delaying = 0; 2466b82face1SPeter Wemm 246715589c42SPeter Wemm while (*b != 0) { 246815589c42SPeter Wemm while (*a != *b) { 24697a69bbfbSPeter Wemm if (*a == 0) { 2470aae38d10SBaptiste Daroussin if (num < 0) { 2471aae38d10SBaptiste Daroussin ; 2472aae38d10SBaptiste Daroussin } else if (b[0] == '$' 24737a69bbfbSPeter Wemm && b[1] == '<') { 2474aae38d10SBaptiste Daroussin _nc_warning("did not find delay %s", _nc_visbuf(b)); 24757a69bbfbSPeter Wemm } else { 2476b82face1SPeter Wemm _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s", 2477aae38d10SBaptiste Daroussin sgr_names[num], _nc_visbuf2(1, base_a), 2478b82face1SPeter Wemm _nc_visbuf2(2, base_b), 2479b82face1SPeter Wemm _nc_visbuf2(3, b)); 24807a69bbfbSPeter Wemm } 248115589c42SPeter Wemm return FALSE; 2482b82face1SPeter Wemm } else if (delaying) { 2483b82face1SPeter Wemm a = skip_delay(a); 2484b82face1SPeter Wemm b = skip_delay(b); 248506bfebdeSXin LI } else if ((*b == '0' || (*b == ';')) && *a == 'm') { 248606bfebdeSXin LI b++; 2487b82face1SPeter Wemm } else { 248815589c42SPeter Wemm a++; 248915589c42SPeter Wemm } 2490b82face1SPeter Wemm } 2491b82face1SPeter Wemm switch (*a) { 2492b82face1SPeter Wemm case '$': 2493b82face1SPeter Wemm if (delaying == 0) 2494b82face1SPeter Wemm delaying = 1; 2495b82face1SPeter Wemm break; 2496b82face1SPeter Wemm case '<': 2497b82face1SPeter Wemm if (delaying == 1) 2498b82face1SPeter Wemm delaying = 2; 2499b82face1SPeter Wemm break; 2500b82face1SPeter Wemm default: 2501b82face1SPeter Wemm delaying = 0; 2502b82face1SPeter Wemm break; 2503b82face1SPeter Wemm } 250415589c42SPeter Wemm a++; 250515589c42SPeter Wemm b++; 250615589c42SPeter Wemm } 25074a1a9510SRong-En Fan /* ignore delays on the end of the string */ 25084a1a9510SRong-En Fan a = ignore_delays(a); 25094a1a9510SRong-En Fan return ((num != 0) || (*a == 0)); 251015589c42SPeter Wemm } 251115589c42SPeter Wemm 25124a1a9510SRong-En Fan static char * 2513aae38d10SBaptiste Daroussin check_sgr(TERMTYPE2 *tp, char *zero, int num, char *cap, const char *name) 251415589c42SPeter Wemm { 25154a1a9510SRong-En Fan char *test; 25164a1a9510SRong-En Fan 25174a1a9510SRong-En Fan _nc_tparm_err = 0; 25184a1a9510SRong-En Fan test = TPARM_9(set_attributes, 251915589c42SPeter Wemm num == 1, 252015589c42SPeter Wemm num == 2, 252115589c42SPeter Wemm num == 3, 252215589c42SPeter Wemm num == 4, 252315589c42SPeter Wemm num == 5, 252415589c42SPeter Wemm num == 6, 252515589c42SPeter Wemm num == 7, 252615589c42SPeter Wemm num == 8, 252715589c42SPeter Wemm num == 9); 252815589c42SPeter Wemm if (test != 0) { 252915589c42SPeter Wemm if (PRESENT(cap)) { 2530b82face1SPeter Wemm if (!similar_sgr(num, test, cap)) { 2531b82face1SPeter Wemm _nc_warning("%s differs from sgr(%d)\n\t%s=%s\n\tsgr(%d)=%s", 2532b82face1SPeter Wemm name, num, 2533b82face1SPeter Wemm name, _nc_visbuf2(1, cap), 2534b82face1SPeter Wemm num, _nc_visbuf2(2, test)); 253515589c42SPeter Wemm } 25364a1a9510SRong-En Fan } else if (_nc_capcmp(test, zero)) { 253715589c42SPeter Wemm _nc_warning("sgr(%d) present, but not %s", num, name); 253815589c42SPeter Wemm } 253915589c42SPeter Wemm } else if (PRESENT(cap)) { 254015589c42SPeter Wemm _nc_warning("sgr(%d) missing, but %s present", num, name); 254115589c42SPeter Wemm } 25424a1a9510SRong-En Fan if (_nc_tparm_err) 25434a1a9510SRong-En Fan _nc_warning("stack error in sgr(%d) string", num); 25444a1a9510SRong-En Fan return test; 254515589c42SPeter Wemm } 254615589c42SPeter Wemm 254715589c42SPeter Wemm #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name) 254815589c42SPeter Wemm 25494a1a9510SRong-En Fan #ifdef TRACE 25504a1a9510SRong-En Fan /* 25514a1a9510SRong-En Fan * If tic is compiled with TRACE, we'll be able to see the output from the 25524a1a9510SRong-En Fan * DEBUG() macro. But since it doesn't use traceon(), it always goes to 25534a1a9510SRong-En Fan * the standard error. Use this function to make it simpler to follow the 25544a1a9510SRong-En Fan * resulting debug traces. 25554a1a9510SRong-En Fan */ 25564a1a9510SRong-En Fan static void 25574a1a9510SRong-En Fan show_where(unsigned level) 25584a1a9510SRong-En Fan { 25594a1a9510SRong-En Fan if (_nc_tracing >= DEBUG_LEVEL(level)) { 256073f0a83dSXin LI char my_name[MAX_NAME_SIZE]; 25614a1a9510SRong-En Fan _nc_get_type(my_name); 256206bfebdeSXin LI _tracef("\"%s\", line %d, '%s'", 25634a1a9510SRong-En Fan _nc_get_source(), 25644a1a9510SRong-En Fan _nc_curr_line, my_name); 25654a1a9510SRong-En Fan } 25664a1a9510SRong-En Fan } 25674a1a9510SRong-En Fan 25684a1a9510SRong-En Fan #else 25694a1a9510SRong-En Fan #define show_where(level) /* nothing */ 25704a1a9510SRong-En Fan #endif 25714a1a9510SRong-En Fan 257273f0a83dSXin LI typedef struct { 257373f0a83dSXin LI int keycode; 257473f0a83dSXin LI const char *name; 257573f0a83dSXin LI const char *value; 257673f0a83dSXin LI } NAME_VALUE; 257773f0a83dSXin LI 257873f0a83dSXin LI static NAME_VALUE * 2579aae38d10SBaptiste Daroussin get_fkey_list(TERMTYPE2 *tp) 258073f0a83dSXin LI { 258173f0a83dSXin LI NAME_VALUE *result = typeMalloc(NAME_VALUE, NUM_STRINGS(tp) + 1); 258273f0a83dSXin LI const struct tinfo_fkeys *all_fkeys = _nc_tinfo_fkeys; 258373f0a83dSXin LI int used = 0; 2584aae38d10SBaptiste Daroussin unsigned j; 258573f0a83dSXin LI 258673f0a83dSXin LI if (result == 0) 258773f0a83dSXin LI failed("get_fkey_list"); 258873f0a83dSXin LI 258973f0a83dSXin LI for (j = 0; all_fkeys[j].code; j++) { 259073f0a83dSXin LI char *a = tp->Strings[all_fkeys[j].offset]; 259173f0a83dSXin LI if (VALID_STRING(a)) { 259273f0a83dSXin LI result[used].keycode = (int) all_fkeys[j].code; 259373f0a83dSXin LI result[used].name = strnames[all_fkeys[j].offset]; 259473f0a83dSXin LI result[used].value = a; 259573f0a83dSXin LI ++used; 259673f0a83dSXin LI } 259773f0a83dSXin LI } 259873f0a83dSXin LI #if NCURSES_XNAMES 259973f0a83dSXin LI for (j = STRCOUNT; j < NUM_STRINGS(tp); ++j) { 2600aae38d10SBaptiste Daroussin const char *name = ExtStrname(tp, (int) j, strnames); 260173f0a83dSXin LI if (*name == 'k') { 260273f0a83dSXin LI result[used].keycode = -1; 260373f0a83dSXin LI result[used].name = name; 260473f0a83dSXin LI result[used].value = tp->Strings[j]; 260573f0a83dSXin LI ++used; 260673f0a83dSXin LI } 260773f0a83dSXin LI } 260873f0a83dSXin LI #endif 260973f0a83dSXin LI result[used].keycode = 0; 261073f0a83dSXin LI return result; 261173f0a83dSXin LI } 261273f0a83dSXin LI 261373f0a83dSXin LI static void 261473f0a83dSXin LI show_fkey_name(NAME_VALUE * data) 261573f0a83dSXin LI { 261673f0a83dSXin LI if (data->keycode > 0) { 261773f0a83dSXin LI fprintf(stderr, " %s", keyname(data->keycode)); 261873f0a83dSXin LI fprintf(stderr, " (capability \"%s\")", data->name); 261973f0a83dSXin LI } else { 262073f0a83dSXin LI fprintf(stderr, " capability \"%s\"", data->name); 262173f0a83dSXin LI } 262273f0a83dSXin LI } 262373f0a83dSXin LI 2624aae38d10SBaptiste Daroussin /* 2625aae38d10SBaptiste Daroussin * A terminal entry may contain more than one keycode assigned to a given 2626aae38d10SBaptiste Daroussin * string (e.g., KEY_END and KEY_LL). But curses will only return one (the 2627aae38d10SBaptiste Daroussin * last one assigned). 26280e3d5408SPeter Wemm */ 262915589c42SPeter Wemm static void 2630aae38d10SBaptiste Daroussin check_conflict(TERMTYPE2 *tp) 26310e3d5408SPeter Wemm { 26320e3d5408SPeter Wemm bool conflict = FALSE; 26330e3d5408SPeter Wemm unsigned j, k; 26340e3d5408SPeter Wemm 26354a1a9510SRong-En Fan if (!(_nc_syntax == SYN_TERMCAP && capdump)) { 263673f0a83dSXin LI char *check = calloc((size_t) (NUM_STRINGS(tp) + 1), sizeof(char)); 263773f0a83dSXin LI NAME_VALUE *given = get_fkey_list(tp); 263873f0a83dSXin LI 263973f0a83dSXin LI if (check == 0) 2640aae38d10SBaptiste Daroussin failed("check_conflict"); 264173f0a83dSXin LI 264273f0a83dSXin LI for (j = 0; given[j].keycode; ++j) { 264373f0a83dSXin LI const char *a = given[j].value; 26440e3d5408SPeter Wemm bool first = TRUE; 264573f0a83dSXin LI 2646aae38d10SBaptiste Daroussin if (!VALID_STRING(a)) 2647aae38d10SBaptiste Daroussin continue; 2648aae38d10SBaptiste Daroussin 264973f0a83dSXin LI for (k = j + 1; given[k].keycode; k++) { 265073f0a83dSXin LI const char *b = given[k].value; 2651aae38d10SBaptiste Daroussin 2652aae38d10SBaptiste Daroussin if (!VALID_STRING(b)) 2653aae38d10SBaptiste Daroussin continue; 265473f0a83dSXin LI if (check[k]) 26550e3d5408SPeter Wemm continue; 2656aae38d10SBaptiste Daroussin 26574a1a9510SRong-En Fan if (!_nc_capcmp(a, b)) { 265873f0a83dSXin LI check[j] = 1; 265973f0a83dSXin LI check[k] = 1; 26600e3d5408SPeter Wemm if (first) { 26610e3d5408SPeter Wemm if (!conflict) { 2662aae38d10SBaptiste Daroussin _nc_warning("conflicting key definitions (using the last)"); 26630e3d5408SPeter Wemm conflict = TRUE; 26640e3d5408SPeter Wemm } 266573f0a83dSXin LI fprintf(stderr, "..."); 266673f0a83dSXin LI show_fkey_name(given + j); 266773f0a83dSXin LI fprintf(stderr, " is the same as"); 266873f0a83dSXin LI show_fkey_name(given + k); 26690e3d5408SPeter Wemm first = FALSE; 26700e3d5408SPeter Wemm } else { 267173f0a83dSXin LI fprintf(stderr, ", "); 267273f0a83dSXin LI show_fkey_name(given + k); 26730e3d5408SPeter Wemm } 26740e3d5408SPeter Wemm } 26750e3d5408SPeter Wemm } 26760e3d5408SPeter Wemm if (!first) 26770e3d5408SPeter Wemm fprintf(stderr, "\n"); 26780e3d5408SPeter Wemm } 2679aae38d10SBaptiste Daroussin #if NCURSES_XNAMES 2680aae38d10SBaptiste Daroussin if (using_extensions) { 2681aae38d10SBaptiste Daroussin /* *INDENT-OFF* */ 2682aae38d10SBaptiste Daroussin static struct { 2683aae38d10SBaptiste Daroussin const char *xcurses; 2684aae38d10SBaptiste Daroussin const char *shifted; 2685aae38d10SBaptiste Daroussin } table[] = { 2686aae38d10SBaptiste Daroussin { "kDC", NULL }, 2687aae38d10SBaptiste Daroussin { "kDN", "kind" }, 2688aae38d10SBaptiste Daroussin { "kEND", NULL }, 2689aae38d10SBaptiste Daroussin { "kHOM", NULL }, 2690aae38d10SBaptiste Daroussin { "kLFT", NULL }, 2691aae38d10SBaptiste Daroussin { "kNXT", NULL }, 2692aae38d10SBaptiste Daroussin { "kPRV", NULL }, 2693aae38d10SBaptiste Daroussin { "kRIT", NULL }, 2694aae38d10SBaptiste Daroussin { "kUP", "kri" }, 2695aae38d10SBaptiste Daroussin { NULL, NULL }, 2696aae38d10SBaptiste Daroussin }; 2697aae38d10SBaptiste Daroussin /* *INDENT-ON* */ 2698aae38d10SBaptiste Daroussin 2699aae38d10SBaptiste Daroussin /* 2700aae38d10SBaptiste Daroussin * SVr4 curses defines the "xcurses" names listed above except for 2701aae38d10SBaptiste Daroussin * the special cases in the "shifted" column. When using these 2702aae38d10SBaptiste Daroussin * names for xterm's extensions, that was confusing, and resulted 2703aae38d10SBaptiste Daroussin * in adding extended capabilities with "2" (shift) suffix. This 2704aae38d10SBaptiste Daroussin * check warns about unnecessary use of extensions for this quirk. 2705aae38d10SBaptiste Daroussin */ 2706aae38d10SBaptiste Daroussin for (j = 0; given[j].keycode; ++j) { 2707aae38d10SBaptiste Daroussin const char *find = given[j].name; 2708aae38d10SBaptiste Daroussin int value; 2709aae38d10SBaptiste Daroussin char ch; 2710aae38d10SBaptiste Daroussin 2711aae38d10SBaptiste Daroussin if (!VALID_STRING(given[j].value)) 2712aae38d10SBaptiste Daroussin continue; 2713aae38d10SBaptiste Daroussin 2714aae38d10SBaptiste Daroussin for (k = 0; table[k].xcurses; ++k) { 2715aae38d10SBaptiste Daroussin const char *test = table[k].xcurses; 2716aae38d10SBaptiste Daroussin size_t size = strlen(test); 2717aae38d10SBaptiste Daroussin 2718aae38d10SBaptiste Daroussin if (!strncmp(find, test, size) && strcmp(find, test)) { 2719aae38d10SBaptiste Daroussin switch (sscanf(find + size, "%d%c", &value, &ch)) { 2720aae38d10SBaptiste Daroussin case 1: 2721aae38d10SBaptiste Daroussin if (value == 2) { 2722aae38d10SBaptiste Daroussin _nc_warning("expected '%s' rather than '%s'", 2723aae38d10SBaptiste Daroussin (table[k].shifted 2724aae38d10SBaptiste Daroussin ? table[k].shifted 2725aae38d10SBaptiste Daroussin : test), find); 2726aae38d10SBaptiste Daroussin } else if (value < 2 || value > 15) { 2727aae38d10SBaptiste Daroussin _nc_warning("expected numeric 2..15 '%s'", find); 2728aae38d10SBaptiste Daroussin } 2729aae38d10SBaptiste Daroussin break; 2730aae38d10SBaptiste Daroussin default: 2731aae38d10SBaptiste Daroussin _nc_warning("expected numeric suffix for '%s'", find); 2732aae38d10SBaptiste Daroussin break; 2733aae38d10SBaptiste Daroussin } 2734aae38d10SBaptiste Daroussin break; 2735aae38d10SBaptiste Daroussin } 2736aae38d10SBaptiste Daroussin } 2737aae38d10SBaptiste Daroussin } 2738aae38d10SBaptiste Daroussin } 2739aae38d10SBaptiste Daroussin #endif 274073f0a83dSXin LI free(given); 274173f0a83dSXin LI free(check); 27424a1a9510SRong-En Fan } 2743aae38d10SBaptiste Daroussin } 2744aae38d10SBaptiste Daroussin 2745aae38d10SBaptiste Daroussin /* 2746aae38d10SBaptiste Daroussin * Exiting a video mode should not duplicate sgr0 2747aae38d10SBaptiste Daroussin */ 2748aae38d10SBaptiste Daroussin static void 2749aae38d10SBaptiste Daroussin check_exit_attribute(const char *name, char *test, char *trimmed, char *untrimmed) 2750aae38d10SBaptiste Daroussin { 2751aae38d10SBaptiste Daroussin if (VALID_STRING(test) && (trimmed != 0)) { 2752aae38d10SBaptiste Daroussin if (similar_sgr(-1, trimmed, test) || 2753aae38d10SBaptiste Daroussin similar_sgr(-1, untrimmed, test)) { 2754aae38d10SBaptiste Daroussin _nc_warning("%s matches exit_attribute_mode", name); 2755aae38d10SBaptiste Daroussin } 2756aae38d10SBaptiste Daroussin } 2757aae38d10SBaptiste Daroussin } 2758aae38d10SBaptiste Daroussin 2759aae38d10SBaptiste Daroussin /* 2760aae38d10SBaptiste Daroussin * Returns true if the string looks like a standard SGR string. 2761aae38d10SBaptiste Daroussin */ 2762aae38d10SBaptiste Daroussin static bool 2763aae38d10SBaptiste Daroussin is_sgr_string(char *value) 2764aae38d10SBaptiste Daroussin { 2765aae38d10SBaptiste Daroussin bool result = FALSE; 2766aae38d10SBaptiste Daroussin 2767aae38d10SBaptiste Daroussin if (VALID_STRING(value)) { 2768aae38d10SBaptiste Daroussin int skip = csi_length(value); 2769aae38d10SBaptiste Daroussin 2770aae38d10SBaptiste Daroussin if (skip) { 2771aae38d10SBaptiste Daroussin int ch; 2772aae38d10SBaptiste Daroussin 2773aae38d10SBaptiste Daroussin result = TRUE; 2774aae38d10SBaptiste Daroussin value += skip; 2775aae38d10SBaptiste Daroussin while ((ch = UChar(*value++)) != '\0') { 2776aae38d10SBaptiste Daroussin if (isdigit(ch) || ch == ';') { 2777aae38d10SBaptiste Daroussin ; 2778aae38d10SBaptiste Daroussin } else if (ch == 'm' && *value == '\0') { 2779aae38d10SBaptiste Daroussin ; 2780aae38d10SBaptiste Daroussin } else { 2781aae38d10SBaptiste Daroussin result = FALSE; 2782aae38d10SBaptiste Daroussin break; 2783aae38d10SBaptiste Daroussin } 2784aae38d10SBaptiste Daroussin } 2785aae38d10SBaptiste Daroussin } 2786aae38d10SBaptiste Daroussin } 2787aae38d10SBaptiste Daroussin return result; 2788aae38d10SBaptiste Daroussin } 2789aae38d10SBaptiste Daroussin 2790aae38d10SBaptiste Daroussin /* 2791aae38d10SBaptiste Daroussin * Check if the given capability contains a given SGR attribute. 2792aae38d10SBaptiste Daroussin */ 2793aae38d10SBaptiste Daroussin static void 2794aae38d10SBaptiste Daroussin check_sgr_param(TERMTYPE2 *tp, int code, const char *name, char *value) 2795aae38d10SBaptiste Daroussin { 2796aae38d10SBaptiste Daroussin if (VALID_STRING(value)) { 2797aae38d10SBaptiste Daroussin int ncv = ((code != 0) ? (1 << (code - 1)) : 0); 2798aae38d10SBaptiste Daroussin char *test = tgoto(value, 0, 0); 2799aae38d10SBaptiste Daroussin if (is_sgr_string(test)) { 2800aae38d10SBaptiste Daroussin int param = 0; 2801aae38d10SBaptiste Daroussin int count = 0; 2802aae38d10SBaptiste Daroussin int skips = 0; 2803aae38d10SBaptiste Daroussin int color = (value == set_a_foreground || 2804aae38d10SBaptiste Daroussin value == set_a_background || 2805aae38d10SBaptiste Daroussin value == set_foreground || 2806aae38d10SBaptiste Daroussin value == set_background); 2807aae38d10SBaptiste Daroussin while (*test != 0) { 2808aae38d10SBaptiste Daroussin if (isdigit(UChar(*test))) { 2809aae38d10SBaptiste Daroussin param = 10 * param + (*test - '0'); 2810aae38d10SBaptiste Daroussin ++count; 2811aae38d10SBaptiste Daroussin } else { 2812aae38d10SBaptiste Daroussin if (count) { 2813aae38d10SBaptiste Daroussin /* 2814aae38d10SBaptiste Daroussin * Avoid unnecessary warning for xterm 256color codes. 2815aae38d10SBaptiste Daroussin */ 2816aae38d10SBaptiste Daroussin if (color && (param == 38 || param == 48)) 2817aae38d10SBaptiste Daroussin skips = 3; 2818aae38d10SBaptiste Daroussin if ((skips-- <= 0) && (param == code)) 2819aae38d10SBaptiste Daroussin break; 2820aae38d10SBaptiste Daroussin } 2821aae38d10SBaptiste Daroussin count = 0; 2822aae38d10SBaptiste Daroussin param = 0; 2823aae38d10SBaptiste Daroussin } 2824aae38d10SBaptiste Daroussin ++test; 2825aae38d10SBaptiste Daroussin } 2826aae38d10SBaptiste Daroussin if (count != 0 && param == code) { 2827aae38d10SBaptiste Daroussin if (code == 0 || 2828aae38d10SBaptiste Daroussin no_color_video < 0 || 2829aae38d10SBaptiste Daroussin !(no_color_video & ncv)) { 2830aae38d10SBaptiste Daroussin _nc_warning("\"%s\" SGR-attribute used in %s", 2831aae38d10SBaptiste Daroussin sgr_names[code], 2832aae38d10SBaptiste Daroussin name); 2833aae38d10SBaptiste Daroussin } 2834aae38d10SBaptiste Daroussin } 2835aae38d10SBaptiste Daroussin } 2836aae38d10SBaptiste Daroussin } 2837aae38d10SBaptiste Daroussin } 2838aae38d10SBaptiste Daroussin 2839aae38d10SBaptiste Daroussin #if NCURSES_XNAMES 2840aae38d10SBaptiste Daroussin static int 2841aae38d10SBaptiste Daroussin standard_type(const char *name) 2842aae38d10SBaptiste Daroussin { 2843aae38d10SBaptiste Daroussin int result = -1; 2844aae38d10SBaptiste Daroussin const struct name_table_entry *np; 2845aae38d10SBaptiste Daroussin 2846aae38d10SBaptiste Daroussin if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0) { 2847aae38d10SBaptiste Daroussin result = np->nte_type; 2848aae38d10SBaptiste Daroussin } 2849aae38d10SBaptiste Daroussin return result; 2850aae38d10SBaptiste Daroussin } 2851aae38d10SBaptiste Daroussin 2852aae38d10SBaptiste Daroussin static const char * 2853aae38d10SBaptiste Daroussin name_of_type(int type) 2854aae38d10SBaptiste Daroussin { 2855aae38d10SBaptiste Daroussin const char *result = "unknown"; 2856aae38d10SBaptiste Daroussin switch (type) { 2857aae38d10SBaptiste Daroussin case BOOLEAN: 2858aae38d10SBaptiste Daroussin result = "boolean"; 2859aae38d10SBaptiste Daroussin break; 2860aae38d10SBaptiste Daroussin case NUMBER: 2861aae38d10SBaptiste Daroussin result = "number"; 2862aae38d10SBaptiste Daroussin break; 2863aae38d10SBaptiste Daroussin case STRING: 2864aae38d10SBaptiste Daroussin result = "string"; 2865aae38d10SBaptiste Daroussin break; 2866aae38d10SBaptiste Daroussin } 2867aae38d10SBaptiste Daroussin return result; 2868aae38d10SBaptiste Daroussin } 2869aae38d10SBaptiste Daroussin 2870aae38d10SBaptiste Daroussin static void 2871aae38d10SBaptiste Daroussin check_user_capability_type(const char *name, int actual) 2872aae38d10SBaptiste Daroussin { 2873aae38d10SBaptiste Daroussin if (lookup_user_capability(name) == 0) { 2874aae38d10SBaptiste Daroussin int expected = standard_type(name); 2875aae38d10SBaptiste Daroussin if (expected >= 0) { 2876aae38d10SBaptiste Daroussin _nc_warning("expected %s to be %s, but actually %s", 2877aae38d10SBaptiste Daroussin name, 2878aae38d10SBaptiste Daroussin name_of_type(actual), 2879aae38d10SBaptiste Daroussin name_of_type(expected) 2880aae38d10SBaptiste Daroussin ); 2881aae38d10SBaptiste Daroussin } else if (*name != 'k') { 2882aae38d10SBaptiste Daroussin _nc_warning("undocumented %s capability %s", 2883aae38d10SBaptiste Daroussin name_of_type(actual), 2884aae38d10SBaptiste Daroussin name); 2885aae38d10SBaptiste Daroussin } 2886aae38d10SBaptiste Daroussin } 2887aae38d10SBaptiste Daroussin } 2888aae38d10SBaptiste Daroussin #endif 2889aae38d10SBaptiste Daroussin 2890aae38d10SBaptiste Daroussin /* other sanity-checks (things that we don't want in the normal 2891aae38d10SBaptiste Daroussin * logic that reads a terminfo entry) 2892aae38d10SBaptiste Daroussin */ 2893aae38d10SBaptiste Daroussin static void 2894aae38d10SBaptiste Daroussin check_termtype(TERMTYPE2 *tp, bool literal) 2895aae38d10SBaptiste Daroussin { 2896aae38d10SBaptiste Daroussin unsigned j; 2897aae38d10SBaptiste Daroussin 2898aae38d10SBaptiste Daroussin check_conflict(tp); 28990e3d5408SPeter Wemm 290073f0a83dSXin LI for_each_string(j, tp) { 290118259542SPeter Wemm char *a = tp->Strings[j]; 2902aae38d10SBaptiste Daroussin if (VALID_STRING(a)) { 2903aae38d10SBaptiste Daroussin const char *name = ExtStrname(tp, (int) j, strnames); 2904aae38d10SBaptiste Daroussin /* 2905aae38d10SBaptiste Daroussin * If we expect parameters, or if there might be parameters, 2906aae38d10SBaptiste Daroussin * check for consistent number of parameters. 2907aae38d10SBaptiste Daroussin */ 2908aae38d10SBaptiste Daroussin if (j >= SIZEOF(parametrized) || 2909aae38d10SBaptiste Daroussin is_user_capability(name) >= 0 || 2910aae38d10SBaptiste Daroussin parametrized[j] > 0) { 2911aae38d10SBaptiste Daroussin check_params(tp, name, a, (j >= STRCOUNT)); 291218259542SPeter Wemm } 2913aae38d10SBaptiste Daroussin check_delays(tp, ExtStrname(tp, (int) j, strnames), a); 2914aae38d10SBaptiste Daroussin if (capdump) { 2915aae38d10SBaptiste Daroussin check_infotocap(tp, (int) j, a); 2916aae38d10SBaptiste Daroussin } 2917aae38d10SBaptiste Daroussin } 2918aae38d10SBaptiste Daroussin } 2919aae38d10SBaptiste Daroussin #if NCURSES_XNAMES 2920aae38d10SBaptiste Daroussin /* in extended mode, verify that each extension is expected type */ 2921aae38d10SBaptiste Daroussin for_each_ext_boolean(j, tp) { 2922aae38d10SBaptiste Daroussin check_user_capability_type(ExtBoolname(tp, (int) j, strnames), BOOLEAN); 2923aae38d10SBaptiste Daroussin } 2924aae38d10SBaptiste Daroussin for_each_ext_number(j, tp) { 2925aae38d10SBaptiste Daroussin check_user_capability_type(ExtNumname(tp, (int) j, strnames), NUMBER); 2926aae38d10SBaptiste Daroussin } 2927aae38d10SBaptiste Daroussin for_each_ext_string(j, tp) { 2928aae38d10SBaptiste Daroussin check_user_capability_type(ExtStrname(tp, (int) j, strnames), STRING); 2929aae38d10SBaptiste Daroussin } 2930aae38d10SBaptiste Daroussin #endif /* NCURSES_XNAMES */ 293118259542SPeter Wemm 29324a1a9510SRong-En Fan check_acs(tp); 29334a1a9510SRong-En Fan check_colors(tp); 293406bfebdeSXin LI check_cursor(tp); 29354a1a9510SRong-En Fan check_keypad(tp); 293606bfebdeSXin LI check_printer(tp); 293773f0a83dSXin LI check_screen(tp); 29380e3d5408SPeter Wemm 29390e3d5408SPeter Wemm /* 2940aae38d10SBaptiste Daroussin * These are probably both or none. 2941aae38d10SBaptiste Daroussin */ 2942aae38d10SBaptiste Daroussin PAIRED(parm_index, parm_rindex); 2943aae38d10SBaptiste Daroussin PAIRED(parm_ich, parm_dch); 2944aae38d10SBaptiste Daroussin 2945aae38d10SBaptiste Daroussin /* 29460e3d5408SPeter Wemm * These may be mismatched because the terminal description relies on 29470e3d5408SPeter Wemm * restoring the cursor visibility by resetting it. 29480e3d5408SPeter Wemm */ 294915589c42SPeter Wemm ANDMISSING(cursor_invisible, cursor_normal); 295015589c42SPeter Wemm ANDMISSING(cursor_visible, cursor_normal); 295115589c42SPeter Wemm 295215589c42SPeter Wemm if (PRESENT(cursor_visible) && PRESENT(cursor_normal) 29534a1a9510SRong-En Fan && !_nc_capcmp(cursor_visible, cursor_normal)) 295415589c42SPeter Wemm _nc_warning("cursor_visible is same as cursor_normal"); 29550e3d5408SPeter Wemm 29560e3d5408SPeter Wemm /* 29570e3d5408SPeter Wemm * From XSI & O'Reilly, we gather that sc/rc are required if csr is 29580e3d5408SPeter Wemm * given, because the cursor position after the scrolling operation is 29590e3d5408SPeter Wemm * performed is undefined. 29600e3d5408SPeter Wemm */ 296115589c42SPeter Wemm ANDMISSING(change_scroll_region, save_cursor); 296215589c42SPeter Wemm ANDMISSING(change_scroll_region, restore_cursor); 296315589c42SPeter Wemm 296406bfebdeSXin LI /* 296506bfebdeSXin LI * If we can clear tabs, we should be able to initialize them. 296606bfebdeSXin LI */ 296706bfebdeSXin LI ANDMISSING(clear_all_tabs, set_tab); 296806bfebdeSXin LI 296915589c42SPeter Wemm if (PRESENT(set_attributes)) { 29704a1a9510SRong-En Fan char *zero = 0; 297115589c42SPeter Wemm 29724a1a9510SRong-En Fan _nc_tparm_err = 0; 29734a1a9510SRong-En Fan if (PRESENT(exit_attribute_mode)) { 29744a1a9510SRong-En Fan zero = strdup(CHECK_SGR(0, exit_attribute_mode)); 29754a1a9510SRong-En Fan } else { 29764a1a9510SRong-En Fan zero = strdup(TPARM_9(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0)); 29774a1a9510SRong-En Fan } 29784a1a9510SRong-En Fan if (_nc_tparm_err) 29794a1a9510SRong-En Fan _nc_warning("stack error in sgr(0) string"); 29804a1a9510SRong-En Fan 29814a1a9510SRong-En Fan if (zero != 0) { 298215589c42SPeter Wemm CHECK_SGR(1, enter_standout_mode); 298315589c42SPeter Wemm CHECK_SGR(2, enter_underline_mode); 298415589c42SPeter Wemm CHECK_SGR(3, enter_reverse_mode); 298515589c42SPeter Wemm CHECK_SGR(4, enter_blink_mode); 298615589c42SPeter Wemm CHECK_SGR(5, enter_dim_mode); 298715589c42SPeter Wemm CHECK_SGR(6, enter_bold_mode); 298815589c42SPeter Wemm CHECK_SGR(7, enter_secure_mode); 298915589c42SPeter Wemm CHECK_SGR(8, enter_protected_mode); 299015589c42SPeter Wemm CHECK_SGR(9, enter_alt_charset_mode); 299115589c42SPeter Wemm free(zero); 29924a1a9510SRong-En Fan } else { 29934a1a9510SRong-En Fan _nc_warning("sgr(0) did not return a value"); 299415589c42SPeter Wemm } 29954a1a9510SRong-En Fan } else if (PRESENT(exit_attribute_mode) && 29964a1a9510SRong-En Fan set_attributes != CANCELLED_STRING) { 29974a1a9510SRong-En Fan if (_nc_syntax == SYN_TERMINFO) 29984a1a9510SRong-En Fan _nc_warning("missing sgr string"); 29994a1a9510SRong-En Fan } 3000aae38d10SBaptiste Daroussin #define CHECK_SGR0(name) check_exit_attribute(#name, name, check_sgr0, exit_attribute_mode) 30014a1a9510SRong-En Fan if (PRESENT(exit_attribute_mode)) { 30024a1a9510SRong-En Fan char *check_sgr0 = _nc_trim_sgr0(tp); 30034a1a9510SRong-En Fan 30044a1a9510SRong-En Fan if (check_sgr0 == 0 || *check_sgr0 == '\0') { 30054a1a9510SRong-En Fan _nc_warning("trimmed sgr0 is empty"); 30064a1a9510SRong-En Fan } else { 30074a1a9510SRong-En Fan show_where(2); 30084a1a9510SRong-En Fan if (check_sgr0 != exit_attribute_mode) { 30094a1a9510SRong-En Fan DEBUG(2, 30104a1a9510SRong-En Fan ("will trim sgr0\n\toriginal sgr0=%s\n\ttrimmed sgr0=%s", 30114a1a9510SRong-En Fan _nc_visbuf2(1, exit_attribute_mode), 30124a1a9510SRong-En Fan _nc_visbuf2(2, check_sgr0))); 30134a1a9510SRong-En Fan } else { 30144a1a9510SRong-En Fan DEBUG(2, 30154a1a9510SRong-En Fan ("will not trim sgr0\n\toriginal sgr0=%s", 30164a1a9510SRong-En Fan _nc_visbuf(exit_attribute_mode))); 30174a1a9510SRong-En Fan } 30184a1a9510SRong-En Fan } 3019aae38d10SBaptiste Daroussin #if defined(exit_italics_mode) 3020aae38d10SBaptiste Daroussin CHECK_SGR0(exit_italics_mode); 3021aae38d10SBaptiste Daroussin #endif 3022aae38d10SBaptiste Daroussin CHECK_SGR0(exit_standout_mode); 3023aae38d10SBaptiste Daroussin CHECK_SGR0(exit_underline_mode); 3024aae38d10SBaptiste Daroussin if (check_sgr0 != exit_attribute_mode) { 3025aae38d10SBaptiste Daroussin free(check_sgr0); 3026aae38d10SBaptiste Daroussin } 3027aae38d10SBaptiste Daroussin } 3028aae38d10SBaptiste Daroussin #define CHECK_SGR_PARAM(code, name) check_sgr_param(tp, (int)code, #name, name) 3029aae38d10SBaptiste Daroussin for (j = 0; *sgr_names[j] != '\0'; ++j) { 3030aae38d10SBaptiste Daroussin CHECK_SGR_PARAM(j, set_a_foreground); 3031aae38d10SBaptiste Daroussin CHECK_SGR_PARAM(j, set_a_background); 3032aae38d10SBaptiste Daroussin CHECK_SGR_PARAM(j, set_foreground); 3033aae38d10SBaptiste Daroussin CHECK_SGR_PARAM(j, set_background); 30344a1a9510SRong-En Fan } 30354a1a9510SRong-En Fan #ifdef TRACE 30364a1a9510SRong-En Fan show_where(2); 30374a1a9510SRong-En Fan if (!auto_right_margin) { 30384a1a9510SRong-En Fan DEBUG(2, 30394a1a9510SRong-En Fan ("can write to lower-right directly")); 30404a1a9510SRong-En Fan } else if (PRESENT(enter_am_mode) && PRESENT(exit_am_mode)) { 30414a1a9510SRong-En Fan DEBUG(2, 30424a1a9510SRong-En Fan ("can write to lower-right by suppressing automargin")); 30434a1a9510SRong-En Fan } else if ((PRESENT(enter_insert_mode) && PRESENT(exit_insert_mode)) 30444a1a9510SRong-En Fan || PRESENT(insert_character) || PRESENT(parm_ich)) { 30454a1a9510SRong-En Fan DEBUG(2, 30464a1a9510SRong-En Fan ("can write to lower-right by using inserts")); 30474a1a9510SRong-En Fan } else { 30484a1a9510SRong-En Fan DEBUG(2, 30494a1a9510SRong-En Fan ("cannot write to lower-right")); 30504a1a9510SRong-En Fan } 30514a1a9510SRong-En Fan #endif 30520e3d5408SPeter Wemm 30530e3d5408SPeter Wemm /* 30540e3d5408SPeter Wemm * Some standard applications (e.g., vi) and some non-curses 30554a1a9510SRong-En Fan * applications (e.g., jove) get confused if we have both ich1 and 30560e3d5408SPeter Wemm * smir/rmir. Let's be nice and warn about that, too, even though 30570e3d5408SPeter Wemm * ncurses handles it. 30580e3d5408SPeter Wemm */ 30590e3d5408SPeter Wemm if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode)) 3060aae38d10SBaptiste Daroussin && PRESENT(insert_character)) { 30614a1a9510SRong-En Fan _nc_warning("non-curses applications may be confused by ich1 with smir/rmir"); 30620e3d5408SPeter Wemm } 30630e3d5408SPeter Wemm 30640e3d5408SPeter Wemm /* 30650e3d5408SPeter Wemm * Finally, do the non-verbose checks 30660e3d5408SPeter Wemm */ 30670e3d5408SPeter Wemm if (save_check_termtype != 0) 30684a1a9510SRong-En Fan save_check_termtype(tp, literal); 30690e3d5408SPeter Wemm } 3070