10e3d5408SPeter Wemm /**************************************************************************** 25ca44d1cSRong-En Fan * Copyright (c) 1998-2006,2007 Free Software Foundation, Inc. * 30e3d5408SPeter Wemm * * 40e3d5408SPeter Wemm * Permission is hereby granted, free of charge, to any person obtaining a * 50e3d5408SPeter Wemm * copy of this software and associated documentation files (the * 60e3d5408SPeter Wemm * "Software"), to deal in the Software without restriction, including * 70e3d5408SPeter Wemm * without limitation the rights to use, copy, modify, merge, publish, * 80e3d5408SPeter Wemm * distribute, distribute with modifications, sublicense, and/or sell * 90e3d5408SPeter Wemm * copies of the Software, and to permit persons to whom the Software is * 100e3d5408SPeter Wemm * furnished to do so, subject to the following conditions: * 110e3d5408SPeter Wemm * * 120e3d5408SPeter Wemm * The above copyright notice and this permission notice shall be included * 130e3d5408SPeter Wemm * in all copies or substantial portions of the Software. * 140e3d5408SPeter Wemm * * 150e3d5408SPeter Wemm * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 160e3d5408SPeter Wemm * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 170e3d5408SPeter Wemm * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 180e3d5408SPeter Wemm * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 190e3d5408SPeter Wemm * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 200e3d5408SPeter Wemm * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 210e3d5408SPeter Wemm * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 220e3d5408SPeter Wemm * * 230e3d5408SPeter Wemm * Except as contained in this notice, the name(s) of the above copyright * 240e3d5408SPeter Wemm * holders shall not be used in advertising or otherwise to promote the * 250e3d5408SPeter Wemm * sale, use or other dealings in this Software without prior written * 260e3d5408SPeter Wemm * authorization. * 270e3d5408SPeter Wemm ****************************************************************************/ 280e3d5408SPeter Wemm 290e3d5408SPeter Wemm /**************************************************************************** 300e3d5408SPeter Wemm * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 310e3d5408SPeter Wemm * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32b82face1SPeter Wemm * and: Thomas E. Dickey 1996 on * 330e3d5408SPeter Wemm ****************************************************************************/ 340e3d5408SPeter Wemm 350e3d5408SPeter Wemm /* 360e3d5408SPeter Wemm * tic.c --- Main program for terminfo compiler 370e3d5408SPeter Wemm * by Eric S. Raymond 380e3d5408SPeter Wemm * 390e3d5408SPeter Wemm */ 400e3d5408SPeter Wemm 410e3d5408SPeter Wemm #include <progs.priv.h> 4218259542SPeter Wemm #include <sys/stat.h> 430e3d5408SPeter Wemm 440e3d5408SPeter Wemm #include <dump_entry.h> 4518259542SPeter Wemm #include <transform.h> 460e3d5408SPeter Wemm 475ca44d1cSRong-En Fan MODULE_ID("$Id: tic.c,v 1.133 2007/07/21 17:45:59 tom Exp $") 480e3d5408SPeter Wemm 490e3d5408SPeter Wemm const char *_nc_progname = "tic"; 500e3d5408SPeter Wemm 510e3d5408SPeter Wemm static FILE *log_fp; 520e3d5408SPeter Wemm static FILE *tmp_fp; 534a1a9510SRong-En Fan static bool capdump = FALSE; /* running as infotocap? */ 544a1a9510SRong-En Fan static bool infodump = FALSE; /* running as captoinfo? */ 550e3d5408SPeter Wemm static bool showsummary = FALSE; 560e3d5408SPeter Wemm static const char *to_remove; 570e3d5408SPeter Wemm 584a1a9510SRong-En Fan static void (*save_check_termtype) (TERMTYPE *, bool); 594a1a9510SRong-En Fan static void check_termtype(TERMTYPE *tt, bool); 600e3d5408SPeter Wemm 614a1a9510SRong-En Fan static const char usage_string[] = "\ 624a1a9510SRong-En Fan [-e names] \ 634a1a9510SRong-En Fan [-o dir] \ 644a1a9510SRong-En Fan [-R name] \ 654a1a9510SRong-En Fan [-v[n]] \ 664a1a9510SRong-En Fan [-V] \ 674a1a9510SRong-En Fan [-w[n]] \ 684a1a9510SRong-En Fan [-\ 694a1a9510SRong-En Fan 1\ 704a1a9510SRong-En Fan a\ 714a1a9510SRong-En Fan C\ 724a1a9510SRong-En Fan c\ 734a1a9510SRong-En Fan f\ 744a1a9510SRong-En Fan G\ 754a1a9510SRong-En Fan g\ 764a1a9510SRong-En Fan I\ 774a1a9510SRong-En Fan L\ 784a1a9510SRong-En Fan N\ 794a1a9510SRong-En Fan r\ 804a1a9510SRong-En Fan s\ 814a1a9510SRong-En Fan T\ 824a1a9510SRong-En Fan t\ 834a1a9510SRong-En Fan U\ 844a1a9510SRong-En Fan x\ 854a1a9510SRong-En Fan ] \ 864a1a9510SRong-En Fan source-file\n"; 870e3d5408SPeter Wemm 8815589c42SPeter Wemm static void 8915589c42SPeter Wemm cleanup(void) 900e3d5408SPeter Wemm { 910e3d5408SPeter Wemm if (tmp_fp != 0) 920e3d5408SPeter Wemm fclose(tmp_fp); 930e3d5408SPeter Wemm if (to_remove != 0) { 940e3d5408SPeter Wemm #if HAVE_REMOVE 950e3d5408SPeter Wemm remove(to_remove); 960e3d5408SPeter Wemm #else 970e3d5408SPeter Wemm unlink(to_remove); 980e3d5408SPeter Wemm #endif 990e3d5408SPeter Wemm } 1000e3d5408SPeter Wemm } 1010e3d5408SPeter Wemm 10215589c42SPeter Wemm static void 10315589c42SPeter Wemm failed(const char *msg) 1040e3d5408SPeter Wemm { 1050e3d5408SPeter Wemm perror(msg); 1060e3d5408SPeter Wemm cleanup(); 1074a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 1080e3d5408SPeter Wemm } 1090e3d5408SPeter Wemm 11015589c42SPeter Wemm static void 11115589c42SPeter Wemm usage(void) 1120e3d5408SPeter Wemm { 11315589c42SPeter Wemm static const char *const tbl[] = 11415589c42SPeter Wemm { 1150e3d5408SPeter Wemm "Options:", 1160e3d5408SPeter Wemm " -1 format translation output one capability per line", 11715589c42SPeter Wemm #if NCURSES_XNAMES 11815589c42SPeter Wemm " -a retain commented-out capabilities (sets -x also)", 11915589c42SPeter Wemm #endif 1204a1a9510SRong-En Fan " -C translate entries to termcap source form", 1210e3d5408SPeter Wemm " -c check only, validate input without compiling or translating", 1224a1a9510SRong-En Fan " -e<names> translate/compile only entries named by comma-separated list", 1230e3d5408SPeter Wemm " -f format complex strings for readability", 1240e3d5408SPeter Wemm " -G format %{number} to %'char'", 1250e3d5408SPeter Wemm " -g format %'char' to %{number}", 1264a1a9510SRong-En Fan " -I translate entries to terminfo source form", 1274a1a9510SRong-En Fan " -L translate entries to full terminfo source form", 1284a1a9510SRong-En Fan " -N disable smart defaults for source translation", 1290e3d5408SPeter Wemm " -o<dir> set output directory for compiled entry writes", 1304a1a9510SRong-En Fan " -R<name> restrict translation to given terminfo/termcap version", 1310e3d5408SPeter Wemm " -r force resolution of all use entries in source translation", 1320e3d5408SPeter Wemm " -s print summary statistics", 1334a1a9510SRong-En Fan " -T remove size-restrictions on compiled description", 1344a1a9510SRong-En Fan #if NCURSES_XNAMES 1354a1a9510SRong-En Fan " -t suppress commented-out capabilities", 1364a1a9510SRong-En Fan #endif 1374a1a9510SRong-En Fan " -U suppress post-processing of entries", 1384a1a9510SRong-En Fan " -V print version", 1390e3d5408SPeter Wemm " -v[n] set verbosity level", 1400e3d5408SPeter Wemm " -w[n] set format width for translation output", 1410e3d5408SPeter Wemm #if NCURSES_XNAMES 1420e3d5408SPeter Wemm " -x treat unknown capabilities as user-defined", 1430e3d5408SPeter Wemm #endif 1440e3d5408SPeter Wemm "", 1450e3d5408SPeter Wemm "Parameters:", 1460e3d5408SPeter Wemm " <file> file to translate or compile" 1470e3d5408SPeter Wemm }; 1480e3d5408SPeter Wemm size_t j; 1490e3d5408SPeter Wemm 15015589c42SPeter Wemm fprintf(stderr, "Usage: %s %s\n", _nc_progname, usage_string); 15118259542SPeter Wemm for (j = 0; j < SIZEOF(tbl); j++) { 15215589c42SPeter Wemm fputs(tbl[j], stderr); 15315589c42SPeter Wemm putc('\n', stderr); 15415589c42SPeter Wemm } 1554a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 1560e3d5408SPeter Wemm } 1570e3d5408SPeter Wemm 1580e3d5408SPeter Wemm #define L_BRACE '{' 1590e3d5408SPeter Wemm #define R_BRACE '}' 1600e3d5408SPeter Wemm #define S_QUOTE '\''; 1610e3d5408SPeter Wemm 16215589c42SPeter Wemm static void 16315589c42SPeter Wemm write_it(ENTRY * ep) 1640e3d5408SPeter Wemm { 1650e3d5408SPeter Wemm unsigned n; 1660e3d5408SPeter Wemm int ch; 1670e3d5408SPeter Wemm char *s, *d, *t; 1680e3d5408SPeter Wemm char result[MAX_ENTRY_SIZE]; 1690e3d5408SPeter Wemm 1700e3d5408SPeter Wemm /* 1710e3d5408SPeter Wemm * Look for strings that contain %{number}, convert them to %'char', 1720e3d5408SPeter Wemm * which is shorter and runs a little faster. 1730e3d5408SPeter Wemm */ 1740e3d5408SPeter Wemm for (n = 0; n < STRCOUNT; n++) { 1750e3d5408SPeter Wemm s = ep->tterm.Strings[n]; 1760e3d5408SPeter Wemm if (VALID_STRING(s) 1770e3d5408SPeter Wemm && strchr(s, L_BRACE) != 0) { 1780e3d5408SPeter Wemm d = result; 1790e3d5408SPeter Wemm t = s; 1800e3d5408SPeter Wemm while ((ch = *t++) != 0) { 1810e3d5408SPeter Wemm *d++ = ch; 1820e3d5408SPeter Wemm if (ch == '\\') { 1830e3d5408SPeter Wemm *d++ = *t++; 1840e3d5408SPeter Wemm } else if ((ch == '%') 1850e3d5408SPeter Wemm && (*t == L_BRACE)) { 1860e3d5408SPeter Wemm char *v = 0; 1870e3d5408SPeter Wemm long value = strtol(t + 1, &v, 0); 1880e3d5408SPeter Wemm if (v != 0 1890e3d5408SPeter Wemm && *v == R_BRACE 1900e3d5408SPeter Wemm && value > 0 1910e3d5408SPeter Wemm && value != '\\' /* FIXME */ 1920e3d5408SPeter Wemm && value < 127 1930e3d5408SPeter Wemm && isprint((int) value)) { 1940e3d5408SPeter Wemm *d++ = S_QUOTE; 1950e3d5408SPeter Wemm *d++ = (int) value; 1960e3d5408SPeter Wemm *d++ = S_QUOTE; 1970e3d5408SPeter Wemm t = (v + 1); 1980e3d5408SPeter Wemm } 1990e3d5408SPeter Wemm } 2000e3d5408SPeter Wemm } 2010e3d5408SPeter Wemm *d = 0; 2020e3d5408SPeter Wemm if (strlen(result) < strlen(s)) 2030e3d5408SPeter Wemm strcpy(s, result); 2040e3d5408SPeter Wemm } 2050e3d5408SPeter Wemm } 2060e3d5408SPeter Wemm 2070e3d5408SPeter Wemm _nc_set_type(_nc_first_name(ep->tterm.term_names)); 2080e3d5408SPeter Wemm _nc_curr_line = ep->startline; 2090e3d5408SPeter Wemm _nc_write_entry(&ep->tterm); 2100e3d5408SPeter Wemm } 2110e3d5408SPeter Wemm 21215589c42SPeter Wemm static bool 21315589c42SPeter Wemm immedhook(ENTRY * ep GCC_UNUSED) 2140e3d5408SPeter Wemm /* write out entries with no use capabilities immediately to save storage */ 2150e3d5408SPeter Wemm { 21618259542SPeter Wemm #if !HAVE_BIG_CORE 2170e3d5408SPeter Wemm /* 2180e3d5408SPeter Wemm * This is strictly a core-economy kluge. The really clean way to handle 2190e3d5408SPeter Wemm * compilation is to slurp the whole file into core and then do all the 2200e3d5408SPeter Wemm * name-collision checks and entry writes in one swell foop. But the 2210e3d5408SPeter Wemm * terminfo master file is large enough that some core-poor systems swap 2220e3d5408SPeter Wemm * like crazy when you compile it this way...there have been reports of 2230e3d5408SPeter Wemm * this process taking *three hours*, rather than the twenty seconds or 2240e3d5408SPeter Wemm * less typical on my development box. 2250e3d5408SPeter Wemm * 2260e3d5408SPeter Wemm * So. This hook *immediately* writes out the referenced entry if it 2270e3d5408SPeter Wemm * has no use capabilities. The compiler main loop refrains from 2280e3d5408SPeter Wemm * adding the entry to the in-core list when this hook fires. If some 2290e3d5408SPeter Wemm * other entry later needs to reference an entry that got written 2300e3d5408SPeter Wemm * immediately, that's OK; the resolution code will fetch it off disk 2310e3d5408SPeter Wemm * when it can't find it in core. 2320e3d5408SPeter Wemm * 2330e3d5408SPeter Wemm * Name collisions will still be detected, just not as cleanly. The 2340e3d5408SPeter Wemm * write_entry() code complains before overwriting an entry that 2350e3d5408SPeter Wemm * postdates the time of tic's first call to write_entry(). Thus 2360e3d5408SPeter Wemm * it will complain about overwriting entries newly made during the 2370e3d5408SPeter Wemm * tic run, but not about overwriting ones that predate it. 2380e3d5408SPeter Wemm * 2390e3d5408SPeter Wemm * The reason this is a hook, and not in line with the rest of the 2400e3d5408SPeter Wemm * compiler code, is that the support for termcap fallback cannot assume 2410e3d5408SPeter Wemm * it has anywhere to spool out these entries! 2420e3d5408SPeter Wemm * 2430e3d5408SPeter Wemm * The _nc_set_type() call here requires a compensating one in 2440e3d5408SPeter Wemm * _nc_parse_entry(). 2450e3d5408SPeter Wemm * 2460e3d5408SPeter Wemm * If you define HAVE_BIG_CORE, you'll disable this kluge. This will 2470e3d5408SPeter Wemm * make tic a bit faster (because the resolution code won't have to do 2480e3d5408SPeter Wemm * disk I/O nearly as often). 2490e3d5408SPeter Wemm */ 25015589c42SPeter Wemm if (ep->nuses == 0) { 2510e3d5408SPeter Wemm int oldline = _nc_curr_line; 2520e3d5408SPeter Wemm 2530e3d5408SPeter Wemm write_it(ep); 2540e3d5408SPeter Wemm _nc_curr_line = oldline; 2550e3d5408SPeter Wemm free(ep->tterm.str_table); 2560e3d5408SPeter Wemm return (TRUE); 2570e3d5408SPeter Wemm } 2580e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */ 2590e3d5408SPeter Wemm return (FALSE); 2600e3d5408SPeter Wemm } 2610e3d5408SPeter Wemm 26215589c42SPeter Wemm static void 26315589c42SPeter Wemm put_translate(int c) 2640e3d5408SPeter Wemm /* emit a comment char, translating terminfo names to termcap names */ 2650e3d5408SPeter Wemm { 2660e3d5408SPeter Wemm static bool in_name = FALSE; 26715589c42SPeter Wemm static size_t have, used; 26815589c42SPeter Wemm static char *namebuf, *suffix; 2690e3d5408SPeter Wemm 27015589c42SPeter Wemm if (in_name) { 27115589c42SPeter Wemm if (used + 1 >= have) { 27215589c42SPeter Wemm have += 132; 27315589c42SPeter Wemm namebuf = typeRealloc(char, have, namebuf); 27415589c42SPeter Wemm suffix = typeRealloc(char, have, suffix); 2750e3d5408SPeter Wemm } 27615589c42SPeter Wemm if (c == '\n' || c == '@') { 27715589c42SPeter Wemm namebuf[used++] = '\0'; 2780e3d5408SPeter Wemm (void) putchar('<'); 2790e3d5408SPeter Wemm (void) fputs(namebuf, stdout); 2800e3d5408SPeter Wemm putchar(c); 2810e3d5408SPeter Wemm in_name = FALSE; 28215589c42SPeter Wemm } else if (c != '>') { 28315589c42SPeter Wemm namebuf[used++] = c; 28415589c42SPeter Wemm } else { /* ah! candidate name! */ 2850e3d5408SPeter Wemm char *up; 2860e3d5408SPeter Wemm NCURSES_CONST char *tp; 2870e3d5408SPeter Wemm 28815589c42SPeter Wemm namebuf[used++] = '\0'; 2890e3d5408SPeter Wemm in_name = FALSE; 2900e3d5408SPeter Wemm 2910e3d5408SPeter Wemm suffix[0] = '\0'; 2920e3d5408SPeter Wemm if ((up = strchr(namebuf, '#')) != 0 2930e3d5408SPeter Wemm || (up = strchr(namebuf, '=')) != 0 29415589c42SPeter Wemm || ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) { 2950e3d5408SPeter Wemm (void) strcpy(suffix, up); 2960e3d5408SPeter Wemm *up = '\0'; 2970e3d5408SPeter Wemm } 2980e3d5408SPeter Wemm 29915589c42SPeter Wemm if ((tp = nametrans(namebuf)) != 0) { 3000e3d5408SPeter Wemm (void) putchar(':'); 3010e3d5408SPeter Wemm (void) fputs(tp, stdout); 3020e3d5408SPeter Wemm (void) fputs(suffix, stdout); 3030e3d5408SPeter Wemm (void) putchar(':'); 30415589c42SPeter Wemm } else { 3050e3d5408SPeter Wemm /* couldn't find a translation, just dump the name */ 3060e3d5408SPeter Wemm (void) putchar('<'); 3070e3d5408SPeter Wemm (void) fputs(namebuf, stdout); 3080e3d5408SPeter Wemm (void) fputs(suffix, stdout); 3090e3d5408SPeter Wemm (void) putchar('>'); 3100e3d5408SPeter Wemm } 31115589c42SPeter Wemm } 31215589c42SPeter Wemm } else { 31315589c42SPeter Wemm used = 0; 31415589c42SPeter Wemm if (c == '<') { 31515589c42SPeter Wemm in_name = TRUE; 31615589c42SPeter Wemm } else { 31715589c42SPeter Wemm putchar(c); 31815589c42SPeter Wemm } 3190e3d5408SPeter Wemm } 3200e3d5408SPeter Wemm } 3210e3d5408SPeter Wemm 3220e3d5408SPeter Wemm /* Returns a string, stripped of leading/trailing whitespace */ 32315589c42SPeter Wemm static char * 32415589c42SPeter Wemm stripped(char *src) 3250e3d5408SPeter Wemm { 32639f2269fSPeter Wemm while (isspace(UChar(*src))) 3270e3d5408SPeter Wemm src++; 3280e3d5408SPeter Wemm if (*src != '\0') { 3294a1a9510SRong-En Fan char *dst = strcpy((char *) malloc(strlen(src) + 1), src); 3300e3d5408SPeter Wemm size_t len = strlen(dst); 33139f2269fSPeter Wemm while (--len != 0 && isspace(UChar(dst[len]))) 3320e3d5408SPeter Wemm dst[len] = '\0'; 3330e3d5408SPeter Wemm return dst; 3340e3d5408SPeter Wemm } 3350e3d5408SPeter Wemm return 0; 3360e3d5408SPeter Wemm } 3370e3d5408SPeter Wemm 33818259542SPeter Wemm static FILE * 33918259542SPeter Wemm open_input(const char *filename) 34018259542SPeter Wemm { 34118259542SPeter Wemm FILE *fp = fopen(filename, "r"); 34218259542SPeter Wemm struct stat sb; 34318259542SPeter Wemm 34418259542SPeter Wemm if (fp == 0) { 34518259542SPeter Wemm fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename); 3464a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 34718259542SPeter Wemm } 34818259542SPeter Wemm if (fstat(fileno(fp), &sb) < 0 34918259542SPeter Wemm || (sb.st_mode & S_IFMT) != S_IFREG) { 35018259542SPeter Wemm fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename); 3514a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 35218259542SPeter Wemm } 35318259542SPeter Wemm return fp; 35418259542SPeter Wemm } 35518259542SPeter Wemm 3565ca44d1cSRong-En Fan #if NO_LEAKS 3575ca44d1cSRong-En Fan static void 3585ca44d1cSRong-En Fan free_namelist(char **src) 3595ca44d1cSRong-En Fan { 3605ca44d1cSRong-En Fan if (src != 0) { 3615ca44d1cSRong-En Fan int n; 3625ca44d1cSRong-En Fan for (n = 0; src[n] != 0; ++n) 3635ca44d1cSRong-En Fan free(src[n]); 3645ca44d1cSRong-En Fan free(src); 3655ca44d1cSRong-En Fan } 3665ca44d1cSRong-En Fan } 3675ca44d1cSRong-En Fan #endif 3685ca44d1cSRong-En Fan 3690e3d5408SPeter Wemm /* Parse the "-e" option-value into a list of names */ 3705ca44d1cSRong-En Fan static char ** 37115589c42SPeter Wemm make_namelist(char *src) 3720e3d5408SPeter Wemm { 3735ca44d1cSRong-En Fan char **dst = 0; 3740e3d5408SPeter Wemm 3750e3d5408SPeter Wemm char *s, *base; 3760e3d5408SPeter Wemm unsigned pass, n, nn; 3770e3d5408SPeter Wemm char buffer[BUFSIZ]; 3780e3d5408SPeter Wemm 3790e3d5408SPeter Wemm if (src == 0) { 3800e3d5408SPeter Wemm /* EMPTY */ ; 3810e3d5408SPeter Wemm } else if (strchr(src, '/') != 0) { /* a filename */ 38218259542SPeter Wemm FILE *fp = open_input(src); 3830e3d5408SPeter Wemm 3840e3d5408SPeter Wemm for (pass = 1; pass <= 2; pass++) { 3850e3d5408SPeter Wemm nn = 0; 3860e3d5408SPeter Wemm while (fgets(buffer, sizeof(buffer), fp) != 0) { 3870e3d5408SPeter Wemm if ((s = stripped(buffer)) != 0) { 3880e3d5408SPeter Wemm if (dst != 0) 3890e3d5408SPeter Wemm dst[nn] = s; 3905ca44d1cSRong-En Fan else 3915ca44d1cSRong-En Fan free(s); 3920e3d5408SPeter Wemm nn++; 3930e3d5408SPeter Wemm } 3940e3d5408SPeter Wemm } 3950e3d5408SPeter Wemm if (pass == 1) { 3965ca44d1cSRong-En Fan dst = typeCalloc(char *, nn + 1); 3970e3d5408SPeter Wemm rewind(fp); 3980e3d5408SPeter Wemm } 3990e3d5408SPeter Wemm } 4000e3d5408SPeter Wemm fclose(fp); 4010e3d5408SPeter Wemm } else { /* literal list of names */ 4020e3d5408SPeter Wemm for (pass = 1; pass <= 2; pass++) { 4030e3d5408SPeter Wemm for (n = nn = 0, base = src;; n++) { 4040e3d5408SPeter Wemm int mark = src[n]; 4050e3d5408SPeter Wemm if (mark == ',' || mark == '\0') { 4060e3d5408SPeter Wemm if (pass == 1) { 4070e3d5408SPeter Wemm nn++; 4080e3d5408SPeter Wemm } else { 4090e3d5408SPeter Wemm src[n] = '\0'; 4100e3d5408SPeter Wemm if ((s = stripped(base)) != 0) 4110e3d5408SPeter Wemm dst[nn++] = s; 4120e3d5408SPeter Wemm base = &src[n + 1]; 4130e3d5408SPeter Wemm } 4140e3d5408SPeter Wemm } 4150e3d5408SPeter Wemm if (mark == '\0') 4160e3d5408SPeter Wemm break; 4170e3d5408SPeter Wemm } 4180e3d5408SPeter Wemm if (pass == 1) 4195ca44d1cSRong-En Fan dst = typeCalloc(char *, nn + 1); 4200e3d5408SPeter Wemm } 4210e3d5408SPeter Wemm } 4225ca44d1cSRong-En Fan if (showsummary && (dst != 0)) { 4230e3d5408SPeter Wemm fprintf(log_fp, "Entries that will be compiled:\n"); 4240e3d5408SPeter Wemm for (n = 0; dst[n] != 0; n++) 4254a1a9510SRong-En Fan fprintf(log_fp, "%u:%s\n", n + 1, dst[n]); 4260e3d5408SPeter Wemm } 4270e3d5408SPeter Wemm return dst; 4280e3d5408SPeter Wemm } 4290e3d5408SPeter Wemm 43015589c42SPeter Wemm static bool 4315ca44d1cSRong-En Fan matches(char **needle, const char *haystack) 4320e3d5408SPeter Wemm /* does entry in needle list match |-separated field in haystack? */ 4330e3d5408SPeter Wemm { 4340e3d5408SPeter Wemm bool code = FALSE; 4350e3d5408SPeter Wemm size_t n; 4360e3d5408SPeter Wemm 43715589c42SPeter Wemm if (needle != 0) { 43815589c42SPeter Wemm for (n = 0; needle[n] != 0; n++) { 43915589c42SPeter Wemm if (_nc_name_match(haystack, needle[n], "|")) { 4400e3d5408SPeter Wemm code = TRUE; 4410e3d5408SPeter Wemm break; 4420e3d5408SPeter Wemm } 4430e3d5408SPeter Wemm } 44415589c42SPeter Wemm } else 4450e3d5408SPeter Wemm code = TRUE; 4460e3d5408SPeter Wemm return (code); 4470e3d5408SPeter Wemm } 4480e3d5408SPeter Wemm 44915589c42SPeter Wemm static FILE * 45015589c42SPeter Wemm open_tempfile(char *name) 45115589c42SPeter Wemm { 45215589c42SPeter Wemm FILE *result = 0; 45315589c42SPeter Wemm #if HAVE_MKSTEMP 45415589c42SPeter Wemm int fd = mkstemp(name); 45515589c42SPeter Wemm if (fd >= 0) 45615589c42SPeter Wemm result = fdopen(fd, "w"); 45715589c42SPeter Wemm #else 45815589c42SPeter Wemm if (tmpnam(name) != 0) 45915589c42SPeter Wemm result = fopen(name, "w"); 46015589c42SPeter Wemm #endif 46115589c42SPeter Wemm return result; 46215589c42SPeter Wemm } 46315589c42SPeter Wemm 46415589c42SPeter Wemm int 46515589c42SPeter Wemm main(int argc, char *argv[]) 4660e3d5408SPeter Wemm { 4670e3d5408SPeter Wemm char my_tmpname[PATH_MAX]; 4680e3d5408SPeter Wemm int v_opt = -1, debug_level; 4690e3d5408SPeter Wemm int smart_defaults = TRUE; 4700e3d5408SPeter Wemm char *termcap; 4710e3d5408SPeter Wemm ENTRY *qp; 4720e3d5408SPeter Wemm 4730e3d5408SPeter Wemm int this_opt, last_opt = '?'; 4740e3d5408SPeter Wemm 4750e3d5408SPeter Wemm int outform = F_TERMINFO; /* output format */ 4760e3d5408SPeter Wemm int sortmode = S_TERMINFO; /* sort_mode */ 4770e3d5408SPeter Wemm 4780e3d5408SPeter Wemm int width = 60; 4790e3d5408SPeter Wemm bool formatted = FALSE; /* reformat complex strings? */ 4804a1a9510SRong-En Fan bool literal = FALSE; /* suppress post-processing? */ 4810e3d5408SPeter Wemm int numbers = 0; /* format "%'char'" to/from "%{number}" */ 4820e3d5408SPeter Wemm bool forceresolve = FALSE; /* force resolution */ 4830e3d5408SPeter Wemm bool limited = TRUE; 4840e3d5408SPeter Wemm char *tversion = (char *) NULL; 4850e3d5408SPeter Wemm const char *source_file = "terminfo"; 4865ca44d1cSRong-En Fan char **namelst = 0; 4870e3d5408SPeter Wemm char *outdir = (char *) NULL; 4880e3d5408SPeter Wemm bool check_only = FALSE; 4894a1a9510SRong-En Fan bool suppress_untranslatable = FALSE; 4900e3d5408SPeter Wemm 4910e3d5408SPeter Wemm log_fp = stderr; 4920e3d5408SPeter Wemm 49339f2269fSPeter Wemm _nc_progname = _nc_rootname(argv[0]); 4940e3d5408SPeter Wemm 49518259542SPeter Wemm if ((infodump = (strcmp(_nc_progname, PROG_CAPTOINFO) == 0)) != FALSE) { 49615589c42SPeter Wemm outform = F_TERMINFO; 49715589c42SPeter Wemm sortmode = S_TERMINFO; 49815589c42SPeter Wemm } 49918259542SPeter Wemm if ((capdump = (strcmp(_nc_progname, PROG_INFOTOCAP) == 0)) != FALSE) { 50015589c42SPeter Wemm outform = F_TERMCAP; 50115589c42SPeter Wemm sortmode = S_TERMCAP; 50215589c42SPeter Wemm } 5030e3d5408SPeter Wemm #if NCURSES_XNAMES 5040e3d5408SPeter Wemm use_extended_names(FALSE); 5050e3d5408SPeter Wemm #endif 5060e3d5408SPeter Wemm 5070e3d5408SPeter Wemm /* 5080e3d5408SPeter Wemm * Processing arguments is a little complicated, since someone made a 5090e3d5408SPeter Wemm * design decision to allow the numeric values for -w, -v options to 5100e3d5408SPeter Wemm * be optional. 5110e3d5408SPeter Wemm */ 51215589c42SPeter Wemm while ((this_opt = getopt(argc, argv, 5135ca44d1cSRong-En Fan "0123456789CILNR:TUVace:fGgo:rstvwx")) != -1) { 5140e3d5408SPeter Wemm if (isdigit(this_opt)) { 5150e3d5408SPeter Wemm switch (last_opt) { 5160e3d5408SPeter Wemm case 'v': 5170e3d5408SPeter Wemm v_opt = (v_opt * 10) + (this_opt - '0'); 5180e3d5408SPeter Wemm break; 5190e3d5408SPeter Wemm case 'w': 5200e3d5408SPeter Wemm width = (width * 10) + (this_opt - '0'); 5210e3d5408SPeter Wemm break; 5220e3d5408SPeter Wemm default: 5230e3d5408SPeter Wemm if (this_opt != '1') 5240e3d5408SPeter Wemm usage(); 5250e3d5408SPeter Wemm last_opt = this_opt; 5260e3d5408SPeter Wemm width = 0; 5270e3d5408SPeter Wemm } 5280e3d5408SPeter Wemm continue; 5290e3d5408SPeter Wemm } 5300e3d5408SPeter Wemm switch (this_opt) { 5310e3d5408SPeter Wemm case 'C': 5320e3d5408SPeter Wemm capdump = TRUE; 5330e3d5408SPeter Wemm outform = F_TERMCAP; 5340e3d5408SPeter Wemm sortmode = S_TERMCAP; 5350e3d5408SPeter Wemm break; 5360e3d5408SPeter Wemm case 'I': 5370e3d5408SPeter Wemm infodump = TRUE; 5380e3d5408SPeter Wemm outform = F_TERMINFO; 5390e3d5408SPeter Wemm sortmode = S_TERMINFO; 5400e3d5408SPeter Wemm break; 5410e3d5408SPeter Wemm case 'L': 5420e3d5408SPeter Wemm infodump = TRUE; 5430e3d5408SPeter Wemm outform = F_VARIABLE; 5440e3d5408SPeter Wemm sortmode = S_VARIABLE; 5450e3d5408SPeter Wemm break; 5460e3d5408SPeter Wemm case 'N': 5470e3d5408SPeter Wemm smart_defaults = FALSE; 5484a1a9510SRong-En Fan literal = TRUE; 5490e3d5408SPeter Wemm break; 5500e3d5408SPeter Wemm case 'R': 5510e3d5408SPeter Wemm tversion = optarg; 5520e3d5408SPeter Wemm break; 5530e3d5408SPeter Wemm case 'T': 5540e3d5408SPeter Wemm limited = FALSE; 5550e3d5408SPeter Wemm break; 5564a1a9510SRong-En Fan case 'U': 5574a1a9510SRong-En Fan literal = TRUE; 5584a1a9510SRong-En Fan break; 5590e3d5408SPeter Wemm case 'V': 56018259542SPeter Wemm puts(curses_version()); 5610e3d5408SPeter Wemm return EXIT_SUCCESS; 5620e3d5408SPeter Wemm case 'c': 5630e3d5408SPeter Wemm check_only = TRUE; 5640e3d5408SPeter Wemm break; 5650e3d5408SPeter Wemm case 'e': 5660e3d5408SPeter Wemm namelst = make_namelist(optarg); 5670e3d5408SPeter Wemm break; 5680e3d5408SPeter Wemm case 'f': 5690e3d5408SPeter Wemm formatted = TRUE; 5700e3d5408SPeter Wemm break; 5710e3d5408SPeter Wemm case 'G': 5720e3d5408SPeter Wemm numbers = 1; 5730e3d5408SPeter Wemm break; 5740e3d5408SPeter Wemm case 'g': 5750e3d5408SPeter Wemm numbers = -1; 5760e3d5408SPeter Wemm break; 5770e3d5408SPeter Wemm case 'o': 5780e3d5408SPeter Wemm outdir = optarg; 5790e3d5408SPeter Wemm break; 5800e3d5408SPeter Wemm case 'r': 5810e3d5408SPeter Wemm forceresolve = TRUE; 5820e3d5408SPeter Wemm break; 5830e3d5408SPeter Wemm case 's': 5840e3d5408SPeter Wemm showsummary = TRUE; 5850e3d5408SPeter Wemm break; 5860e3d5408SPeter Wemm case 'v': 5870e3d5408SPeter Wemm v_opt = 0; 5880e3d5408SPeter Wemm break; 5890e3d5408SPeter Wemm case 'w': 5900e3d5408SPeter Wemm width = 0; 5910e3d5408SPeter Wemm break; 5920e3d5408SPeter Wemm #if NCURSES_XNAMES 5934a1a9510SRong-En Fan case 't': 5944a1a9510SRong-En Fan _nc_disable_period = FALSE; 5954a1a9510SRong-En Fan suppress_untranslatable = TRUE; 5964a1a9510SRong-En Fan break; 59715589c42SPeter Wemm case 'a': 59815589c42SPeter Wemm _nc_disable_period = TRUE; 59915589c42SPeter Wemm /* FALLTHRU */ 6000e3d5408SPeter Wemm case 'x': 6010e3d5408SPeter Wemm use_extended_names(TRUE); 6020e3d5408SPeter Wemm break; 6030e3d5408SPeter Wemm #endif 6040e3d5408SPeter Wemm default: 6050e3d5408SPeter Wemm usage(); 6060e3d5408SPeter Wemm } 6070e3d5408SPeter Wemm last_opt = this_opt; 6080e3d5408SPeter Wemm } 6090e3d5408SPeter Wemm 6100e3d5408SPeter Wemm debug_level = (v_opt > 0) ? v_opt : (v_opt == 0); 61115589c42SPeter Wemm set_trace_level(debug_level); 6120e3d5408SPeter Wemm 61315589c42SPeter Wemm if (_nc_tracing) { 6144a1a9510SRong-En Fan save_check_termtype = _nc_check_termtype2; 6154a1a9510SRong-En Fan _nc_check_termtype2 = check_termtype; 6160e3d5408SPeter Wemm } 61718259542SPeter Wemm #if !HAVE_BIG_CORE 6180e3d5408SPeter Wemm /* 6190e3d5408SPeter Wemm * Aaargh! immedhook seriously hoses us! 6200e3d5408SPeter Wemm * 6210e3d5408SPeter Wemm * One problem with immedhook is it means we can't do -e. Problem 6220e3d5408SPeter Wemm * is that we can't guarantee that for each terminal listed, all the 6230e3d5408SPeter Wemm * terminals it depends on will have been kept in core for reference 6240e3d5408SPeter Wemm * resolution -- in fact it's certain the primitive types at the end 6250e3d5408SPeter Wemm * of reference chains *won't* be in core unless they were explicitly 6260e3d5408SPeter Wemm * in the select list themselves. 6270e3d5408SPeter Wemm */ 62815589c42SPeter Wemm if (namelst && (!infodump && !capdump)) { 6290e3d5408SPeter Wemm (void) fprintf(stderr, 6300e3d5408SPeter Wemm "Sorry, -e can't be used without -I or -C\n"); 6310e3d5408SPeter Wemm cleanup(); 6324a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 6330e3d5408SPeter Wemm } 6340e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */ 6350e3d5408SPeter Wemm 6360e3d5408SPeter Wemm if (optind < argc) { 6370e3d5408SPeter Wemm source_file = argv[optind++]; 6380e3d5408SPeter Wemm if (optind < argc) { 6390e3d5408SPeter Wemm fprintf(stderr, 6400e3d5408SPeter Wemm "%s: Too many file names. Usage:\n\t%s %s", 6410e3d5408SPeter Wemm _nc_progname, 6420e3d5408SPeter Wemm _nc_progname, 6430e3d5408SPeter Wemm usage_string); 6444a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 6450e3d5408SPeter Wemm } 6460e3d5408SPeter Wemm } else { 6470e3d5408SPeter Wemm if (infodump == TRUE) { 6480e3d5408SPeter Wemm /* captoinfo's no-argument case */ 6490e3d5408SPeter Wemm source_file = "/etc/termcap"; 6500e3d5408SPeter Wemm if ((termcap = getenv("TERMCAP")) != 0 6510e3d5408SPeter Wemm && (namelst = make_namelist(getenv("TERM"))) != 0) { 6520e3d5408SPeter Wemm if (access(termcap, F_OK) == 0) { 6530e3d5408SPeter Wemm /* file exists */ 6540e3d5408SPeter Wemm source_file = termcap; 65518259542SPeter Wemm } else if ((tmp_fp = open_tempfile(strcpy(my_tmpname, 65618259542SPeter Wemm "/tmp/XXXXXX"))) 65718259542SPeter Wemm != 0) { 65815589c42SPeter Wemm source_file = my_tmpname; 6590e3d5408SPeter Wemm fprintf(tmp_fp, "%s\n", termcap); 6600e3d5408SPeter Wemm fclose(tmp_fp); 66118259542SPeter Wemm tmp_fp = open_input(source_file); 6620e3d5408SPeter Wemm to_remove = source_file; 6630e3d5408SPeter Wemm } else { 6640e3d5408SPeter Wemm failed("tmpnam"); 6650e3d5408SPeter Wemm } 6660e3d5408SPeter Wemm } 6670e3d5408SPeter Wemm } else { 6680e3d5408SPeter Wemm /* tic */ 6690e3d5408SPeter Wemm fprintf(stderr, 6700e3d5408SPeter Wemm "%s: File name needed. Usage:\n\t%s %s", 6710e3d5408SPeter Wemm _nc_progname, 6720e3d5408SPeter Wemm _nc_progname, 6730e3d5408SPeter Wemm usage_string); 6740e3d5408SPeter Wemm cleanup(); 6754a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 6760e3d5408SPeter Wemm } 6770e3d5408SPeter Wemm } 6780e3d5408SPeter Wemm 67918259542SPeter Wemm if (tmp_fp == 0) 68018259542SPeter Wemm tmp_fp = open_input(source_file); 6810e3d5408SPeter Wemm 6820e3d5408SPeter Wemm if (infodump) 6830e3d5408SPeter Wemm dump_init(tversion, 6840e3d5408SPeter Wemm smart_defaults 6850e3d5408SPeter Wemm ? outform 6860e3d5408SPeter Wemm : F_LITERAL, 6870e3d5408SPeter Wemm sortmode, width, debug_level, formatted); 6880e3d5408SPeter Wemm else if (capdump) 6890e3d5408SPeter Wemm dump_init(tversion, 6900e3d5408SPeter Wemm outform, 6910e3d5408SPeter Wemm sortmode, width, debug_level, FALSE); 6920e3d5408SPeter Wemm 6930e3d5408SPeter Wemm /* parse entries out of the source file */ 6940e3d5408SPeter Wemm _nc_set_source(source_file); 69518259542SPeter Wemm #if !HAVE_BIG_CORE 6960e3d5408SPeter Wemm if (!(check_only || infodump || capdump)) 6970e3d5408SPeter Wemm _nc_set_writedir(outdir); 6980e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */ 6990e3d5408SPeter Wemm _nc_read_entry_source(tmp_fp, (char *) NULL, 7004a1a9510SRong-En Fan !smart_defaults || literal, FALSE, 7014a1a9510SRong-En Fan ((check_only || infodump || capdump) 7024a1a9510SRong-En Fan ? NULLHOOK 7034a1a9510SRong-En Fan : immedhook)); 7040e3d5408SPeter Wemm 7050e3d5408SPeter Wemm /* do use resolution */ 7060e3d5408SPeter Wemm if (check_only || (!infodump && !capdump) || forceresolve) { 7074a1a9510SRong-En Fan if (!_nc_resolve_uses2(TRUE, literal) && !check_only) { 7080e3d5408SPeter Wemm cleanup(); 7094a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE); 7100e3d5408SPeter Wemm } 7110e3d5408SPeter Wemm } 7120e3d5408SPeter Wemm 7130e3d5408SPeter Wemm /* length check */ 71415589c42SPeter Wemm if (check_only && (capdump || infodump)) { 71515589c42SPeter Wemm for_entry_list(qp) { 71615589c42SPeter Wemm if (matches(namelst, qp->tterm.term_names)) { 7174a1a9510SRong-En Fan int len = fmt_entry(&qp->tterm, NULL, FALSE, TRUE, infodump, numbers); 7180e3d5408SPeter Wemm 7190e3d5408SPeter Wemm if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH)) 7200e3d5408SPeter Wemm (void) fprintf(stderr, 7210e3d5408SPeter Wemm "warning: resolved %s entry is %d bytes long\n", 7220e3d5408SPeter Wemm _nc_first_name(qp->tterm.term_names), 7230e3d5408SPeter Wemm len); 7240e3d5408SPeter Wemm } 7250e3d5408SPeter Wemm } 7260e3d5408SPeter Wemm } 7270e3d5408SPeter Wemm 7280e3d5408SPeter Wemm /* write or dump all entries */ 72915589c42SPeter Wemm if (!check_only) { 73015589c42SPeter Wemm if (!infodump && !capdump) { 7310e3d5408SPeter Wemm _nc_set_writedir(outdir); 73215589c42SPeter Wemm for_entry_list(qp) { 7330e3d5408SPeter Wemm if (matches(namelst, qp->tterm.term_names)) 7340e3d5408SPeter Wemm write_it(qp); 7350e3d5408SPeter Wemm } 73615589c42SPeter Wemm } else { 7370e3d5408SPeter Wemm /* this is in case infotocap() generates warnings */ 7380e3d5408SPeter Wemm _nc_curr_col = _nc_curr_line = -1; 7390e3d5408SPeter Wemm 74015589c42SPeter Wemm for_entry_list(qp) { 74115589c42SPeter Wemm if (matches(namelst, qp->tterm.term_names)) { 7420e3d5408SPeter Wemm int j = qp->cend - qp->cstart; 7430e3d5408SPeter Wemm int len = 0; 7440e3d5408SPeter Wemm 7450e3d5408SPeter Wemm /* this is in case infotocap() generates warnings */ 7460e3d5408SPeter Wemm _nc_set_type(_nc_first_name(qp->tterm.term_names)); 7470e3d5408SPeter Wemm 7480e3d5408SPeter Wemm (void) fseek(tmp_fp, qp->cstart, SEEK_SET); 7494a1a9510SRong-En Fan while (j-- > 0) { 7500e3d5408SPeter Wemm if (infodump) 7510e3d5408SPeter Wemm (void) putchar(fgetc(tmp_fp)); 7520e3d5408SPeter Wemm else 7530e3d5408SPeter Wemm put_translate(fgetc(tmp_fp)); 75415589c42SPeter Wemm } 7550e3d5408SPeter Wemm 7564a1a9510SRong-En Fan dump_entry(&qp->tterm, suppress_untranslatable, 7574a1a9510SRong-En Fan limited, numbers, NULL); 7580e3d5408SPeter Wemm for (j = 0; j < qp->nuses; j++) 7594a1a9510SRong-En Fan dump_uses(qp->uses[j].name, !capdump); 7604a1a9510SRong-En Fan len = show_entry(); 7610e3d5408SPeter Wemm if (debug_level != 0 && !limited) 7620e3d5408SPeter Wemm printf("# length=%d\n", len); 7630e3d5408SPeter Wemm } 76415589c42SPeter Wemm } 7657a69bbfbSPeter Wemm if (!namelst && _nc_tail) { 7660e3d5408SPeter Wemm int c, oldc = '\0'; 7670e3d5408SPeter Wemm bool in_comment = FALSE; 7680e3d5408SPeter Wemm bool trailing_comment = FALSE; 7690e3d5408SPeter Wemm 7700e3d5408SPeter Wemm (void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET); 77115589c42SPeter Wemm while ((c = fgetc(tmp_fp)) != EOF) { 7720e3d5408SPeter Wemm if (oldc == '\n') { 7730e3d5408SPeter Wemm if (c == '#') { 7740e3d5408SPeter Wemm trailing_comment = TRUE; 7750e3d5408SPeter Wemm in_comment = TRUE; 7760e3d5408SPeter Wemm } else { 7770e3d5408SPeter Wemm in_comment = FALSE; 7780e3d5408SPeter Wemm } 7790e3d5408SPeter Wemm } 7800e3d5408SPeter Wemm if (trailing_comment 7810e3d5408SPeter Wemm && (in_comment || (oldc == '\n' && c == '\n'))) 7820e3d5408SPeter Wemm putchar(c); 7830e3d5408SPeter Wemm oldc = c; 7840e3d5408SPeter Wemm } 7850e3d5408SPeter Wemm } 7860e3d5408SPeter Wemm } 7870e3d5408SPeter Wemm } 7880e3d5408SPeter Wemm 7890e3d5408SPeter Wemm /* Show the directory into which entries were written, and the total 7900e3d5408SPeter Wemm * number of entries 7910e3d5408SPeter Wemm */ 7920e3d5408SPeter Wemm if (showsummary 7930e3d5408SPeter Wemm && (!(check_only || infodump || capdump))) { 7940e3d5408SPeter Wemm int total = _nc_tic_written(); 7950e3d5408SPeter Wemm if (total != 0) 7960e3d5408SPeter Wemm fprintf(log_fp, "%d entries written to %s\n", 7970e3d5408SPeter Wemm total, 7980e3d5408SPeter Wemm _nc_tic_dir((char *) 0)); 7990e3d5408SPeter Wemm else 8000e3d5408SPeter Wemm fprintf(log_fp, "No entries written\n"); 8010e3d5408SPeter Wemm } 8025ca44d1cSRong-En Fan #if NO_LEAKS 8035ca44d1cSRong-En Fan free_namelist(namelst); 8045ca44d1cSRong-En Fan #endif 8050e3d5408SPeter Wemm cleanup(); 8064a1a9510SRong-En Fan ExitProgram(EXIT_SUCCESS); 8070e3d5408SPeter Wemm } 8080e3d5408SPeter Wemm 8090e3d5408SPeter Wemm /* 8100e3d5408SPeter Wemm * This bit of legerdemain turns all the terminfo variable names into 8110e3d5408SPeter Wemm * references to locations in the arrays Booleans, Numbers, and Strings --- 8120e3d5408SPeter Wemm * precisely what's needed (see comp_parse.c). 8130e3d5408SPeter Wemm */ 8140e3d5408SPeter Wemm #undef CUR 8150e3d5408SPeter Wemm #define CUR tp-> 8160e3d5408SPeter Wemm 81715589c42SPeter Wemm /* 8184a1a9510SRong-En Fan * Check if the alternate character-set capabilities are consistent. 8194a1a9510SRong-En Fan */ 8204a1a9510SRong-En Fan static void 8214a1a9510SRong-En Fan check_acs(TERMTYPE *tp) 8224a1a9510SRong-En Fan { 8234a1a9510SRong-En Fan if (VALID_STRING(acs_chars)) { 8244a1a9510SRong-En Fan const char *boxes = "lmkjtuvwqxn"; 8254a1a9510SRong-En Fan char mapped[256]; 8264a1a9510SRong-En Fan char missing[256]; 8274a1a9510SRong-En Fan const char *p; 8284a1a9510SRong-En Fan char *q; 8294a1a9510SRong-En Fan 8304a1a9510SRong-En Fan memset(mapped, 0, sizeof(mapped)); 8314a1a9510SRong-En Fan for (p = acs_chars; *p != '\0'; p += 2) { 8324a1a9510SRong-En Fan if (p[1] == '\0') { 8334a1a9510SRong-En Fan _nc_warning("acsc has odd number of characters"); 8344a1a9510SRong-En Fan break; 8354a1a9510SRong-En Fan } 8364a1a9510SRong-En Fan mapped[UChar(p[0])] = p[1]; 8374a1a9510SRong-En Fan } 8384a1a9510SRong-En Fan if (mapped[UChar('I')] && !mapped[UChar('i')]) { 8394a1a9510SRong-En Fan _nc_warning("acsc refers to 'I', which is probably an error"); 8404a1a9510SRong-En Fan } 8414a1a9510SRong-En Fan for (p = boxes, q = missing; *p != '\0'; ++p) { 8424a1a9510SRong-En Fan if (!mapped[UChar(p[0])]) { 8434a1a9510SRong-En Fan *q++ = p[0]; 8444a1a9510SRong-En Fan } 8454a1a9510SRong-En Fan *q = '\0'; 8464a1a9510SRong-En Fan } 8474a1a9510SRong-En Fan if (*missing != '\0' && strcmp(missing, boxes)) { 8484a1a9510SRong-En Fan _nc_warning("acsc is missing some line-drawing mapping: %s", missing); 8494a1a9510SRong-En Fan } 8504a1a9510SRong-En Fan } 8514a1a9510SRong-En Fan } 8524a1a9510SRong-En Fan 8534a1a9510SRong-En Fan /* 8544a1a9510SRong-En Fan * Check if the color capabilities are consistent 8554a1a9510SRong-En Fan */ 8564a1a9510SRong-En Fan static void 8574a1a9510SRong-En Fan check_colors(TERMTYPE *tp) 8584a1a9510SRong-En Fan { 8594a1a9510SRong-En Fan if ((max_colors > 0) != (max_pairs > 0) 8604a1a9510SRong-En Fan || ((max_colors > max_pairs) && (initialize_pair == 0))) 8614a1a9510SRong-En Fan _nc_warning("inconsistent values for max_colors (%d) and max_pairs (%d)", 8624a1a9510SRong-En Fan max_colors, max_pairs); 8634a1a9510SRong-En Fan 8644a1a9510SRong-En Fan PAIRED(set_foreground, set_background); 8654a1a9510SRong-En Fan PAIRED(set_a_foreground, set_a_background); 8664a1a9510SRong-En Fan PAIRED(set_color_pair, initialize_pair); 8674a1a9510SRong-En Fan 8684a1a9510SRong-En Fan if (VALID_STRING(set_foreground) 8694a1a9510SRong-En Fan && VALID_STRING(set_a_foreground) 8704a1a9510SRong-En Fan && !_nc_capcmp(set_foreground, set_a_foreground)) 8714a1a9510SRong-En Fan _nc_warning("expected setf/setaf to be different"); 8724a1a9510SRong-En Fan 8734a1a9510SRong-En Fan if (VALID_STRING(set_background) 8744a1a9510SRong-En Fan && VALID_STRING(set_a_background) 8754a1a9510SRong-En Fan && !_nc_capcmp(set_background, set_a_background)) 8764a1a9510SRong-En Fan _nc_warning("expected setb/setab to be different"); 8774a1a9510SRong-En Fan 8784a1a9510SRong-En Fan /* see: has_colors() */ 8794a1a9510SRong-En Fan if (VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs) 8804a1a9510SRong-En Fan && (((set_foreground != NULL) 8814a1a9510SRong-En Fan && (set_background != NULL)) 8824a1a9510SRong-En Fan || ((set_a_foreground != NULL) 8834a1a9510SRong-En Fan && (set_a_background != NULL)) 8844a1a9510SRong-En Fan || set_color_pair)) { 8854a1a9510SRong-En Fan if (!VALID_STRING(orig_pair) && !VALID_STRING(orig_colors)) 8864a1a9510SRong-En Fan _nc_warning("expected either op/oc string for resetting colors"); 8874a1a9510SRong-En Fan } 8884a1a9510SRong-En Fan } 8894a1a9510SRong-En Fan 8904a1a9510SRong-En Fan static int 8914a1a9510SRong-En Fan keypad_final(const char *string) 8924a1a9510SRong-En Fan { 8934a1a9510SRong-En Fan int result = '\0'; 8944a1a9510SRong-En Fan 8954a1a9510SRong-En Fan if (VALID_STRING(string) 8964a1a9510SRong-En Fan && *string++ == '\033' 8974a1a9510SRong-En Fan && *string++ == 'O' 8984a1a9510SRong-En Fan && strlen(string) == 1) { 8994a1a9510SRong-En Fan result = *string; 9004a1a9510SRong-En Fan } 9014a1a9510SRong-En Fan 9024a1a9510SRong-En Fan return result; 9034a1a9510SRong-En Fan } 9044a1a9510SRong-En Fan 9054a1a9510SRong-En Fan static int 9064a1a9510SRong-En Fan keypad_index(const char *string) 9074a1a9510SRong-En Fan { 9084a1a9510SRong-En Fan char *test; 9094a1a9510SRong-En Fan const char *list = "PQRSwxymtuvlqrsPpn"; /* app-keypad except "Enter" */ 9104a1a9510SRong-En Fan int ch; 9114a1a9510SRong-En Fan int result = -1; 9124a1a9510SRong-En Fan 9134a1a9510SRong-En Fan if ((ch = keypad_final(string)) != '\0') { 9144a1a9510SRong-En Fan test = strchr(list, ch); 9154a1a9510SRong-En Fan if (test != 0) 9164a1a9510SRong-En Fan result = (test - list); 9174a1a9510SRong-En Fan } 9184a1a9510SRong-En Fan return result; 9194a1a9510SRong-En Fan } 9204a1a9510SRong-En Fan 9214a1a9510SRong-En Fan /* 9224a1a9510SRong-En Fan * Do a quick sanity-check for vt100-style keypads to see if the 5-key keypad 9234a1a9510SRong-En Fan * is mapped inconsistently. 9244a1a9510SRong-En Fan */ 9254a1a9510SRong-En Fan static void 9264a1a9510SRong-En Fan check_keypad(TERMTYPE *tp) 9274a1a9510SRong-En Fan { 9284a1a9510SRong-En Fan char show[80]; 9294a1a9510SRong-En Fan 9304a1a9510SRong-En Fan if (VALID_STRING(key_a1) && 9314a1a9510SRong-En Fan VALID_STRING(key_a3) && 9324a1a9510SRong-En Fan VALID_STRING(key_b2) && 9334a1a9510SRong-En Fan VALID_STRING(key_c1) && 9344a1a9510SRong-En Fan VALID_STRING(key_c3)) { 9354a1a9510SRong-En Fan char final[6]; 9364a1a9510SRong-En Fan int list[5]; 9374a1a9510SRong-En Fan int increase = 0; 9384a1a9510SRong-En Fan int j, k, kk; 9394a1a9510SRong-En Fan int last; 9404a1a9510SRong-En Fan int test; 9414a1a9510SRong-En Fan 9424a1a9510SRong-En Fan final[0] = keypad_final(key_a1); 9434a1a9510SRong-En Fan final[1] = keypad_final(key_a3); 9444a1a9510SRong-En Fan final[2] = keypad_final(key_b2); 9454a1a9510SRong-En Fan final[3] = keypad_final(key_c1); 9464a1a9510SRong-En Fan final[4] = keypad_final(key_c3); 9474a1a9510SRong-En Fan final[5] = '\0'; 9484a1a9510SRong-En Fan 9494a1a9510SRong-En Fan /* special case: legacy coding using 1,2,3,0,. on the bottom */ 9504a1a9510SRong-En Fan if (!strcmp(final, "qsrpn")) 9514a1a9510SRong-En Fan return; 9524a1a9510SRong-En Fan 9534a1a9510SRong-En Fan list[0] = keypad_index(key_a1); 9544a1a9510SRong-En Fan list[1] = keypad_index(key_a3); 9554a1a9510SRong-En Fan list[2] = keypad_index(key_b2); 9564a1a9510SRong-En Fan list[3] = keypad_index(key_c1); 9574a1a9510SRong-En Fan list[4] = keypad_index(key_c3); 9584a1a9510SRong-En Fan 9594a1a9510SRong-En Fan /* check that they're all vt100 keys */ 9604a1a9510SRong-En Fan for (j = 0; j < 5; ++j) { 9614a1a9510SRong-En Fan if (list[j] < 0) { 9624a1a9510SRong-En Fan return; 9634a1a9510SRong-En Fan } 9644a1a9510SRong-En Fan } 9654a1a9510SRong-En Fan 9664a1a9510SRong-En Fan /* check if they're all in increasing order */ 9674a1a9510SRong-En Fan for (j = 1; j < 5; ++j) { 9684a1a9510SRong-En Fan if (list[j] > list[j - 1]) { 9694a1a9510SRong-En Fan ++increase; 9704a1a9510SRong-En Fan } 9714a1a9510SRong-En Fan } 9724a1a9510SRong-En Fan if (increase != 4) { 9734a1a9510SRong-En Fan show[0] = '\0'; 9744a1a9510SRong-En Fan 9754a1a9510SRong-En Fan for (j = 0, last = -1; j < 5; ++j) { 9764a1a9510SRong-En Fan for (k = 0, kk = -1, test = 100; k < 5; ++k) { 9774a1a9510SRong-En Fan if (list[k] > last && 9784a1a9510SRong-En Fan list[k] < test) { 9794a1a9510SRong-En Fan test = list[k]; 9804a1a9510SRong-En Fan kk = k; 9814a1a9510SRong-En Fan } 9824a1a9510SRong-En Fan } 9834a1a9510SRong-En Fan last = test; 9844a1a9510SRong-En Fan switch (kk) { 9854a1a9510SRong-En Fan case 0: 9864a1a9510SRong-En Fan strcat(show, " ka1"); 9874a1a9510SRong-En Fan break; 9884a1a9510SRong-En Fan case 1: 9894a1a9510SRong-En Fan strcat(show, " ka3"); 9904a1a9510SRong-En Fan break; 9914a1a9510SRong-En Fan case 2: 9924a1a9510SRong-En Fan strcat(show, " kb2"); 9934a1a9510SRong-En Fan break; 9944a1a9510SRong-En Fan case 3: 9954a1a9510SRong-En Fan strcat(show, " kc1"); 9964a1a9510SRong-En Fan break; 9974a1a9510SRong-En Fan case 4: 9984a1a9510SRong-En Fan strcat(show, " kc3"); 9994a1a9510SRong-En Fan break; 10004a1a9510SRong-En Fan } 10014a1a9510SRong-En Fan } 10024a1a9510SRong-En Fan 10034a1a9510SRong-En Fan _nc_warning("vt100 keypad order inconsistent: %s", show); 10044a1a9510SRong-En Fan } 10054a1a9510SRong-En Fan 10064a1a9510SRong-En Fan } else if (VALID_STRING(key_a1) || 10074a1a9510SRong-En Fan VALID_STRING(key_a3) || 10084a1a9510SRong-En Fan VALID_STRING(key_b2) || 10094a1a9510SRong-En Fan VALID_STRING(key_c1) || 10104a1a9510SRong-En Fan VALID_STRING(key_c3)) { 10114a1a9510SRong-En Fan show[0] = '\0'; 10124a1a9510SRong-En Fan if (keypad_index(key_a1) >= 0) 10134a1a9510SRong-En Fan strcat(show, " ka1"); 10144a1a9510SRong-En Fan if (keypad_index(key_a3) >= 0) 10154a1a9510SRong-En Fan strcat(show, " ka3"); 10164a1a9510SRong-En Fan if (keypad_index(key_b2) >= 0) 10174a1a9510SRong-En Fan strcat(show, " kb2"); 10184a1a9510SRong-En Fan if (keypad_index(key_c1) >= 0) 10194a1a9510SRong-En Fan strcat(show, " kc1"); 10204a1a9510SRong-En Fan if (keypad_index(key_c3) >= 0) 10214a1a9510SRong-En Fan strcat(show, " kc3"); 10224a1a9510SRong-En Fan if (*show != '\0') 10234a1a9510SRong-En Fan _nc_warning("vt100 keypad map incomplete:%s", show); 10244a1a9510SRong-En Fan } 10254a1a9510SRong-En Fan } 10264a1a9510SRong-En Fan 10274a1a9510SRong-En Fan /* 102818259542SPeter Wemm * Returns the expected number of parameters for the given capability. 102918259542SPeter Wemm */ 103018259542SPeter Wemm static int 10317a69bbfbSPeter Wemm expected_params(const char *name) 103218259542SPeter Wemm { 103318259542SPeter Wemm /* *INDENT-OFF* */ 103418259542SPeter Wemm static const struct { 103518259542SPeter Wemm const char *name; 103618259542SPeter Wemm int count; 103718259542SPeter Wemm } table[] = { 10387a69bbfbSPeter Wemm { "S0", 1 }, /* 'screen' extension */ 103918259542SPeter Wemm { "birep", 2 }, 104018259542SPeter Wemm { "chr", 1 }, 104118259542SPeter Wemm { "colornm", 1 }, 104218259542SPeter Wemm { "cpi", 1 }, 10437a69bbfbSPeter Wemm { "csnm", 1 }, 104418259542SPeter Wemm { "csr", 2 }, 104518259542SPeter Wemm { "cub", 1 }, 104618259542SPeter Wemm { "cud", 1 }, 104718259542SPeter Wemm { "cuf", 1 }, 104818259542SPeter Wemm { "cup", 2 }, 104918259542SPeter Wemm { "cuu", 1 }, 10507a69bbfbSPeter Wemm { "cvr", 1 }, 105118259542SPeter Wemm { "cwin", 5 }, 105218259542SPeter Wemm { "dch", 1 }, 10537a69bbfbSPeter Wemm { "defc", 3 }, 105418259542SPeter Wemm { "dial", 1 }, 105518259542SPeter Wemm { "dispc", 1 }, 105618259542SPeter Wemm { "dl", 1 }, 105718259542SPeter Wemm { "ech", 1 }, 105818259542SPeter Wemm { "getm", 1 }, 105918259542SPeter Wemm { "hpa", 1 }, 106018259542SPeter Wemm { "ich", 1 }, 106118259542SPeter Wemm { "il", 1 }, 106218259542SPeter Wemm { "indn", 1 }, 106318259542SPeter Wemm { "initc", 4 }, 106418259542SPeter Wemm { "initp", 7 }, 106518259542SPeter Wemm { "lpi", 1 }, 106618259542SPeter Wemm { "mc5p", 1 }, 106718259542SPeter Wemm { "mrcup", 2 }, 106818259542SPeter Wemm { "mvpa", 1 }, 106918259542SPeter Wemm { "pfkey", 2 }, 107018259542SPeter Wemm { "pfloc", 2 }, 107118259542SPeter Wemm { "pfx", 2 }, 107218259542SPeter Wemm { "pfxl", 3 }, 107318259542SPeter Wemm { "pln", 2 }, 107418259542SPeter Wemm { "qdial", 1 }, 10757a69bbfbSPeter Wemm { "rcsd", 1 }, 107618259542SPeter Wemm { "rep", 2 }, 107718259542SPeter Wemm { "rin", 1 }, 107818259542SPeter Wemm { "sclk", 3 }, 107918259542SPeter Wemm { "scp", 1 }, 108018259542SPeter Wemm { "scs", 1 }, 10817a69bbfbSPeter Wemm { "scsd", 2 }, 108218259542SPeter Wemm { "setab", 1 }, 108318259542SPeter Wemm { "setaf", 1 }, 108418259542SPeter Wemm { "setb", 1 }, 108518259542SPeter Wemm { "setcolor", 1 }, 108618259542SPeter Wemm { "setf", 1 }, 108718259542SPeter Wemm { "sgr", 9 }, 108818259542SPeter Wemm { "sgr1", 6 }, 108918259542SPeter Wemm { "slength", 1 }, 109018259542SPeter Wemm { "slines", 1 }, 1091b82face1SPeter Wemm { "smgbp", 1 }, /* 2 if smgtp is not given */ 1092b82face1SPeter Wemm { "smglp", 1 }, 109318259542SPeter Wemm { "smglr", 2 }, 109418259542SPeter Wemm { "smgrp", 1 }, 109518259542SPeter Wemm { "smgtb", 2 }, 10967a69bbfbSPeter Wemm { "smgtp", 1 }, 109718259542SPeter Wemm { "tsl", 1 }, 109818259542SPeter Wemm { "u6", -1 }, 109918259542SPeter Wemm { "vpa", 1 }, 110018259542SPeter Wemm { "wind", 4 }, 110118259542SPeter Wemm { "wingo", 1 }, 110218259542SPeter Wemm }; 110318259542SPeter Wemm /* *INDENT-ON* */ 110418259542SPeter Wemm 110518259542SPeter Wemm unsigned n; 110618259542SPeter Wemm int result = 0; /* function-keys, etc., use none */ 110718259542SPeter Wemm 110818259542SPeter Wemm for (n = 0; n < SIZEOF(table); n++) { 110918259542SPeter Wemm if (!strcmp(name, table[n].name)) { 111018259542SPeter Wemm result = table[n].count; 111118259542SPeter Wemm break; 111218259542SPeter Wemm } 111318259542SPeter Wemm } 111418259542SPeter Wemm 111518259542SPeter Wemm return result; 111618259542SPeter Wemm } 111718259542SPeter Wemm 111818259542SPeter Wemm /* 111918259542SPeter Wemm * Make a quick sanity check for the parameters which are used in the given 112018259542SPeter Wemm * strings. If there are no "%p" tokens, then there should be no other "%" 112118259542SPeter Wemm * markers. 112218259542SPeter Wemm */ 112318259542SPeter Wemm static void 11247a69bbfbSPeter Wemm check_params(TERMTYPE *tp, const char *name, char *value) 112518259542SPeter Wemm { 112618259542SPeter Wemm int expected = expected_params(name); 112718259542SPeter Wemm int actual = 0; 112818259542SPeter Wemm int n; 112918259542SPeter Wemm bool params[10]; 113018259542SPeter Wemm char *s = value; 113118259542SPeter Wemm 11324a1a9510SRong-En Fan #ifdef set_top_margin_parm 1133b82face1SPeter Wemm if (!strcmp(name, "smgbp") 1134b82face1SPeter Wemm && set_top_margin_parm == 0) 1135b82face1SPeter Wemm expected = 2; 11364a1a9510SRong-En Fan #endif 1137b82face1SPeter Wemm 113818259542SPeter Wemm for (n = 0; n < 10; n++) 113918259542SPeter Wemm params[n] = FALSE; 114018259542SPeter Wemm 114118259542SPeter Wemm while (*s != 0) { 114218259542SPeter Wemm if (*s == '%') { 114318259542SPeter Wemm if (*++s == '\0') { 114418259542SPeter Wemm _nc_warning("expected character after %% in %s", name); 114518259542SPeter Wemm break; 114618259542SPeter Wemm } else if (*s == 'p') { 114718259542SPeter Wemm if (*++s == '\0' || !isdigit((int) *s)) { 114818259542SPeter Wemm _nc_warning("expected digit after %%p in %s", name); 114918259542SPeter Wemm return; 115018259542SPeter Wemm } else { 115118259542SPeter Wemm n = (*s - '0'); 115218259542SPeter Wemm if (n > actual) 115318259542SPeter Wemm actual = n; 115418259542SPeter Wemm params[n] = TRUE; 115518259542SPeter Wemm } 115618259542SPeter Wemm } 115718259542SPeter Wemm } 115818259542SPeter Wemm s++; 115918259542SPeter Wemm } 116018259542SPeter Wemm 116118259542SPeter Wemm if (params[0]) { 116218259542SPeter Wemm _nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name); 116318259542SPeter Wemm } 116418259542SPeter Wemm if (value == set_attributes || expected < 0) { 116518259542SPeter Wemm ; 116618259542SPeter Wemm } else if (expected != actual) { 116718259542SPeter Wemm _nc_warning("%s uses %d parameters, expected %d", name, 116818259542SPeter Wemm actual, expected); 116918259542SPeter Wemm for (n = 1; n < actual; n++) { 117018259542SPeter Wemm if (!params[n]) 117118259542SPeter Wemm _nc_warning("%s omits parameter %d", name, n); 117218259542SPeter Wemm } 117318259542SPeter Wemm } 117418259542SPeter Wemm } 117518259542SPeter Wemm 1176b82face1SPeter Wemm static char * 1177b82face1SPeter Wemm skip_delay(char *s) 1178b82face1SPeter Wemm { 1179b82face1SPeter Wemm while (*s == '/' || isdigit(UChar(*s))) 1180b82face1SPeter Wemm ++s; 1181b82face1SPeter Wemm return s; 1182b82face1SPeter Wemm } 1183b82face1SPeter Wemm 118418259542SPeter Wemm /* 11854a1a9510SRong-En Fan * Skip a delay altogether, e.g., when comparing a simple string to sgr, 11864a1a9510SRong-En Fan * the latter may have a worst-case delay on the end. 11874a1a9510SRong-En Fan */ 11884a1a9510SRong-En Fan static char * 11894a1a9510SRong-En Fan ignore_delays(char *s) 11904a1a9510SRong-En Fan { 11914a1a9510SRong-En Fan int delaying = 0; 11924a1a9510SRong-En Fan 11934a1a9510SRong-En Fan do { 11944a1a9510SRong-En Fan switch (*s) { 11954a1a9510SRong-En Fan case '$': 11964a1a9510SRong-En Fan if (delaying == 0) 11974a1a9510SRong-En Fan delaying = 1; 11984a1a9510SRong-En Fan break; 11994a1a9510SRong-En Fan case '<': 12004a1a9510SRong-En Fan if (delaying == 1) 12014a1a9510SRong-En Fan delaying = 2; 12024a1a9510SRong-En Fan break; 12034a1a9510SRong-En Fan case '\0': 12044a1a9510SRong-En Fan delaying = 0; 12054a1a9510SRong-En Fan break; 12064a1a9510SRong-En Fan default: 12074a1a9510SRong-En Fan if (delaying) { 12084a1a9510SRong-En Fan s = skip_delay(s); 12094a1a9510SRong-En Fan if (*s == '>') 12104a1a9510SRong-En Fan ++s; 12114a1a9510SRong-En Fan delaying = 0; 12124a1a9510SRong-En Fan } 12134a1a9510SRong-En Fan break; 12144a1a9510SRong-En Fan } 12154a1a9510SRong-En Fan if (delaying) 12164a1a9510SRong-En Fan ++s; 12174a1a9510SRong-En Fan } while (delaying); 12184a1a9510SRong-En Fan return s; 12194a1a9510SRong-En Fan } 12204a1a9510SRong-En Fan 12214a1a9510SRong-En Fan /* 122215589c42SPeter Wemm * An sgr string may contain several settings other than the one we're 122315589c42SPeter Wemm * interested in, essentially sgr0 + rmacs + whatever. As long as the 122415589c42SPeter Wemm * "whatever" is contained in the sgr string, that is close enough for our 122515589c42SPeter Wemm * sanity check. 122615589c42SPeter Wemm */ 122715589c42SPeter Wemm static bool 1228b82face1SPeter Wemm similar_sgr(int num, char *a, char *b) 122915589c42SPeter Wemm { 1230b82face1SPeter Wemm static const char *names[] = 1231b82face1SPeter Wemm { 1232b82face1SPeter Wemm "none" 1233b82face1SPeter Wemm ,"standout" 1234b82face1SPeter Wemm ,"underline" 1235b82face1SPeter Wemm ,"reverse" 1236b82face1SPeter Wemm ,"blink" 1237b82face1SPeter Wemm ,"dim" 1238b82face1SPeter Wemm ,"bold" 1239b82face1SPeter Wemm ,"invis" 1240b82face1SPeter Wemm ,"protect" 1241b82face1SPeter Wemm ,"altcharset" 1242b82face1SPeter Wemm }; 1243b82face1SPeter Wemm char *base_a = a; 1244b82face1SPeter Wemm char *base_b = b; 1245b82face1SPeter Wemm int delaying = 0; 1246b82face1SPeter Wemm 124715589c42SPeter Wemm while (*b != 0) { 124815589c42SPeter Wemm while (*a != *b) { 12497a69bbfbSPeter Wemm if (*a == 0) { 12507a69bbfbSPeter Wemm if (b[0] == '$' 12517a69bbfbSPeter Wemm && b[1] == '<') { 12527a69bbfbSPeter Wemm _nc_warning("Did not find delay %s", _nc_visbuf(b)); 12537a69bbfbSPeter Wemm } else { 1254b82face1SPeter Wemm _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s", 1255b82face1SPeter Wemm names[num], _nc_visbuf2(1, base_a), 1256b82face1SPeter Wemm _nc_visbuf2(2, base_b), 1257b82face1SPeter Wemm _nc_visbuf2(3, b)); 12587a69bbfbSPeter Wemm } 125915589c42SPeter Wemm return FALSE; 1260b82face1SPeter Wemm } else if (delaying) { 1261b82face1SPeter Wemm a = skip_delay(a); 1262b82face1SPeter Wemm b = skip_delay(b); 1263b82face1SPeter Wemm } else { 126415589c42SPeter Wemm a++; 126515589c42SPeter Wemm } 1266b82face1SPeter Wemm } 1267b82face1SPeter Wemm switch (*a) { 1268b82face1SPeter Wemm case '$': 1269b82face1SPeter Wemm if (delaying == 0) 1270b82face1SPeter Wemm delaying = 1; 1271b82face1SPeter Wemm break; 1272b82face1SPeter Wemm case '<': 1273b82face1SPeter Wemm if (delaying == 1) 1274b82face1SPeter Wemm delaying = 2; 1275b82face1SPeter Wemm break; 1276b82face1SPeter Wemm default: 1277b82face1SPeter Wemm delaying = 0; 1278b82face1SPeter Wemm break; 1279b82face1SPeter Wemm } 128015589c42SPeter Wemm a++; 128115589c42SPeter Wemm b++; 128215589c42SPeter Wemm } 12834a1a9510SRong-En Fan /* ignore delays on the end of the string */ 12844a1a9510SRong-En Fan a = ignore_delays(a); 12854a1a9510SRong-En Fan return ((num != 0) || (*a == 0)); 128615589c42SPeter Wemm } 128715589c42SPeter Wemm 12884a1a9510SRong-En Fan static char * 128915589c42SPeter Wemm check_sgr(TERMTYPE *tp, char *zero, int num, char *cap, const char *name) 129015589c42SPeter Wemm { 12914a1a9510SRong-En Fan char *test; 12924a1a9510SRong-En Fan 12934a1a9510SRong-En Fan _nc_tparm_err = 0; 12944a1a9510SRong-En Fan test = TPARM_9(set_attributes, 129515589c42SPeter Wemm num == 1, 129615589c42SPeter Wemm num == 2, 129715589c42SPeter Wemm num == 3, 129815589c42SPeter Wemm num == 4, 129915589c42SPeter Wemm num == 5, 130015589c42SPeter Wemm num == 6, 130115589c42SPeter Wemm num == 7, 130215589c42SPeter Wemm num == 8, 130315589c42SPeter Wemm num == 9); 130415589c42SPeter Wemm if (test != 0) { 130515589c42SPeter Wemm if (PRESENT(cap)) { 1306b82face1SPeter Wemm if (!similar_sgr(num, test, cap)) { 1307b82face1SPeter Wemm _nc_warning("%s differs from sgr(%d)\n\t%s=%s\n\tsgr(%d)=%s", 1308b82face1SPeter Wemm name, num, 1309b82face1SPeter Wemm name, _nc_visbuf2(1, cap), 1310b82face1SPeter Wemm num, _nc_visbuf2(2, test)); 131115589c42SPeter Wemm } 13124a1a9510SRong-En Fan } else if (_nc_capcmp(test, zero)) { 131315589c42SPeter Wemm _nc_warning("sgr(%d) present, but not %s", num, name); 131415589c42SPeter Wemm } 131515589c42SPeter Wemm } else if (PRESENT(cap)) { 131615589c42SPeter Wemm _nc_warning("sgr(%d) missing, but %s present", num, name); 131715589c42SPeter Wemm } 13184a1a9510SRong-En Fan if (_nc_tparm_err) 13194a1a9510SRong-En Fan _nc_warning("stack error in sgr(%d) string", num); 13204a1a9510SRong-En Fan return test; 132115589c42SPeter Wemm } 132215589c42SPeter Wemm 132315589c42SPeter Wemm #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name) 132415589c42SPeter Wemm 13254a1a9510SRong-En Fan #ifdef TRACE 13264a1a9510SRong-En Fan /* 13274a1a9510SRong-En Fan * If tic is compiled with TRACE, we'll be able to see the output from the 13284a1a9510SRong-En Fan * DEBUG() macro. But since it doesn't use traceon(), it always goes to 13294a1a9510SRong-En Fan * the standard error. Use this function to make it simpler to follow the 13304a1a9510SRong-En Fan * resulting debug traces. 13314a1a9510SRong-En Fan */ 13324a1a9510SRong-En Fan static void 13334a1a9510SRong-En Fan show_where(unsigned level) 13344a1a9510SRong-En Fan { 13354a1a9510SRong-En Fan if (_nc_tracing >= DEBUG_LEVEL(level)) { 13364a1a9510SRong-En Fan char my_name[256]; 13374a1a9510SRong-En Fan _nc_get_type(my_name); 13384a1a9510SRong-En Fan fprintf(stderr, "\"%s\", line %d, '%s' ", 13394a1a9510SRong-En Fan _nc_get_source(), 13404a1a9510SRong-En Fan _nc_curr_line, my_name); 13414a1a9510SRong-En Fan } 13424a1a9510SRong-En Fan } 13434a1a9510SRong-En Fan 13444a1a9510SRong-En Fan #else 13454a1a9510SRong-En Fan #define show_where(level) /* nothing */ 13464a1a9510SRong-En Fan #endif 13474a1a9510SRong-En Fan 13480e3d5408SPeter Wemm /* other sanity-checks (things that we don't want in the normal 13490e3d5408SPeter Wemm * logic that reads a terminfo entry) 13500e3d5408SPeter Wemm */ 135115589c42SPeter Wemm static void 13524a1a9510SRong-En Fan check_termtype(TERMTYPE *tp, bool literal) 13530e3d5408SPeter Wemm { 13540e3d5408SPeter Wemm bool conflict = FALSE; 13550e3d5408SPeter Wemm unsigned j, k; 13560e3d5408SPeter Wemm char fkeys[STRCOUNT]; 13570e3d5408SPeter Wemm 13580e3d5408SPeter Wemm /* 13590e3d5408SPeter Wemm * A terminal entry may contain more than one keycode assigned to 13600e3d5408SPeter Wemm * a given string (e.g., KEY_END and KEY_LL). But curses will only 13610e3d5408SPeter Wemm * return one (the last one assigned). 13620e3d5408SPeter Wemm */ 13634a1a9510SRong-En Fan if (!(_nc_syntax == SYN_TERMCAP && capdump)) { 13640e3d5408SPeter Wemm memset(fkeys, 0, sizeof(fkeys)); 13650e3d5408SPeter Wemm for (j = 0; _nc_tinfo_fkeys[j].code; j++) { 13660e3d5408SPeter Wemm char *a = tp->Strings[_nc_tinfo_fkeys[j].offset]; 13670e3d5408SPeter Wemm bool first = TRUE; 13680e3d5408SPeter Wemm if (!VALID_STRING(a)) 13690e3d5408SPeter Wemm continue; 13700e3d5408SPeter Wemm for (k = j + 1; _nc_tinfo_fkeys[k].code; k++) { 13710e3d5408SPeter Wemm char *b = tp->Strings[_nc_tinfo_fkeys[k].offset]; 13720e3d5408SPeter Wemm if (!VALID_STRING(b) 13730e3d5408SPeter Wemm || fkeys[k]) 13740e3d5408SPeter Wemm continue; 13754a1a9510SRong-En Fan if (!_nc_capcmp(a, b)) { 13760e3d5408SPeter Wemm fkeys[j] = 1; 13770e3d5408SPeter Wemm fkeys[k] = 1; 13780e3d5408SPeter Wemm if (first) { 13790e3d5408SPeter Wemm if (!conflict) { 13800e3d5408SPeter Wemm _nc_warning("Conflicting key definitions (using the last)"); 13810e3d5408SPeter Wemm conflict = TRUE; 13820e3d5408SPeter Wemm } 13830e3d5408SPeter Wemm fprintf(stderr, "... %s is the same as %s", 13844a1a9510SRong-En Fan keyname((int) _nc_tinfo_fkeys[j].code), 13854a1a9510SRong-En Fan keyname((int) _nc_tinfo_fkeys[k].code)); 13860e3d5408SPeter Wemm first = FALSE; 13870e3d5408SPeter Wemm } else { 13880e3d5408SPeter Wemm fprintf(stderr, ", %s", 13894a1a9510SRong-En Fan keyname((int) _nc_tinfo_fkeys[k].code)); 13900e3d5408SPeter Wemm } 13910e3d5408SPeter Wemm } 13920e3d5408SPeter Wemm } 13930e3d5408SPeter Wemm if (!first) 13940e3d5408SPeter Wemm fprintf(stderr, "\n"); 13950e3d5408SPeter Wemm } 13964a1a9510SRong-En Fan } 13970e3d5408SPeter Wemm 139818259542SPeter Wemm for (j = 0; j < NUM_STRINGS(tp); j++) { 139918259542SPeter Wemm char *a = tp->Strings[j]; 140018259542SPeter Wemm if (VALID_STRING(a)) 140118259542SPeter Wemm check_params(tp, ExtStrname(tp, j, strnames), a); 140218259542SPeter Wemm } 140318259542SPeter Wemm 14044a1a9510SRong-En Fan check_acs(tp); 14054a1a9510SRong-En Fan check_colors(tp); 14064a1a9510SRong-En Fan check_keypad(tp); 14070e3d5408SPeter Wemm 14080e3d5408SPeter Wemm /* 14090e3d5408SPeter Wemm * These may be mismatched because the terminal description relies on 14100e3d5408SPeter Wemm * restoring the cursor visibility by resetting it. 14110e3d5408SPeter Wemm */ 141215589c42SPeter Wemm ANDMISSING(cursor_invisible, cursor_normal); 141315589c42SPeter Wemm ANDMISSING(cursor_visible, cursor_normal); 141415589c42SPeter Wemm 141515589c42SPeter Wemm if (PRESENT(cursor_visible) && PRESENT(cursor_normal) 14164a1a9510SRong-En Fan && !_nc_capcmp(cursor_visible, cursor_normal)) 141715589c42SPeter Wemm _nc_warning("cursor_visible is same as cursor_normal"); 14180e3d5408SPeter Wemm 14190e3d5408SPeter Wemm /* 14200e3d5408SPeter Wemm * From XSI & O'Reilly, we gather that sc/rc are required if csr is 14210e3d5408SPeter Wemm * given, because the cursor position after the scrolling operation is 14220e3d5408SPeter Wemm * performed is undefined. 14230e3d5408SPeter Wemm */ 142415589c42SPeter Wemm ANDMISSING(change_scroll_region, save_cursor); 142515589c42SPeter Wemm ANDMISSING(change_scroll_region, restore_cursor); 142615589c42SPeter Wemm 142715589c42SPeter Wemm if (PRESENT(set_attributes)) { 14284a1a9510SRong-En Fan char *zero = 0; 142915589c42SPeter Wemm 14304a1a9510SRong-En Fan _nc_tparm_err = 0; 14314a1a9510SRong-En Fan if (PRESENT(exit_attribute_mode)) { 14324a1a9510SRong-En Fan zero = strdup(CHECK_SGR(0, exit_attribute_mode)); 14334a1a9510SRong-En Fan } else { 14344a1a9510SRong-En Fan zero = strdup(TPARM_9(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0)); 14354a1a9510SRong-En Fan } 14364a1a9510SRong-En Fan if (_nc_tparm_err) 14374a1a9510SRong-En Fan _nc_warning("stack error in sgr(0) string"); 14384a1a9510SRong-En Fan 14394a1a9510SRong-En Fan if (zero != 0) { 144015589c42SPeter Wemm CHECK_SGR(1, enter_standout_mode); 144115589c42SPeter Wemm CHECK_SGR(2, enter_underline_mode); 144215589c42SPeter Wemm CHECK_SGR(3, enter_reverse_mode); 144315589c42SPeter Wemm CHECK_SGR(4, enter_blink_mode); 144415589c42SPeter Wemm CHECK_SGR(5, enter_dim_mode); 144515589c42SPeter Wemm CHECK_SGR(6, enter_bold_mode); 144615589c42SPeter Wemm CHECK_SGR(7, enter_secure_mode); 144715589c42SPeter Wemm CHECK_SGR(8, enter_protected_mode); 144815589c42SPeter Wemm CHECK_SGR(9, enter_alt_charset_mode); 144915589c42SPeter Wemm free(zero); 14504a1a9510SRong-En Fan } else { 14514a1a9510SRong-En Fan _nc_warning("sgr(0) did not return a value"); 145215589c42SPeter Wemm } 14534a1a9510SRong-En Fan } else if (PRESENT(exit_attribute_mode) && 14544a1a9510SRong-En Fan set_attributes != CANCELLED_STRING) { 14554a1a9510SRong-En Fan if (_nc_syntax == SYN_TERMINFO) 14564a1a9510SRong-En Fan _nc_warning("missing sgr string"); 14574a1a9510SRong-En Fan } 14584a1a9510SRong-En Fan 14594a1a9510SRong-En Fan if (PRESENT(exit_attribute_mode)) { 14604a1a9510SRong-En Fan char *check_sgr0 = _nc_trim_sgr0(tp); 14614a1a9510SRong-En Fan 14624a1a9510SRong-En Fan if (check_sgr0 == 0 || *check_sgr0 == '\0') { 14634a1a9510SRong-En Fan _nc_warning("trimmed sgr0 is empty"); 14644a1a9510SRong-En Fan } else { 14654a1a9510SRong-En Fan show_where(2); 14664a1a9510SRong-En Fan if (check_sgr0 != exit_attribute_mode) { 14674a1a9510SRong-En Fan DEBUG(2, 14684a1a9510SRong-En Fan ("will trim sgr0\n\toriginal sgr0=%s\n\ttrimmed sgr0=%s", 14694a1a9510SRong-En Fan _nc_visbuf2(1, exit_attribute_mode), 14704a1a9510SRong-En Fan _nc_visbuf2(2, check_sgr0))); 14714a1a9510SRong-En Fan free(check_sgr0); 14724a1a9510SRong-En Fan } else { 14734a1a9510SRong-En Fan DEBUG(2, 14744a1a9510SRong-En Fan ("will not trim sgr0\n\toriginal sgr0=%s", 14754a1a9510SRong-En Fan _nc_visbuf(exit_attribute_mode))); 14764a1a9510SRong-En Fan } 14774a1a9510SRong-En Fan } 14784a1a9510SRong-En Fan } 14794a1a9510SRong-En Fan #ifdef TRACE 14804a1a9510SRong-En Fan show_where(2); 14814a1a9510SRong-En Fan if (!auto_right_margin) { 14824a1a9510SRong-En Fan DEBUG(2, 14834a1a9510SRong-En Fan ("can write to lower-right directly")); 14844a1a9510SRong-En Fan } else if (PRESENT(enter_am_mode) && PRESENT(exit_am_mode)) { 14854a1a9510SRong-En Fan DEBUG(2, 14864a1a9510SRong-En Fan ("can write to lower-right by suppressing automargin")); 14874a1a9510SRong-En Fan } else if ((PRESENT(enter_insert_mode) && PRESENT(exit_insert_mode)) 14884a1a9510SRong-En Fan || PRESENT(insert_character) || PRESENT(parm_ich)) { 14894a1a9510SRong-En Fan DEBUG(2, 14904a1a9510SRong-En Fan ("can write to lower-right by using inserts")); 14914a1a9510SRong-En Fan } else { 14924a1a9510SRong-En Fan DEBUG(2, 14934a1a9510SRong-En Fan ("cannot write to lower-right")); 14944a1a9510SRong-En Fan } 14954a1a9510SRong-En Fan #endif 14960e3d5408SPeter Wemm 14970e3d5408SPeter Wemm /* 14980e3d5408SPeter Wemm * Some standard applications (e.g., vi) and some non-curses 14994a1a9510SRong-En Fan * applications (e.g., jove) get confused if we have both ich1 and 15000e3d5408SPeter Wemm * smir/rmir. Let's be nice and warn about that, too, even though 15010e3d5408SPeter Wemm * ncurses handles it. 15020e3d5408SPeter Wemm */ 15030e3d5408SPeter Wemm if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode)) 15044a1a9510SRong-En Fan && PRESENT(parm_ich)) { 15054a1a9510SRong-En Fan _nc_warning("non-curses applications may be confused by ich1 with smir/rmir"); 15060e3d5408SPeter Wemm } 15070e3d5408SPeter Wemm 15080e3d5408SPeter Wemm /* 15090e3d5408SPeter Wemm * Finally, do the non-verbose checks 15100e3d5408SPeter Wemm */ 15110e3d5408SPeter Wemm if (save_check_termtype != 0) 15124a1a9510SRong-En Fan save_check_termtype(tp, literal); 15130e3d5408SPeter Wemm } 1514