10e3d5408SPeter Wemm /****************************************************************************
2*21817992SBaptiste Daroussin * Copyright 2018-2023,2024 Thomas E. Dickey *
3e1865124SBaptiste 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*21817992SBaptiste Daroussin MODULE_ID("$Id: tic.c,v 1.325 2024/03/02 19:33:22 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
free_namelist(char ** src)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
cleanup(void)11773f0a83dSXin LI cleanup(void)
1185d08fb1fSRong-En Fan {
1195d08fb1fSRong-En Fan #if NO_LEAKS
1205d08fb1fSRong-En Fan free_namelist(namelst);
121aae38d10SBaptiste Daroussin _nc_leaks_dump_entry();
1225d08fb1fSRong-En Fan #endif
1230e3d5408SPeter Wemm if (tmp_fp != 0)
1240e3d5408SPeter Wemm fclose(tmp_fp);
1250e3d5408SPeter Wemm if (to_remove != 0) {
126*21817992SBaptiste Daroussin int rc;
127*21817992SBaptiste Daroussin
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
failed(const char * msg)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
usage(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
write_it(ENTRY * ep)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
immedhook(ENTRY * ep GCC_UNUSED)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
put_translate(int c)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;
307*21817992SBaptiste Daroussin static size_t used;
3080e3d5408SPeter Wemm
30915589c42SPeter Wemm if (in_name) {
310*21817992SBaptiste Daroussin static size_t have;
311*21817992SBaptiste Daroussin static char *namebuf, *suffix;
312*21817992SBaptiste Daroussin
31315589c42SPeter Wemm if (used + 1 >= have) {
31415589c42SPeter Wemm have += 132;
315*21817992SBaptiste Daroussin if ((namebuf = typeRealloc(char, have, namebuf)) == NULL)
31673f0a83dSXin LI failed("put_translate namebuf");
317*21817992SBaptiste Daroussin if ((suffix = typeRealloc(char, have, suffix)) == NULL)
31873f0a83dSXin LI failed("put_translate suffix");
3190e3d5408SPeter Wemm }
32015589c42SPeter Wemm if (c == '\n' || c == '@') {
32115589c42SPeter Wemm namebuf[used++] = '\0';
3220e3d5408SPeter Wemm (void) putchar('<');
3230e3d5408SPeter Wemm (void) fputs(namebuf, stdout);
3240e3d5408SPeter Wemm putchar(c);
3250e3d5408SPeter Wemm in_name = FALSE;
32615589c42SPeter Wemm } else if (c != '>') {
3275d08fb1fSRong-En Fan namebuf[used++] = (char) c;
32815589c42SPeter Wemm } else { /* ah! candidate name! */
3290e3d5408SPeter Wemm char *up;
3300e3d5408SPeter Wemm NCURSES_CONST char *tp;
3310e3d5408SPeter Wemm
33215589c42SPeter Wemm namebuf[used++] = '\0';
3330e3d5408SPeter Wemm in_name = FALSE;
3340e3d5408SPeter Wemm
3350e3d5408SPeter Wemm suffix[0] = '\0';
3360e3d5408SPeter Wemm if ((up = strchr(namebuf, '#')) != 0
3370e3d5408SPeter Wemm || (up = strchr(namebuf, '=')) != 0
33815589c42SPeter Wemm || ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {
33973f0a83dSXin LI _nc_STRCPY(suffix, up, have);
3400e3d5408SPeter Wemm *up = '\0';
3410e3d5408SPeter Wemm }
3420e3d5408SPeter Wemm
34315589c42SPeter Wemm if ((tp = nametrans(namebuf)) != 0) {
3440e3d5408SPeter Wemm (void) putchar(':');
3450e3d5408SPeter Wemm (void) fputs(tp, stdout);
3460e3d5408SPeter Wemm (void) fputs(suffix, stdout);
3470e3d5408SPeter Wemm (void) putchar(':');
34815589c42SPeter Wemm } else {
3490e3d5408SPeter Wemm /* couldn't find a translation, just dump the name */
3500e3d5408SPeter Wemm (void) putchar('<');
3510e3d5408SPeter Wemm (void) fputs(namebuf, stdout);
3520e3d5408SPeter Wemm (void) fputs(suffix, stdout);
3530e3d5408SPeter Wemm (void) putchar('>');
3540e3d5408SPeter Wemm }
35515589c42SPeter Wemm }
35615589c42SPeter Wemm } else {
35715589c42SPeter Wemm used = 0;
35815589c42SPeter Wemm if (c == '<') {
35915589c42SPeter Wemm in_name = TRUE;
36015589c42SPeter Wemm } else {
36115589c42SPeter Wemm putchar(c);
36215589c42SPeter Wemm }
3630e3d5408SPeter Wemm }
3640e3d5408SPeter Wemm }
3650e3d5408SPeter Wemm
3660e3d5408SPeter Wemm /* Returns a string, stripped of leading/trailing whitespace */
36715589c42SPeter Wemm static char *
stripped(char * src)36815589c42SPeter Wemm stripped(char *src)
3690e3d5408SPeter Wemm {
37073f0a83dSXin LI char *dst = 0;
37173f0a83dSXin LI
37239f2269fSPeter Wemm while (isspace(UChar(*src)))
3730e3d5408SPeter Wemm src++;
37473f0a83dSXin LI
3750e3d5408SPeter Wemm if (*src != '\0') {
37673f0a83dSXin LI if ((dst = strdup(src)) == NULL) {
37706bfebdeSXin LI failed("strdup");
37873f0a83dSXin LI } else {
379*21817992SBaptiste Daroussin size_t 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 *
open_tempfile(char * filename)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)
403*21817992SBaptiste Daroussin result = safe_fopen(filename, "w");
40473f0a83dSXin LI #endif
40573f0a83dSXin LI return result;
40673f0a83dSXin LI }
40773f0a83dSXin LI
40873f0a83dSXin LI static FILE *
copy_input(FILE * source,const char * filename,char * alt_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;
413*21817992SBaptiste Daroussin FILE *target;
41473f0a83dSXin LI int ch;
41573f0a83dSXin LI
416*21817992SBaptiste Daroussin if (alt_file == NULL)
41773f0a83dSXin LI alt_file = my_altfile;
41873f0a83dSXin LI
419*21817992SBaptiste Daroussin if (source == NULL) {
42073f0a83dSXin LI failed("copy_input (source)");
421*21817992SBaptiste Daroussin } else if ((target = open_tempfile(alt_file)) == NULL) {
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 */
445*21817992SBaptiste Daroussin result = safe_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 *
open_input(const char * filename,char * alt_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);
461*21817992SBaptiste Daroussin } else if (stat(filename, &sb) == -1) {
462*21817992SBaptiste Daroussin fprintf(stderr, "%s: cannot open '%s': %s\n", _nc_progname,
463*21817992SBaptiste Daroussin filename, strerror(errno));
46473f0a83dSXin LI ExitProgram(EXIT_FAILURE);
46573f0a83dSXin LI } else if ((mode = (sb.st_mode & S_IFMT)) == S_IFDIR
466aae38d10SBaptiste Daroussin || (mode != S_IFREG && mode != S_IFCHR && mode != S_IFIFO)) {
467*21817992SBaptiste Daroussin fprintf(stderr, "%s: cannot open '%s'; it is not a file\n",
468*21817992SBaptiste Daroussin _nc_progname, filename);
46973f0a83dSXin LI ExitProgram(EXIT_FAILURE);
47073f0a83dSXin LI } else {
471*21817992SBaptiste Daroussin fp = safe_fopen(filename, "r");
47218259542SPeter Wemm
473*21817992SBaptiste Daroussin if (fp == NULL) {
474*21817992SBaptiste Daroussin fprintf(stderr, "%s: cannot open '%s': %s\n", _nc_progname,
475*21817992SBaptiste Daroussin filename, strerror(errno));
4764a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE);
47718259542SPeter Wemm }
47873f0a83dSXin LI if (mode != S_IFREG) {
47973f0a83dSXin LI if (alt_file != 0) {
48073f0a83dSXin LI FILE *fp2 = copy_input(fp, filename, alt_file);
48173f0a83dSXin LI fp = fp2;
48273f0a83dSXin LI } else {
483*21817992SBaptiste Daroussin fprintf(stderr, "%s: cannot open '%s'; it is not a"
484*21817992SBaptiste Daroussin " file\n", _nc_progname, filename);
4854a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE);
48618259542SPeter Wemm }
48773f0a83dSXin LI }
48873f0a83dSXin LI }
48918259542SPeter Wemm return fp;
49018259542SPeter Wemm }
49118259542SPeter Wemm
4920e3d5408SPeter Wemm /* Parse the "-e" option-value into a list of names */
4935ca44d1cSRong-En Fan static char **
make_namelist(char * src)49415589c42SPeter Wemm make_namelist(char *src)
4950e3d5408SPeter Wemm {
4965ca44d1cSRong-En Fan char **dst = 0;
4970e3d5408SPeter Wemm
4980e3d5408SPeter Wemm char *s, *base;
4990e3d5408SPeter Wemm unsigned pass, n, nn;
5000e3d5408SPeter Wemm char buffer[BUFSIZ];
5010e3d5408SPeter Wemm
502*21817992SBaptiste Daroussin if (src == NULL) {
5030e3d5408SPeter Wemm /* EMPTY */ ;
5040e3d5408SPeter Wemm } else if (strchr(src, '/') != 0) { /* a filename */
50573f0a83dSXin LI FILE *fp = open_input(src, (char *) 0);
5060e3d5408SPeter Wemm
5070e3d5408SPeter Wemm for (pass = 1; pass <= 2; pass++) {
5080e3d5408SPeter Wemm nn = 0;
5090e3d5408SPeter Wemm while (fgets(buffer, sizeof(buffer), fp) != 0) {
5100e3d5408SPeter Wemm if ((s = stripped(buffer)) != 0) {
5110e3d5408SPeter Wemm if (dst != 0)
5120e3d5408SPeter Wemm dst[nn] = s;
5135ca44d1cSRong-En Fan else
5145ca44d1cSRong-En Fan free(s);
5150e3d5408SPeter Wemm nn++;
5160e3d5408SPeter Wemm }
5170e3d5408SPeter Wemm }
5180e3d5408SPeter Wemm if (pass == 1) {
519*21817992SBaptiste Daroussin if ((dst = typeCalloc(char *, nn + 1)) == NULL)
52073f0a83dSXin LI failed("make_namelist");
5210e3d5408SPeter Wemm rewind(fp);
5220e3d5408SPeter Wemm }
5230e3d5408SPeter Wemm }
5240e3d5408SPeter Wemm fclose(fp);
5250e3d5408SPeter Wemm } else { /* literal list of names */
5260e3d5408SPeter Wemm for (pass = 1; pass <= 2; pass++) {
5270e3d5408SPeter Wemm for (n = nn = 0, base = src;; n++) {
5280e3d5408SPeter Wemm int mark = src[n];
5290e3d5408SPeter Wemm if (mark == ',' || mark == '\0') {
5300e3d5408SPeter Wemm if (pass == 1) {
5310e3d5408SPeter Wemm nn++;
5320e3d5408SPeter Wemm } else {
5330e3d5408SPeter Wemm src[n] = '\0';
5340e3d5408SPeter Wemm if ((s = stripped(base)) != 0)
5350e3d5408SPeter Wemm dst[nn++] = s;
5360e3d5408SPeter Wemm base = &src[n + 1];
5370e3d5408SPeter Wemm }
5380e3d5408SPeter Wemm }
5390e3d5408SPeter Wemm if (mark == '\0')
5400e3d5408SPeter Wemm break;
5410e3d5408SPeter Wemm }
54273f0a83dSXin LI if (pass == 1) {
543*21817992SBaptiste Daroussin if ((dst = typeCalloc(char *, nn + 1)) == NULL)
54473f0a83dSXin LI failed("make_namelist");
54573f0a83dSXin LI }
5460e3d5408SPeter Wemm }
5470e3d5408SPeter Wemm }
5485ca44d1cSRong-En Fan if (showsummary && (dst != 0)) {
5490e3d5408SPeter Wemm fprintf(log_fp, "Entries that will be compiled:\n");
5500e3d5408SPeter Wemm for (n = 0; dst[n] != 0; n++)
5514a1a9510SRong-En Fan fprintf(log_fp, "%u:%s\n", n + 1, dst[n]);
5520e3d5408SPeter Wemm }
5530e3d5408SPeter Wemm return dst;
5540e3d5408SPeter Wemm }
5550e3d5408SPeter Wemm
55615589c42SPeter Wemm static bool
matches(char ** needle,const char * haystack)5575ca44d1cSRong-En Fan matches(char **needle, const char *haystack)
5580e3d5408SPeter Wemm /* does entry in needle list match |-separated field in haystack? */
5590e3d5408SPeter Wemm {
5600e3d5408SPeter Wemm bool code = FALSE;
5610e3d5408SPeter Wemm
56215589c42SPeter Wemm if (needle != 0) {
563*21817992SBaptiste Daroussin size_t n;
564*21817992SBaptiste Daroussin
56515589c42SPeter Wemm for (n = 0; needle[n] != 0; n++) {
56615589c42SPeter Wemm if (_nc_name_match(haystack, needle[n], "|")) {
5670e3d5408SPeter Wemm code = TRUE;
5680e3d5408SPeter Wemm break;
5690e3d5408SPeter Wemm }
5700e3d5408SPeter Wemm }
57115589c42SPeter Wemm } else
5720e3d5408SPeter Wemm code = TRUE;
5730e3d5408SPeter Wemm return (code);
5740e3d5408SPeter Wemm }
5750e3d5408SPeter Wemm
57673f0a83dSXin LI static char *
valid_db_path(const char * nominal)57773f0a83dSXin LI valid_db_path(const char *nominal)
57815589c42SPeter Wemm {
57973f0a83dSXin LI struct stat sb;
58073f0a83dSXin LI #if USE_HASHED_DB
58173f0a83dSXin LI char suffix[] = DBM_SUFFIX;
58273f0a83dSXin LI size_t need = strlen(nominal) + sizeof(suffix);
58373f0a83dSXin LI char *result = malloc(need);
58473f0a83dSXin LI
585*21817992SBaptiste Daroussin if (result == NULL)
58673f0a83dSXin LI failed("valid_db_path");
58773f0a83dSXin LI _nc_STRCPY(result, nominal, need);
58873f0a83dSXin LI if (strcmp(result + need - sizeof(suffix), suffix)) {
58973f0a83dSXin LI _nc_STRCAT(result, suffix, need);
59073f0a83dSXin LI }
59115589c42SPeter Wemm #else
59273f0a83dSXin LI char *result = strdup(nominal);
59315589c42SPeter Wemm #endif
59473f0a83dSXin LI
59573f0a83dSXin LI DEBUG(1, ("** stat(%s)", result));
59673f0a83dSXin LI if (stat(result, &sb) >= 0) {
59773f0a83dSXin LI #if USE_HASHED_DB
59873f0a83dSXin LI if (!S_ISREG(sb.st_mode)
59973f0a83dSXin LI || access(result, R_OK | W_OK) != 0) {
60073f0a83dSXin LI DEBUG(1, ("...not a writable file"));
60173f0a83dSXin LI free(result);
60273f0a83dSXin LI result = 0;
60373f0a83dSXin LI }
60473f0a83dSXin LI #else
60573f0a83dSXin LI if (!S_ISDIR(sb.st_mode)
60673f0a83dSXin LI || access(result, R_OK | W_OK | X_OK) != 0) {
60773f0a83dSXin LI DEBUG(1, ("...not a writable directory"));
60873f0a83dSXin LI free(result);
60973f0a83dSXin LI result = 0;
61073f0a83dSXin LI }
61173f0a83dSXin LI #endif
61273f0a83dSXin LI } else {
61373f0a83dSXin LI /* check if parent is directory and is writable */
61473f0a83dSXin LI unsigned leaf = _nc_pathlast(result);
61573f0a83dSXin LI
61673f0a83dSXin LI DEBUG(1, ("...not found"));
61773f0a83dSXin LI if (leaf) {
61873f0a83dSXin LI char save = result[leaf];
61973f0a83dSXin LI result[leaf] = 0;
62073f0a83dSXin LI if (stat(result, &sb) >= 0
62173f0a83dSXin LI && S_ISDIR(sb.st_mode)
62273f0a83dSXin LI && access(result, R_OK | W_OK | X_OK) == 0) {
62373f0a83dSXin LI result[leaf] = save;
62473f0a83dSXin LI } else {
62573f0a83dSXin LI DEBUG(1, ("...parent directory %s is not writable", result));
62673f0a83dSXin LI free(result);
62773f0a83dSXin LI result = 0;
62873f0a83dSXin LI }
62973f0a83dSXin LI } else {
63073f0a83dSXin LI DEBUG(1, ("... no parent directory"));
63173f0a83dSXin LI free(result);
63273f0a83dSXin LI result = 0;
63373f0a83dSXin LI }
63473f0a83dSXin LI }
63515589c42SPeter Wemm return result;
63615589c42SPeter Wemm }
63715589c42SPeter Wemm
63873f0a83dSXin LI /*
63973f0a83dSXin LI * Show the databases to which tic could write. The location to which it
64073f0a83dSXin LI * writes is always the first one. If none are writable, print an error
64173f0a83dSXin LI * message.
64273f0a83dSXin LI */
64373f0a83dSXin LI static void
show_databases(const char * outdir)64473f0a83dSXin LI show_databases(const char *outdir)
64573f0a83dSXin LI {
64673f0a83dSXin LI bool specific = (outdir != 0) || getenv("TERMINFO") != 0;
64773f0a83dSXin LI char *result;
64873f0a83dSXin LI const char *tried = 0;
64973f0a83dSXin LI
650*21817992SBaptiste Daroussin if (outdir == NULL) {
651*21817992SBaptiste Daroussin outdir = _nc_tic_dir(NULL);
65273f0a83dSXin LI }
65373f0a83dSXin LI if ((result = valid_db_path(outdir)) != 0) {
65473f0a83dSXin LI printf("%s\n", result);
65573f0a83dSXin LI free(result);
65673f0a83dSXin LI } else {
65773f0a83dSXin LI tried = outdir;
65873f0a83dSXin LI }
65973f0a83dSXin LI
66073f0a83dSXin LI if ((outdir = _nc_home_terminfo())) {
66173f0a83dSXin LI if ((result = valid_db_path(outdir)) != 0) {
66273f0a83dSXin LI printf("%s\n", result);
66373f0a83dSXin LI free(result);
66473f0a83dSXin LI } else if (!specific) {
66573f0a83dSXin LI tried = outdir;
66673f0a83dSXin LI }
66773f0a83dSXin LI }
66873f0a83dSXin LI
66973f0a83dSXin LI /*
67073f0a83dSXin LI * If we can write in neither location, give an error message.
67173f0a83dSXin LI */
67273f0a83dSXin LI if (tried) {
67373f0a83dSXin LI fflush(stdout);
67473f0a83dSXin LI fprintf(stderr, "%s: %s (no permission)\n", _nc_progname, tried);
67573f0a83dSXin LI ExitProgram(EXIT_FAILURE);
67673f0a83dSXin LI }
67773f0a83dSXin LI }
67873f0a83dSXin LI
679aae38d10SBaptiste Daroussin static void
add_digit(int * target,int source)680aae38d10SBaptiste Daroussin add_digit(int *target, int source)
681aae38d10SBaptiste Daroussin {
682aae38d10SBaptiste Daroussin *target = (*target * 10) + (source - '0');
683aae38d10SBaptiste Daroussin }
68473f0a83dSXin LI
68515589c42SPeter Wemm int
main(int argc,char * argv[])68615589c42SPeter Wemm main(int argc, char *argv[])
6870e3d5408SPeter Wemm {
6880e3d5408SPeter Wemm char my_tmpname[PATH_MAX];
68973f0a83dSXin LI int v_opt = -1;
6900e3d5408SPeter Wemm int smart_defaults = TRUE;
6910e3d5408SPeter Wemm char *termcap;
6920e3d5408SPeter Wemm ENTRY *qp;
6930e3d5408SPeter Wemm
6940e3d5408SPeter Wemm int this_opt, last_opt = '?';
6950e3d5408SPeter Wemm
6960e3d5408SPeter Wemm int outform = F_TERMINFO; /* output format */
6970e3d5408SPeter Wemm int sortmode = S_TERMINFO; /* sort_mode */
6980e3d5408SPeter Wemm
6990e3d5408SPeter Wemm int width = 60;
70073f0a83dSXin LI int height = 65535;
7010e3d5408SPeter Wemm bool formatted = FALSE; /* reformat complex strings? */
7024a1a9510SRong-En Fan bool literal = FALSE; /* suppress post-processing? */
7030e3d5408SPeter Wemm int numbers = 0; /* format "%'char'" to/from "%{number}" */
7040e3d5408SPeter Wemm bool forceresolve = FALSE; /* force resolution */
7050e3d5408SPeter Wemm bool limited = TRUE;
7060e3d5408SPeter Wemm char *tversion = (char *) NULL;
707*21817992SBaptiste Daroussin const char *source_file;
7080e3d5408SPeter Wemm char *outdir = (char *) NULL;
7090e3d5408SPeter Wemm bool check_only = FALSE;
7104a1a9510SRong-En Fan bool suppress_untranslatable = FALSE;
711aae38d10SBaptiste Daroussin int quickdump = 0;
712aae38d10SBaptiste Daroussin bool quiet = FALSE;
713aae38d10SBaptiste Daroussin bool wrap_strings = FALSE;
7140e3d5408SPeter Wemm
7150e3d5408SPeter Wemm log_fp = stderr;
7160e3d5408SPeter Wemm
71739f2269fSPeter Wemm _nc_progname = _nc_rootname(argv[0]);
71873f0a83dSXin LI atexit(cleanup);
7190e3d5408SPeter Wemm
72006bfebdeSXin LI if ((infodump = same_program(_nc_progname, PROG_CAPTOINFO)) != FALSE) {
72115589c42SPeter Wemm outform = F_TERMINFO;
72215589c42SPeter Wemm sortmode = S_TERMINFO;
72315589c42SPeter Wemm }
72406bfebdeSXin LI if ((capdump = same_program(_nc_progname, PROG_INFOTOCAP)) != FALSE) {
72515589c42SPeter Wemm outform = F_TERMCAP;
72615589c42SPeter Wemm sortmode = S_TERMCAP;
72715589c42SPeter Wemm }
7280e3d5408SPeter Wemm #if NCURSES_XNAMES
729*21817992SBaptiste Daroussin /* set this directly to avoid interaction with -v and -D options */
730*21817992SBaptiste Daroussin _nc_user_definable = FALSE;
7310e3d5408SPeter Wemm #endif
73273f0a83dSXin LI _nc_strict_bsd = 0;
7330e3d5408SPeter Wemm
7340e3d5408SPeter Wemm /*
7350e3d5408SPeter Wemm * Processing arguments is a little complicated, since someone made a
7360e3d5408SPeter Wemm * design decision to allow the numeric values for -w, -v options to
7370e3d5408SPeter Wemm * be optional.
7380e3d5408SPeter Wemm */
73915589c42SPeter Wemm while ((this_opt = getopt(argc, argv,
740aae38d10SBaptiste Daroussin "0123456789CDIKLNQR:TUVWace:fGgo:qrstvwx")) != -1) {
7410e3d5408SPeter Wemm if (isdigit(this_opt)) {
7420e3d5408SPeter Wemm switch (last_opt) {
743aae38d10SBaptiste Daroussin case 'Q':
744aae38d10SBaptiste Daroussin add_digit(&quickdump, this_opt);
745aae38d10SBaptiste Daroussin break;
7460e3d5408SPeter Wemm case 'v':
747aae38d10SBaptiste Daroussin add_digit(&v_opt, this_opt);
7480e3d5408SPeter Wemm break;
7490e3d5408SPeter Wemm case 'w':
750aae38d10SBaptiste Daroussin add_digit(&width, this_opt);
7510e3d5408SPeter Wemm break;
7520e3d5408SPeter Wemm default:
75373f0a83dSXin LI switch (this_opt) {
75473f0a83dSXin LI case '0':
75573f0a83dSXin LI last_opt = this_opt;
75673f0a83dSXin LI width = 65535;
75773f0a83dSXin LI height = 1;
75873f0a83dSXin LI break;
75973f0a83dSXin LI case '1':
7600e3d5408SPeter Wemm last_opt = this_opt;
7610e3d5408SPeter Wemm width = 0;
76273f0a83dSXin LI break;
76373f0a83dSXin LI default:
76473f0a83dSXin LI usage();
76573f0a83dSXin LI }
7660e3d5408SPeter Wemm }
7670e3d5408SPeter Wemm continue;
7680e3d5408SPeter Wemm }
7690e3d5408SPeter Wemm switch (this_opt) {
77073f0a83dSXin LI case 'K':
77173f0a83dSXin LI _nc_strict_bsd = 1;
77273f0a83dSXin LI /* the initial version of -K in 20110730 fell-thru here, but the
77373f0a83dSXin LI * same flag is useful when reading sources -TD
77473f0a83dSXin LI */
77573f0a83dSXin LI break;
7760e3d5408SPeter Wemm case 'C':
7770e3d5408SPeter Wemm capdump = TRUE;
7780e3d5408SPeter Wemm outform = F_TERMCAP;
7790e3d5408SPeter Wemm sortmode = S_TERMCAP;
7800e3d5408SPeter Wemm break;
78173f0a83dSXin LI case 'D':
78273f0a83dSXin LI debug_level = VtoTrace(v_opt);
783*21817992SBaptiste Daroussin use_verbosity(debug_level);
78473f0a83dSXin LI show_databases(outdir);
78573f0a83dSXin LI ExitProgram(EXIT_SUCCESS);
78673f0a83dSXin LI break;
7870e3d5408SPeter Wemm case 'I':
7880e3d5408SPeter Wemm infodump = TRUE;
7890e3d5408SPeter Wemm outform = F_TERMINFO;
7900e3d5408SPeter Wemm sortmode = S_TERMINFO;
7910e3d5408SPeter Wemm break;
7920e3d5408SPeter Wemm case 'L':
7930e3d5408SPeter Wemm infodump = TRUE;
7940e3d5408SPeter Wemm outform = F_VARIABLE;
7950e3d5408SPeter Wemm sortmode = S_VARIABLE;
7960e3d5408SPeter Wemm break;
7970e3d5408SPeter Wemm case 'N':
7980e3d5408SPeter Wemm smart_defaults = FALSE;
7994a1a9510SRong-En Fan literal = TRUE;
8000e3d5408SPeter Wemm break;
801aae38d10SBaptiste Daroussin case 'Q':
802aae38d10SBaptiste Daroussin quickdump = 0;
803aae38d10SBaptiste Daroussin break;
8040e3d5408SPeter Wemm case 'R':
8050e3d5408SPeter Wemm tversion = optarg;
8060e3d5408SPeter Wemm break;
8070e3d5408SPeter Wemm case 'T':
8080e3d5408SPeter Wemm limited = FALSE;
8090e3d5408SPeter Wemm break;
8104a1a9510SRong-En Fan case 'U':
8114a1a9510SRong-En Fan literal = TRUE;
8124a1a9510SRong-En Fan break;
8130e3d5408SPeter Wemm case 'V':
81418259542SPeter Wemm puts(curses_version());
8155d08fb1fSRong-En Fan ExitProgram(EXIT_SUCCESS);
816aae38d10SBaptiste Daroussin case 'W':
817aae38d10SBaptiste Daroussin wrap_strings = TRUE;
818aae38d10SBaptiste Daroussin break;
8190e3d5408SPeter Wemm case 'c':
8200e3d5408SPeter Wemm check_only = TRUE;
8210e3d5408SPeter Wemm break;
8220e3d5408SPeter Wemm case 'e':
8230e3d5408SPeter Wemm namelst = make_namelist(optarg);
8240e3d5408SPeter Wemm break;
8250e3d5408SPeter Wemm case 'f':
8260e3d5408SPeter Wemm formatted = TRUE;
8270e3d5408SPeter Wemm break;
8280e3d5408SPeter Wemm case 'G':
8290e3d5408SPeter Wemm numbers = 1;
8300e3d5408SPeter Wemm break;
8310e3d5408SPeter Wemm case 'g':
8320e3d5408SPeter Wemm numbers = -1;
8330e3d5408SPeter Wemm break;
8340e3d5408SPeter Wemm case 'o':
8350e3d5408SPeter Wemm outdir = optarg;
8360e3d5408SPeter Wemm break;
837aae38d10SBaptiste Daroussin case 'q':
838aae38d10SBaptiste Daroussin quiet = TRUE;
839aae38d10SBaptiste Daroussin break;
8400e3d5408SPeter Wemm case 'r':
8410e3d5408SPeter Wemm forceresolve = TRUE;
8420e3d5408SPeter Wemm break;
8430e3d5408SPeter Wemm case 's':
8440e3d5408SPeter Wemm showsummary = TRUE;
8450e3d5408SPeter Wemm break;
8460e3d5408SPeter Wemm case 'v':
8470e3d5408SPeter Wemm v_opt = 0;
8480e3d5408SPeter Wemm break;
8490e3d5408SPeter Wemm case 'w':
8500e3d5408SPeter Wemm width = 0;
8510e3d5408SPeter Wemm break;
8520e3d5408SPeter Wemm #if NCURSES_XNAMES
8534a1a9510SRong-En Fan case 't':
8544a1a9510SRong-En Fan _nc_disable_period = FALSE;
8554a1a9510SRong-En Fan suppress_untranslatable = TRUE;
8564a1a9510SRong-En Fan break;
85715589c42SPeter Wemm case 'a':
85815589c42SPeter Wemm _nc_disable_period = TRUE;
85915589c42SPeter Wemm /* FALLTHRU */
8600e3d5408SPeter Wemm case 'x':
861aae38d10SBaptiste Daroussin using_extensions = TRUE;
8620e3d5408SPeter Wemm break;
8630e3d5408SPeter Wemm #endif
8640e3d5408SPeter Wemm default:
8650e3d5408SPeter Wemm usage();
8660e3d5408SPeter Wemm }
8670e3d5408SPeter Wemm last_opt = this_opt;
8680e3d5408SPeter Wemm }
8690e3d5408SPeter Wemm
870*21817992SBaptiste Daroussin /*
871*21817992SBaptiste Daroussin * If the -v option is set, it may override the $NCURSES_TRACE environment
872*21817992SBaptiste Daroussin * variable, e.g., for -v3 and up.
873*21817992SBaptiste Daroussin */
87473f0a83dSXin LI debug_level = VtoTrace(v_opt);
875*21817992SBaptiste Daroussin use_verbosity(debug_level);
876*21817992SBaptiste Daroussin
877*21817992SBaptiste Daroussin /*
878*21817992SBaptiste Daroussin * Do this after setting debug_level, since the function calls START_TRACE,
879*21817992SBaptiste Daroussin * which uses the $NCURSES_TRACE environment variable if _nc_tracing bits
880*21817992SBaptiste Daroussin * for tracing are zero.
881*21817992SBaptiste Daroussin */
882*21817992SBaptiste Daroussin #if NCURSES_XNAMES
883*21817992SBaptiste Daroussin if (using_extensions) {
884*21817992SBaptiste Daroussin use_extended_names(TRUE);
885*21817992SBaptiste Daroussin }
886*21817992SBaptiste Daroussin #endif
8870e3d5408SPeter Wemm
88815589c42SPeter Wemm if (_nc_tracing) {
8894a1a9510SRong-En Fan save_check_termtype = _nc_check_termtype2;
8904a1a9510SRong-En Fan _nc_check_termtype2 = check_termtype;
8910e3d5408SPeter Wemm }
89218259542SPeter Wemm #if !HAVE_BIG_CORE
8930e3d5408SPeter Wemm /*
8940e3d5408SPeter Wemm * Aaargh! immedhook seriously hoses us!
8950e3d5408SPeter Wemm *
8960e3d5408SPeter Wemm * One problem with immedhook is it means we can't do -e. Problem
8970e3d5408SPeter Wemm * is that we can't guarantee that for each terminal listed, all the
8980e3d5408SPeter Wemm * terminals it depends on will have been kept in core for reference
899*21817992SBaptiste Daroussin * resolution -- in fact it is certain the primitive types at the end
9000e3d5408SPeter Wemm * of reference chains *won't* be in core unless they were explicitly
9010e3d5408SPeter Wemm * in the select list themselves.
9020e3d5408SPeter Wemm */
90315589c42SPeter Wemm if (namelst && (!infodump && !capdump)) {
9040e3d5408SPeter Wemm (void) fprintf(stderr,
90573f0a83dSXin LI "%s: Sorry, -e can't be used without -I or -C\n",
90673f0a83dSXin LI _nc_progname);
9074a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE);
9080e3d5408SPeter Wemm }
9090e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
9100e3d5408SPeter Wemm
9110e3d5408SPeter Wemm if (optind < argc) {
9120e3d5408SPeter Wemm source_file = argv[optind++];
9130e3d5408SPeter Wemm if (optind < argc) {
9140e3d5408SPeter Wemm fprintf(stderr,
9150e3d5408SPeter Wemm "%s: Too many file names. Usage:\n\t%s %s",
9160e3d5408SPeter Wemm _nc_progname,
9170e3d5408SPeter Wemm _nc_progname,
9180e3d5408SPeter Wemm usage_string);
9194a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE);
9200e3d5408SPeter Wemm }
9210e3d5408SPeter Wemm } else {
9220e3d5408SPeter Wemm if (infodump == TRUE) {
9230e3d5408SPeter Wemm /* captoinfo's no-argument case */
9240e3d5408SPeter Wemm source_file = "/etc/termcap";
9250e3d5408SPeter Wemm if ((termcap = getenv("TERMCAP")) != 0
9260e3d5408SPeter Wemm && (namelst = make_namelist(getenv("TERM"))) != 0) {
9270e3d5408SPeter Wemm if (access(termcap, F_OK) == 0) {
9280e3d5408SPeter Wemm /* file exists */
9290e3d5408SPeter Wemm source_file = termcap;
93073f0a83dSXin LI } else {
93173f0a83dSXin LI if ((tmp_fp = open_tempfile(my_tmpname)) != 0) {
93215589c42SPeter Wemm source_file = my_tmpname;
9330e3d5408SPeter Wemm fprintf(tmp_fp, "%s\n", termcap);
9340e3d5408SPeter Wemm fclose(tmp_fp);
93573f0a83dSXin LI tmp_fp = open_input(source_file, (char *) 0);
9360e3d5408SPeter Wemm to_remove = source_file;
9370e3d5408SPeter Wemm } else {
9380e3d5408SPeter Wemm failed("tmpnam");
9390e3d5408SPeter Wemm }
9400e3d5408SPeter Wemm }
94173f0a83dSXin LI }
9420e3d5408SPeter Wemm } else {
9430e3d5408SPeter Wemm /* tic */
9440e3d5408SPeter Wemm fprintf(stderr,
9450e3d5408SPeter Wemm "%s: File name needed. Usage:\n\t%s %s",
9460e3d5408SPeter Wemm _nc_progname,
9470e3d5408SPeter Wemm _nc_progname,
9480e3d5408SPeter Wemm usage_string);
9494a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE);
9500e3d5408SPeter Wemm }
9510e3d5408SPeter Wemm }
9520e3d5408SPeter Wemm
953*21817992SBaptiste Daroussin if (tmp_fp == NULL) {
954*21817992SBaptiste Daroussin char my_altfile[PATH_MAX];
95573f0a83dSXin LI tmp_fp = open_input(source_file, my_altfile);
95673f0a83dSXin LI if (!strcmp(source_file, "-")) {
95773f0a83dSXin LI source_file = STDIN_NAME;
95873f0a83dSXin LI }
95973f0a83dSXin LI }
9600e3d5408SPeter Wemm
961aae38d10SBaptiste Daroussin if (infodump || check_only) {
9620e3d5408SPeter Wemm dump_init(tversion,
963aae38d10SBaptiste Daroussin (smart_defaults
9640e3d5408SPeter Wemm ? outform
965aae38d10SBaptiste Daroussin : F_LITERAL),
966aae38d10SBaptiste Daroussin sortmode,
967aae38d10SBaptiste Daroussin wrap_strings, width, height,
968aae38d10SBaptiste Daroussin debug_level, formatted || check_only, check_only, quickdump);
96973f0a83dSXin LI } else if (capdump) {
9700e3d5408SPeter Wemm dump_init(tversion,
9710e3d5408SPeter Wemm outform,
972aae38d10SBaptiste Daroussin sortmode,
973aae38d10SBaptiste Daroussin wrap_strings, width, height,
974aae38d10SBaptiste Daroussin debug_level, FALSE, FALSE, FALSE);
97573f0a83dSXin LI }
9760e3d5408SPeter Wemm
9770e3d5408SPeter Wemm /* parse entries out of the source file */
9780e3d5408SPeter Wemm _nc_set_source(source_file);
97918259542SPeter Wemm #if !HAVE_BIG_CORE
9800e3d5408SPeter Wemm if (!(check_only || infodump || capdump))
9810e3d5408SPeter Wemm _nc_set_writedir(outdir);
9820e3d5408SPeter Wemm #endif /* HAVE_BIG_CORE */
9830e3d5408SPeter Wemm _nc_read_entry_source(tmp_fp, (char *) NULL,
9844a1a9510SRong-En Fan !smart_defaults || literal, FALSE,
9854a1a9510SRong-En Fan ((check_only || infodump || capdump)
9864a1a9510SRong-En Fan ? NULLHOOK
9874a1a9510SRong-En Fan : immedhook));
9880e3d5408SPeter Wemm
9890e3d5408SPeter Wemm /* do use resolution */
9900e3d5408SPeter Wemm if (check_only || (!infodump && !capdump) || forceresolve) {
9914a1a9510SRong-En Fan if (!_nc_resolve_uses2(TRUE, literal) && !check_only) {
9924a1a9510SRong-En Fan ExitProgram(EXIT_FAILURE);
9930e3d5408SPeter Wemm }
9940e3d5408SPeter Wemm }
9950e3d5408SPeter Wemm
9960e3d5408SPeter Wemm /* length check */
997aae38d10SBaptiste Daroussin if (check_only && limited && (capdump || infodump)) {
99815589c42SPeter Wemm for_entry_list(qp) {
99915589c42SPeter Wemm if (matches(namelst, qp->tterm.term_names)) {
10004a1a9510SRong-En Fan int len = fmt_entry(&qp->tterm, NULL, FALSE, TRUE, infodump, numbers);
10010e3d5408SPeter Wemm
10020e3d5408SPeter Wemm if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))
10030e3d5408SPeter Wemm (void) fprintf(stderr,
1004aae38d10SBaptiste Daroussin "%s: resolved %s entry is %d bytes long\n",
1005aae38d10SBaptiste Daroussin _nc_progname,
10060e3d5408SPeter Wemm _nc_first_name(qp->tterm.term_names),
10070e3d5408SPeter Wemm len);
10080e3d5408SPeter Wemm }
10090e3d5408SPeter Wemm }
10100e3d5408SPeter Wemm }
10110e3d5408SPeter Wemm
10120e3d5408SPeter Wemm /* write or dump all entries */
1013aae38d10SBaptiste Daroussin if (check_only) {
1014aae38d10SBaptiste Daroussin /* this is in case infotocap() generates warnings */
1015aae38d10SBaptiste Daroussin _nc_curr_col = _nc_curr_line = -1;
1016aae38d10SBaptiste Daroussin
1017aae38d10SBaptiste Daroussin for_entry_list(qp) {
1018aae38d10SBaptiste Daroussin if (matches(namelst, qp->tterm.term_names)) {
1019aae38d10SBaptiste Daroussin /* this is in case infotocap() generates warnings */
1020aae38d10SBaptiste Daroussin _nc_set_type(_nc_first_name(qp->tterm.term_names));
1021aae38d10SBaptiste Daroussin _nc_curr_line = (int) qp->startline;
1022aae38d10SBaptiste Daroussin repair_acsc(&qp->tterm);
1023aae38d10SBaptiste Daroussin dump_entry(&qp->tterm, suppress_untranslatable,
1024aae38d10SBaptiste Daroussin limited, numbers, NULL);
1025aae38d10SBaptiste Daroussin }
1026aae38d10SBaptiste Daroussin }
1027aae38d10SBaptiste Daroussin } else {
102815589c42SPeter Wemm if (!infodump && !capdump) {
10290e3d5408SPeter Wemm _nc_set_writedir(outdir);
103015589c42SPeter Wemm for_entry_list(qp) {
10310e3d5408SPeter Wemm if (matches(namelst, qp->tterm.term_names))
10320e3d5408SPeter Wemm write_it(qp);
10330e3d5408SPeter Wemm }
103415589c42SPeter Wemm } else {
10350e3d5408SPeter Wemm /* this is in case infotocap() generates warnings */
10360e3d5408SPeter Wemm _nc_curr_col = _nc_curr_line = -1;
10370e3d5408SPeter Wemm
103815589c42SPeter Wemm for_entry_list(qp) {
103915589c42SPeter Wemm if (matches(namelst, qp->tterm.term_names)) {
104073f0a83dSXin LI long j = qp->cend - qp->cstart;
10410e3d5408SPeter Wemm int len = 0;
10420e3d5408SPeter Wemm
10430e3d5408SPeter Wemm /* this is in case infotocap() generates warnings */
10440e3d5408SPeter Wemm _nc_set_type(_nc_first_name(qp->tterm.term_names));
10450e3d5408SPeter Wemm
1046aae38d10SBaptiste Daroussin if (!quiet) {
10470e3d5408SPeter Wemm (void) fseek(tmp_fp, qp->cstart, SEEK_SET);
10484a1a9510SRong-En Fan while (j-- > 0) {
1049aae38d10SBaptiste Daroussin int ch = fgetc(tmp_fp);
1050aae38d10SBaptiste Daroussin if (ch == EOF || ferror(tmp_fp)) {
1051aae38d10SBaptiste Daroussin break;
1052aae38d10SBaptiste Daroussin } else if (infodump) {
1053aae38d10SBaptiste Daroussin (void) putchar(ch);
1054aae38d10SBaptiste Daroussin } else {
1055aae38d10SBaptiste Daroussin put_translate(ch);
1056aae38d10SBaptiste Daroussin }
1057aae38d10SBaptiste Daroussin }
105815589c42SPeter Wemm }
10590e3d5408SPeter Wemm
106006bfebdeSXin LI repair_acsc(&qp->tterm);
10614a1a9510SRong-En Fan dump_entry(&qp->tterm, suppress_untranslatable,
10624a1a9510SRong-En Fan limited, numbers, NULL);
106373f0a83dSXin LI for (j = 0; j < (long) qp->nuses; j++)
10644a1a9510SRong-En Fan dump_uses(qp->uses[j].name, !capdump);
10654a1a9510SRong-En Fan len = show_entry();
10660e3d5408SPeter Wemm if (debug_level != 0 && !limited)
10670e3d5408SPeter Wemm printf("# length=%d\n", len);
10680e3d5408SPeter Wemm }
106915589c42SPeter Wemm }
1070aae38d10SBaptiste Daroussin if (!namelst && _nc_tail && !quiet) {
10710e3d5408SPeter Wemm int c, oldc = '\0';
10720e3d5408SPeter Wemm bool in_comment = FALSE;
10730e3d5408SPeter Wemm bool trailing_comment = FALSE;
10740e3d5408SPeter Wemm
10750e3d5408SPeter Wemm (void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET);
107615589c42SPeter Wemm while ((c = fgetc(tmp_fp)) != EOF) {
10770e3d5408SPeter Wemm if (oldc == '\n') {
10780e3d5408SPeter Wemm if (c == '#') {
10790e3d5408SPeter Wemm trailing_comment = TRUE;
10800e3d5408SPeter Wemm in_comment = TRUE;
10810e3d5408SPeter Wemm } else {
10820e3d5408SPeter Wemm in_comment = FALSE;
10830e3d5408SPeter Wemm }
10840e3d5408SPeter Wemm }
10850e3d5408SPeter Wemm if (trailing_comment
10860e3d5408SPeter Wemm && (in_comment || (oldc == '\n' && c == '\n')))
10870e3d5408SPeter Wemm putchar(c);
10880e3d5408SPeter Wemm oldc = c;
10890e3d5408SPeter Wemm }
10900e3d5408SPeter Wemm }
10910e3d5408SPeter Wemm }
10920e3d5408SPeter Wemm }
10930e3d5408SPeter Wemm
10940e3d5408SPeter Wemm /* Show the directory into which entries were written, and the total
10950e3d5408SPeter Wemm * number of entries
10960e3d5408SPeter Wemm */
10970e3d5408SPeter Wemm if (showsummary
10980e3d5408SPeter Wemm && (!(check_only || infodump || capdump))) {
10990e3d5408SPeter Wemm int total = _nc_tic_written();
11000e3d5408SPeter Wemm if (total != 0)
11010e3d5408SPeter Wemm fprintf(log_fp, "%d entries written to %s\n",
11020e3d5408SPeter Wemm total,
1103*21817992SBaptiste Daroussin _nc_tic_dir(NULL));
11040e3d5408SPeter Wemm else
11050e3d5408SPeter Wemm fprintf(log_fp, "No entries written\n");
11060e3d5408SPeter Wemm }
11074a1a9510SRong-En Fan ExitProgram(EXIT_SUCCESS);
11080e3d5408SPeter Wemm }
11090e3d5408SPeter Wemm
11100e3d5408SPeter Wemm /*
11110e3d5408SPeter Wemm * This bit of legerdemain turns all the terminfo variable names into
11120e3d5408SPeter Wemm * references to locations in the arrays Booleans, Numbers, and Strings ---
11130e3d5408SPeter Wemm * precisely what's needed (see comp_parse.c).
11140e3d5408SPeter Wemm */
11150e3d5408SPeter Wemm #undef CUR
11160e3d5408SPeter Wemm #define CUR tp->
11170e3d5408SPeter Wemm
111815589c42SPeter Wemm /*
11194a1a9510SRong-En Fan * Check if the alternate character-set capabilities are consistent.
11204a1a9510SRong-En Fan */
11214a1a9510SRong-En Fan static void
check_acs(TERMTYPE2 * tp)1122aae38d10SBaptiste Daroussin check_acs(TERMTYPE2 *tp)
11234a1a9510SRong-En Fan {
1124aae38d10SBaptiste Daroussin int vt100_smacs = 0;
1125aae38d10SBaptiste Daroussin int vt100_rmacs = 0;
1126aae38d10SBaptiste Daroussin int vt100_enacs = 0;
1127aae38d10SBaptiste Daroussin
1128aae38d10SBaptiste Daroussin /*
1129aae38d10SBaptiste Daroussin * ena_acs is not always necessary, but if it is present, the enter/exit
1130aae38d10SBaptiste Daroussin * capabilities should be.
1131aae38d10SBaptiste Daroussin */
1132aae38d10SBaptiste Daroussin ANDMISSING(ena_acs, enter_alt_charset_mode);
1133aae38d10SBaptiste Daroussin ANDMISSING(ena_acs, exit_alt_charset_mode);
1134aae38d10SBaptiste Daroussin PAIRED(exit_alt_charset_mode, exit_alt_charset_mode);
1135aae38d10SBaptiste Daroussin
1136aae38d10SBaptiste Daroussin /*
1137aae38d10SBaptiste Daroussin * vt100-like is frequently used, but perhaps ena_acs is missing, etc.
1138aae38d10SBaptiste Daroussin */
1139aae38d10SBaptiste Daroussin if (VALID_STRING(enter_alt_charset_mode)) {
1140aae38d10SBaptiste Daroussin vt100_smacs = (!strcmp("\033(0", enter_alt_charset_mode)
1141aae38d10SBaptiste Daroussin ? 2
1142aae38d10SBaptiste Daroussin : (!strcmp("\016", enter_alt_charset_mode)
1143aae38d10SBaptiste Daroussin ? 1
1144aae38d10SBaptiste Daroussin : 0));
1145aae38d10SBaptiste Daroussin }
1146aae38d10SBaptiste Daroussin if (VALID_STRING(exit_alt_charset_mode)) {
1147aae38d10SBaptiste Daroussin vt100_rmacs = (!strcmp("\033(B", exit_alt_charset_mode)
1148aae38d10SBaptiste Daroussin ? 2
1149aae38d10SBaptiste Daroussin : (!strcmp("\017", exit_alt_charset_mode)
1150aae38d10SBaptiste Daroussin ? 1
1151aae38d10SBaptiste Daroussin : 0));
1152aae38d10SBaptiste Daroussin }
1153aae38d10SBaptiste Daroussin if (VALID_STRING(ena_acs)) {
1154aae38d10SBaptiste Daroussin vt100_enacs = (!strcmp("\033(B\033)0", ena_acs)
1155aae38d10SBaptiste Daroussin ? 2
1156aae38d10SBaptiste Daroussin : 0);
1157aae38d10SBaptiste Daroussin }
1158aae38d10SBaptiste Daroussin if (vt100_rmacs && vt100_smacs && (vt100_rmacs != vt100_smacs)) {
1159aae38d10SBaptiste Daroussin _nc_warning("rmacs/smacs are inconsistent");
1160aae38d10SBaptiste Daroussin }
1161aae38d10SBaptiste Daroussin if ((vt100_rmacs == 2) && (vt100_smacs == 2) && vt100_enacs) {
1162aae38d10SBaptiste Daroussin _nc_warning("rmacs/smacs make enacs redundant");
1163aae38d10SBaptiste Daroussin }
1164aae38d10SBaptiste Daroussin if ((vt100_rmacs == 1) && (vt100_smacs == 1) && !vt100_enacs) {
1165aae38d10SBaptiste Daroussin _nc_warning("VT100-style rmacs/smacs require enacs");
1166aae38d10SBaptiste Daroussin }
1167aae38d10SBaptiste Daroussin
11684a1a9510SRong-En Fan if (VALID_STRING(acs_chars)) {
11694a1a9510SRong-En Fan const char *boxes = "lmkjtuvwqxn";
11704a1a9510SRong-En Fan char mapped[256];
11714a1a9510SRong-En Fan char missing[256];
11724a1a9510SRong-En Fan const char *p;
11734a1a9510SRong-En Fan char *q;
11744a1a9510SRong-En Fan
11754a1a9510SRong-En Fan memset(mapped, 0, sizeof(mapped));
1176*21817992SBaptiste Daroussin memset(missing, 0, sizeof(missing));
11774a1a9510SRong-En Fan for (p = acs_chars; *p != '\0'; p += 2) {
11784a1a9510SRong-En Fan if (p[1] == '\0') {
11794a1a9510SRong-En Fan _nc_warning("acsc has odd number of characters");
11804a1a9510SRong-En Fan break;
11814a1a9510SRong-En Fan }
11824a1a9510SRong-En Fan mapped[UChar(p[0])] = p[1];
11834a1a9510SRong-En Fan }
11845d08fb1fSRong-En Fan
11854a1a9510SRong-En Fan if (mapped[UChar('I')] && !mapped[UChar('i')]) {
11864a1a9510SRong-En Fan _nc_warning("acsc refers to 'I', which is probably an error");
11874a1a9510SRong-En Fan }
11885d08fb1fSRong-En Fan
11894a1a9510SRong-En Fan for (p = boxes, q = missing; *p != '\0'; ++p) {
11904a1a9510SRong-En Fan if (!mapped[UChar(p[0])]) {
11914a1a9510SRong-En Fan *q++ = p[0];
11924a1a9510SRong-En Fan }
11934a1a9510SRong-En Fan }
11945d08fb1fSRong-En Fan *q = '\0';
11955d08fb1fSRong-En Fan
11965d08fb1fSRong-En Fan assert(strlen(missing) <= strlen(boxes));
11974a1a9510SRong-En Fan if (*missing != '\0' && strcmp(missing, boxes)) {
11984a1a9510SRong-En Fan _nc_warning("acsc is missing some line-drawing mapping: %s", missing);
11994a1a9510SRong-En Fan }
12004a1a9510SRong-En Fan }
12014a1a9510SRong-En Fan }
12024a1a9510SRong-En Fan
12037a656419SBaptiste Daroussin static char *
safe_strdup(const char * value)12047a656419SBaptiste Daroussin safe_strdup(const char *value)
12057a656419SBaptiste Daroussin {
12067a656419SBaptiste Daroussin if (value == NULL)
12077a656419SBaptiste Daroussin value = "";
12087a656419SBaptiste Daroussin return strdup(value);
12097a656419SBaptiste Daroussin }
12107a656419SBaptiste Daroussin
1211aae38d10SBaptiste Daroussin static bool
same_color(NCURSES_CONST char * oldcap,NCURSES_CONST char * newcap,int limit)1212aae38d10SBaptiste Daroussin same_color(NCURSES_CONST char *oldcap, NCURSES_CONST char *newcap, int limit)
1213aae38d10SBaptiste Daroussin {
1214aae38d10SBaptiste Daroussin bool result = FALSE;
1215aae38d10SBaptiste Daroussin if (limit > 16)
1216aae38d10SBaptiste Daroussin limit = 16;
1217aae38d10SBaptiste Daroussin if (limit >= 8) {
1218aae38d10SBaptiste Daroussin int n;
1219aae38d10SBaptiste Daroussin int same;
1220aae38d10SBaptiste Daroussin for (n = same = 0; n < limit; ++n) {
12217a656419SBaptiste Daroussin char *oldvalue = safe_strdup(TIPARM_1(oldcap, n));
12227a656419SBaptiste Daroussin char *newvalue = safe_strdup(TIPARM_1(newcap, n));
1223aae38d10SBaptiste Daroussin same += !strcmp(oldvalue, newvalue);
1224aae38d10SBaptiste Daroussin free(oldvalue);
1225aae38d10SBaptiste Daroussin free(newvalue);
1226aae38d10SBaptiste Daroussin }
1227aae38d10SBaptiste Daroussin result = (same == limit);
1228aae38d10SBaptiste Daroussin }
1229aae38d10SBaptiste Daroussin return result;
1230aae38d10SBaptiste Daroussin }
1231aae38d10SBaptiste Daroussin
12324a1a9510SRong-En Fan /*
12334a1a9510SRong-En Fan * Check if the color capabilities are consistent
12344a1a9510SRong-En Fan */
12354a1a9510SRong-En Fan static void
check_colors(TERMTYPE2 * tp)1236aae38d10SBaptiste Daroussin check_colors(TERMTYPE2 *tp)
12374a1a9510SRong-En Fan {
1238aae38d10SBaptiste Daroussin char *value;
1239aae38d10SBaptiste Daroussin
12404a1a9510SRong-En Fan if ((max_colors > 0) != (max_pairs > 0)
1241*21817992SBaptiste Daroussin || ((max_colors > max_pairs) && !VALID_STRING(initialize_pair)))
12424a1a9510SRong-En Fan _nc_warning("inconsistent values for max_colors (%d) and max_pairs (%d)",
12434a1a9510SRong-En Fan max_colors, max_pairs);
12444a1a9510SRong-En Fan
12454a1a9510SRong-En Fan PAIRED(set_foreground, set_background);
12464a1a9510SRong-En Fan PAIRED(set_a_foreground, set_a_background);
12474a1a9510SRong-En Fan PAIRED(set_color_pair, initialize_pair);
12484a1a9510SRong-En Fan
12494a1a9510SRong-En Fan if (VALID_STRING(set_foreground)
1250aae38d10SBaptiste Daroussin && VALID_STRING(set_a_foreground)) {
1251aae38d10SBaptiste Daroussin if (!_nc_capcmp(set_foreground, set_a_foreground)) {
12524a1a9510SRong-En Fan _nc_warning("expected setf/setaf to be different");
1253aae38d10SBaptiste Daroussin } else if (same_color(set_foreground, set_a_foreground, max_colors)) {
1254aae38d10SBaptiste Daroussin _nc_warning("setf/setaf are equivalent");
1255aae38d10SBaptiste Daroussin }
1256aae38d10SBaptiste Daroussin }
12574a1a9510SRong-En Fan
12584a1a9510SRong-En Fan if (VALID_STRING(set_background)
1259aae38d10SBaptiste Daroussin && VALID_STRING(set_a_background)) {
1260aae38d10SBaptiste Daroussin if (!_nc_capcmp(set_background, set_a_background)) {
12614a1a9510SRong-En Fan _nc_warning("expected setb/setab to be different");
1262aae38d10SBaptiste Daroussin } else if (same_color(set_background, set_a_background, max_colors)) {
1263aae38d10SBaptiste Daroussin _nc_warning("setb/setab are equivalent");
1264aae38d10SBaptiste Daroussin }
1265aae38d10SBaptiste Daroussin }
12664a1a9510SRong-En Fan
12674a1a9510SRong-En Fan /* see: has_colors() */
12684a1a9510SRong-En Fan if (VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs)
1269aae38d10SBaptiste Daroussin && ((VALID_STRING(set_foreground)
1270aae38d10SBaptiste Daroussin && VALID_STRING(set_background))
1271aae38d10SBaptiste Daroussin || (VALID_STRING(set_a_foreground)
1272aae38d10SBaptiste Daroussin && VALID_STRING(set_a_background))
12734a1a9510SRong-En Fan || set_color_pair)) {
12744a1a9510SRong-En Fan if (!VALID_STRING(orig_pair) && !VALID_STRING(orig_colors))
12754a1a9510SRong-En Fan _nc_warning("expected either op/oc string for resetting colors");
12764a1a9510SRong-En Fan }
1277aae38d10SBaptiste Daroussin if (can_change) {
1278aae38d10SBaptiste Daroussin if (!VALID_STRING(initialize_pair) &&
1279aae38d10SBaptiste Daroussin !VALID_STRING(initialize_color)) {
1280aae38d10SBaptiste Daroussin _nc_warning("expected initc or initp because ccc is given");
1281aae38d10SBaptiste Daroussin }
1282aae38d10SBaptiste Daroussin } else {
1283aae38d10SBaptiste Daroussin if (VALID_STRING(initialize_pair) ||
1284aae38d10SBaptiste Daroussin VALID_STRING(initialize_color)) {
1285aae38d10SBaptiste Daroussin _nc_warning("expected ccc because initc is given");
1286aae38d10SBaptiste Daroussin }
1287aae38d10SBaptiste Daroussin }
1288aae38d10SBaptiste Daroussin value = tigetstr("RGB");
1289aae38d10SBaptiste Daroussin if (VALID_STRING(value)) {
1290aae38d10SBaptiste Daroussin int r, g, b;
1291aae38d10SBaptiste Daroussin char bad;
1292aae38d10SBaptiste Daroussin int code = sscanf(value, "%d/%d/%d%c", &r, &g, &b, &bad);
1293aae38d10SBaptiste Daroussin if (code != 3 || r <= 0 || g <= 0 || b <= 0) {
1294aae38d10SBaptiste Daroussin _nc_warning("unexpected value for RGB capability: %s", value);
1295aae38d10SBaptiste Daroussin }
1296aae38d10SBaptiste Daroussin }
1297aae38d10SBaptiste Daroussin }
1298aae38d10SBaptiste Daroussin
1299aae38d10SBaptiste Daroussin static int
csi_length(const char * value)1300aae38d10SBaptiste Daroussin csi_length(const char *value)
1301aae38d10SBaptiste Daroussin {
1302aae38d10SBaptiste Daroussin int result = 0;
1303aae38d10SBaptiste Daroussin
1304aae38d10SBaptiste Daroussin if (value[0] == '\033' && value[1] == '[') {
1305aae38d10SBaptiste Daroussin result = 2;
1306aae38d10SBaptiste Daroussin } else if (UChar(value[0]) == 0x9a) {
1307aae38d10SBaptiste Daroussin result = 1;
1308aae38d10SBaptiste Daroussin }
1309aae38d10SBaptiste Daroussin return result;
13104a1a9510SRong-En Fan }
13114a1a9510SRong-En Fan
13125d08fb1fSRong-En Fan static char
keypad_final(const char * string)13134a1a9510SRong-En Fan keypad_final(const char *string)
13144a1a9510SRong-En Fan {
13155d08fb1fSRong-En Fan char result = '\0';
13164a1a9510SRong-En Fan
13174a1a9510SRong-En Fan if (VALID_STRING(string)
13184a1a9510SRong-En Fan && *string++ == '\033'
13194a1a9510SRong-En Fan && *string++ == 'O'
13204a1a9510SRong-En Fan && strlen(string) == 1) {
13214a1a9510SRong-En Fan result = *string;
13224a1a9510SRong-En Fan }
13234a1a9510SRong-En Fan
13244a1a9510SRong-En Fan return result;
13254a1a9510SRong-En Fan }
13264a1a9510SRong-En Fan
132773f0a83dSXin LI static long
keypad_index(const char * string)13284a1a9510SRong-En Fan keypad_index(const char *string)
13294a1a9510SRong-En Fan {
13304a1a9510SRong-En Fan int ch;
133173f0a83dSXin LI long result = -1;
13324a1a9510SRong-En Fan
13334a1a9510SRong-En Fan if ((ch = keypad_final(string)) != '\0') {
1334*21817992SBaptiste Daroussin const char *list = "PQRSwxymtuvlqrsPpn"; /* app-keypad except "Enter" */
1335*21817992SBaptiste Daroussin char *test = (strchr) (list, ch);
13364a1a9510SRong-En Fan if (test != 0)
133773f0a83dSXin LI result = (long) (test - list);
13384a1a9510SRong-En Fan }
13394a1a9510SRong-En Fan return result;
13404a1a9510SRong-En Fan }
13414a1a9510SRong-En Fan
134206bfebdeSXin LI /*
134306bfebdeSXin LI * list[] is down, up, left, right
134406bfebdeSXin LI * "left" may be ^H rather than \E[D
134506bfebdeSXin LI * "down" may be ^J rather than \E[B
134606bfebdeSXin LI * But up/right are generally consistently escape sequences for ANSI terminals.
134706bfebdeSXin LI */
134806bfebdeSXin LI static void
check_ansi_cursor(char * list[4])134906bfebdeSXin LI check_ansi_cursor(char *list[4])
135006bfebdeSXin LI {
135106bfebdeSXin LI int j, k;
135206bfebdeSXin LI bool skip[4];
135306bfebdeSXin LI bool repeated = FALSE;
135406bfebdeSXin LI
135506bfebdeSXin LI for (j = 0; j < 4; ++j) {
135606bfebdeSXin LI skip[j] = FALSE;
135706bfebdeSXin LI for (k = 0; k < j; ++k) {
1358*21817992SBaptiste Daroussin if (!strcmp(list[j], list[k])) {
135906bfebdeSXin LI char *value = _nc_tic_expand(list[k], TRUE, 0);
1360*21817992SBaptiste Daroussin _nc_warning("repeated cursor control %s", value);
136106bfebdeSXin LI repeated = TRUE;
136206bfebdeSXin LI }
136306bfebdeSXin LI }
136406bfebdeSXin LI }
136506bfebdeSXin LI if (!repeated) {
136606bfebdeSXin LI char *up = list[1];
1367aae38d10SBaptiste Daroussin size_t prefix = (size_t) csi_length(up);
1368*21817992SBaptiste Daroussin size_t suffix;
136906bfebdeSXin LI
137006bfebdeSXin LI if (prefix) {
137106bfebdeSXin LI suffix = prefix;
137206bfebdeSXin LI while (up[suffix] && isdigit(UChar(up[suffix])))
137306bfebdeSXin LI ++suffix;
137406bfebdeSXin LI }
137506bfebdeSXin LI if (prefix && up[suffix] == 'A') {
137606bfebdeSXin LI skip[1] = TRUE;
137706bfebdeSXin LI if (!strcmp(list[0], "\n"))
137806bfebdeSXin LI skip[0] = TRUE;
137906bfebdeSXin LI if (!strcmp(list[2], "\b"))
138006bfebdeSXin LI skip[2] = TRUE;
138106bfebdeSXin LI
138206bfebdeSXin LI for (j = 0; j < 4; ++j) {
1383*21817992SBaptiste Daroussin int want;
1384*21817992SBaptiste Daroussin
138506bfebdeSXin LI if (skip[j] || strlen(list[j]) == 1)
138606bfebdeSXin LI continue;
138706bfebdeSXin LI if (memcmp(list[j], up, prefix)) {
138806bfebdeSXin LI char *value = _nc_tic_expand(list[j], TRUE, 0);
1389*21817992SBaptiste Daroussin _nc_warning("inconsistent prefix for %s", value);
139006bfebdeSXin LI continue;
139106bfebdeSXin LI }
139206bfebdeSXin LI if (strlen(list[j]) < suffix) {
139306bfebdeSXin LI char *value = _nc_tic_expand(list[j], TRUE, 0);
1394*21817992SBaptiste Daroussin _nc_warning("inconsistent length for %s, expected %d",
139506bfebdeSXin LI value, (int) suffix + 1);
139606bfebdeSXin LI continue;
139706bfebdeSXin LI }
139806bfebdeSXin LI want = "BADC"[j];
139906bfebdeSXin LI if (list[j][suffix] != want) {
140006bfebdeSXin LI char *value = _nc_tic_expand(list[j], TRUE, 0);
1401*21817992SBaptiste Daroussin _nc_warning("inconsistent suffix for %s, expected %c, have %c",
140206bfebdeSXin LI value, want, list[j][suffix]);
140306bfebdeSXin LI }
140406bfebdeSXin LI }
140506bfebdeSXin LI }
140606bfebdeSXin LI }
140706bfebdeSXin LI }
140806bfebdeSXin LI
140906bfebdeSXin LI #define EXPECTED(name) if (!PRESENT(name)) _nc_warning("expected " #name)
141073f0a83dSXin LI #define UNEXPECTED(name) if (PRESENT(name)) _nc_warning("unexpected " #name ", for %s", why)
141173f0a83dSXin LI
141273f0a83dSXin LI static void
check_noaddress(TERMTYPE2 * tp,const char * why)1413aae38d10SBaptiste Daroussin check_noaddress(TERMTYPE2 *tp, const char *why)
141473f0a83dSXin LI {
141573f0a83dSXin LI UNEXPECTED(column_address);
141673f0a83dSXin LI UNEXPECTED(cursor_address);
141773f0a83dSXin LI UNEXPECTED(cursor_home);
141873f0a83dSXin LI UNEXPECTED(cursor_mem_address);
141973f0a83dSXin LI UNEXPECTED(cursor_to_ll);
142073f0a83dSXin LI UNEXPECTED(row_address);
142173f0a83dSXin LI UNEXPECTED(row_address);
142273f0a83dSXin LI }
142306bfebdeSXin LI
142406bfebdeSXin LI static void
check_cursor(TERMTYPE2 * tp)1425aae38d10SBaptiste Daroussin check_cursor(TERMTYPE2 *tp)
142606bfebdeSXin LI {
142706bfebdeSXin LI int count;
142806bfebdeSXin LI char *list[4];
142906bfebdeSXin LI
143073f0a83dSXin LI if (hard_copy) {
143173f0a83dSXin LI check_noaddress(tp, "hard_copy");
143273f0a83dSXin LI } else if (generic_type) {
143373f0a83dSXin LI check_noaddress(tp, "generic_type");
1434*21817992SBaptiste Daroussin } else if (strchr(tp->term_names, '+') == NULL) {
143573f0a83dSXin LI int y = 0;
143673f0a83dSXin LI int x = 0;
143773f0a83dSXin LI if (PRESENT(column_address))
143873f0a83dSXin LI ++y;
143973f0a83dSXin LI if (PRESENT(cursor_address))
144073f0a83dSXin LI y = x = 10;
144173f0a83dSXin LI if (PRESENT(cursor_home))
144273f0a83dSXin LI ++y, ++x;
144373f0a83dSXin LI if (PRESENT(cursor_mem_address))
144473f0a83dSXin LI y = x = 10;
144573f0a83dSXin LI if (PRESENT(cursor_to_ll))
144673f0a83dSXin LI ++y, ++x;
144773f0a83dSXin LI if (PRESENT(row_address))
144873f0a83dSXin LI ++x;
144973f0a83dSXin LI if (PRESENT(cursor_down))
145073f0a83dSXin LI ++y;
145173f0a83dSXin LI if (PRESENT(cursor_up))
145273f0a83dSXin LI ++y;
145373f0a83dSXin LI if (PRESENT(cursor_left))
145473f0a83dSXin LI ++x;
145573f0a83dSXin LI if (PRESENT(cursor_right))
145673f0a83dSXin LI ++x;
145773f0a83dSXin LI if (x < 2 && y < 2) {
145873f0a83dSXin LI _nc_warning("terminal lacks cursor addressing");
145973f0a83dSXin LI } else {
146073f0a83dSXin LI if (x < 2)
146173f0a83dSXin LI _nc_warning("terminal lacks cursor column-addressing");
146273f0a83dSXin LI if (y < 2)
146373f0a83dSXin LI _nc_warning("terminal lacks cursor row-addressing");
146473f0a83dSXin LI }
146573f0a83dSXin LI }
146673f0a83dSXin LI
146773f0a83dSXin LI /* it is rare to have an insert-line feature without a matching delete */
146873f0a83dSXin LI ANDMISSING(parm_insert_line, insert_line);
146973f0a83dSXin LI ANDMISSING(parm_delete_line, delete_line);
147073f0a83dSXin LI ANDMISSING(parm_insert_line, parm_delete_line);
147173f0a83dSXin LI
147206bfebdeSXin LI /* if we have a parameterized form, then the non-parameterized is easy */
147306bfebdeSXin LI ANDMISSING(parm_down_cursor, cursor_down);
147406bfebdeSXin LI ANDMISSING(parm_up_cursor, cursor_up);
147506bfebdeSXin LI ANDMISSING(parm_left_cursor, cursor_left);
147606bfebdeSXin LI ANDMISSING(parm_right_cursor, cursor_right);
147706bfebdeSXin LI
147806bfebdeSXin LI /* Given any of a set of cursor movement, the whole set should be present.
147906bfebdeSXin LI * Technically this is not true (we could use cursor_address to fill in
148006bfebdeSXin LI * unsupported controls), but it is likely.
148106bfebdeSXin LI */
148206bfebdeSXin LI count = 0;
148306bfebdeSXin LI if (PRESENT(parm_down_cursor)) {
148406bfebdeSXin LI list[count++] = parm_down_cursor;
148506bfebdeSXin LI }
148606bfebdeSXin LI if (PRESENT(parm_up_cursor)) {
148706bfebdeSXin LI list[count++] = parm_up_cursor;
148806bfebdeSXin LI }
148906bfebdeSXin LI if (PRESENT(parm_left_cursor)) {
149006bfebdeSXin LI list[count++] = parm_left_cursor;
149106bfebdeSXin LI }
149206bfebdeSXin LI if (PRESENT(parm_right_cursor)) {
149306bfebdeSXin LI list[count++] = parm_right_cursor;
149406bfebdeSXin LI }
149506bfebdeSXin LI if (count == 4) {
149606bfebdeSXin LI check_ansi_cursor(list);
149706bfebdeSXin LI } else if (count != 0) {
149806bfebdeSXin LI EXPECTED(parm_down_cursor);
149906bfebdeSXin LI EXPECTED(parm_up_cursor);
150006bfebdeSXin LI EXPECTED(parm_left_cursor);
150106bfebdeSXin LI EXPECTED(parm_right_cursor);
150206bfebdeSXin LI }
150306bfebdeSXin LI
150406bfebdeSXin LI count = 0;
150506bfebdeSXin LI if (PRESENT(cursor_down)) {
150606bfebdeSXin LI list[count++] = cursor_down;
150706bfebdeSXin LI }
150806bfebdeSXin LI if (PRESENT(cursor_up)) {
150906bfebdeSXin LI list[count++] = cursor_up;
151006bfebdeSXin LI }
151106bfebdeSXin LI if (PRESENT(cursor_left)) {
151206bfebdeSXin LI list[count++] = cursor_left;
151306bfebdeSXin LI }
151406bfebdeSXin LI if (PRESENT(cursor_right)) {
151506bfebdeSXin LI list[count++] = cursor_right;
151606bfebdeSXin LI }
151706bfebdeSXin LI if (count == 4) {
151806bfebdeSXin LI check_ansi_cursor(list);
151906bfebdeSXin LI } else if (count != 0) {
152006bfebdeSXin LI count = 0;
152106bfebdeSXin LI if (PRESENT(cursor_down) && strcmp(cursor_down, "\n"))
152206bfebdeSXin LI ++count;
152306bfebdeSXin LI if (PRESENT(cursor_left) && strcmp(cursor_left, "\b"))
152406bfebdeSXin LI ++count;
152506bfebdeSXin LI if (PRESENT(cursor_up) && strlen(cursor_up) > 1)
152606bfebdeSXin LI ++count;
152706bfebdeSXin LI if (PRESENT(cursor_right) && strlen(cursor_right) > 1)
152806bfebdeSXin LI ++count;
152906bfebdeSXin LI if (count) {
153006bfebdeSXin LI EXPECTED(cursor_down);
153106bfebdeSXin LI EXPECTED(cursor_up);
153206bfebdeSXin LI EXPECTED(cursor_left);
153306bfebdeSXin LI EXPECTED(cursor_right);
153406bfebdeSXin LI }
153506bfebdeSXin LI }
153606bfebdeSXin LI }
153706bfebdeSXin LI
15385d08fb1fSRong-En Fan #define MAX_KP 5
15394a1a9510SRong-En Fan /*
15404a1a9510SRong-En Fan * Do a quick sanity-check for vt100-style keypads to see if the 5-key keypad
15414a1a9510SRong-En Fan * is mapped inconsistently.
15424a1a9510SRong-En Fan */
15434a1a9510SRong-En Fan static void
check_keypad(TERMTYPE2 * tp)1544aae38d10SBaptiste Daroussin check_keypad(TERMTYPE2 *tp)
15454a1a9510SRong-En Fan {
15464a1a9510SRong-En Fan char show[80];
15474a1a9510SRong-En Fan
15484a1a9510SRong-En Fan if (VALID_STRING(key_a1) &&
15494a1a9510SRong-En Fan VALID_STRING(key_a3) &&
15504a1a9510SRong-En Fan VALID_STRING(key_b2) &&
15514a1a9510SRong-En Fan VALID_STRING(key_c1) &&
15524a1a9510SRong-En Fan VALID_STRING(key_c3)) {
15535d08fb1fSRong-En Fan char final[MAX_KP + 1];
155473f0a83dSXin LI long list[MAX_KP];
15554a1a9510SRong-En Fan int increase = 0;
1556*21817992SBaptiste Daroussin int j;
15574a1a9510SRong-En Fan
15584a1a9510SRong-En Fan final[0] = keypad_final(key_a1);
15594a1a9510SRong-En Fan final[1] = keypad_final(key_a3);
15604a1a9510SRong-En Fan final[2] = keypad_final(key_b2);
15614a1a9510SRong-En Fan final[3] = keypad_final(key_c1);
15624a1a9510SRong-En Fan final[4] = keypad_final(key_c3);
15634a1a9510SRong-En Fan final[5] = '\0';
15644a1a9510SRong-En Fan
15654a1a9510SRong-En Fan /* special case: legacy coding using 1,2,3,0,. on the bottom */
15665d08fb1fSRong-En Fan assert(strlen(final) <= MAX_KP);
15674a1a9510SRong-En Fan if (!strcmp(final, "qsrpn"))
15684a1a9510SRong-En Fan return;
15694a1a9510SRong-En Fan
15704a1a9510SRong-En Fan list[0] = keypad_index(key_a1);
15714a1a9510SRong-En Fan list[1] = keypad_index(key_a3);
15724a1a9510SRong-En Fan list[2] = keypad_index(key_b2);
15734a1a9510SRong-En Fan list[3] = keypad_index(key_c1);
15744a1a9510SRong-En Fan list[4] = keypad_index(key_c3);
15754a1a9510SRong-En Fan
15764a1a9510SRong-En Fan /* check that they're all vt100 keys */
15775d08fb1fSRong-En Fan for (j = 0; j < MAX_KP; ++j) {
15784a1a9510SRong-En Fan if (list[j] < 0) {
15794a1a9510SRong-En Fan return;
15804a1a9510SRong-En Fan }
15814a1a9510SRong-En Fan }
15824a1a9510SRong-En Fan
15834a1a9510SRong-En Fan /* check if they're all in increasing order */
15845d08fb1fSRong-En Fan for (j = 1; j < MAX_KP; ++j) {
15854a1a9510SRong-En Fan if (list[j] > list[j - 1]) {
15864a1a9510SRong-En Fan ++increase;
15874a1a9510SRong-En Fan }
15884a1a9510SRong-En Fan }
1589*21817992SBaptiste Daroussin
15905d08fb1fSRong-En Fan if (increase != (MAX_KP - 1)) {
1591*21817992SBaptiste Daroussin long last;
1592*21817992SBaptiste Daroussin
15934a1a9510SRong-En Fan show[0] = '\0';
15944a1a9510SRong-En Fan
15955d08fb1fSRong-En Fan for (j = 0, last = -1; j < MAX_KP; ++j) {
1596*21817992SBaptiste Daroussin int k;
1597*21817992SBaptiste Daroussin int kk;
1598*21817992SBaptiste Daroussin long test;
1599*21817992SBaptiste Daroussin
16004a1a9510SRong-En Fan for (k = 0, kk = -1, test = 100; k < 5; ++k) {
16014a1a9510SRong-En Fan if (list[k] > last &&
16024a1a9510SRong-En Fan list[k] < test) {
16034a1a9510SRong-En Fan test = list[k];
16044a1a9510SRong-En Fan kk = k;
16054a1a9510SRong-En Fan }
16064a1a9510SRong-En Fan }
16074a1a9510SRong-En Fan last = test;
16085d08fb1fSRong-En Fan assert(strlen(show) < (MAX_KP * 4));
16094a1a9510SRong-En Fan switch (kk) {
16104a1a9510SRong-En Fan case 0:
161173f0a83dSXin LI _nc_STRCAT(show, " ka1", sizeof(show));
16124a1a9510SRong-En Fan break;
16134a1a9510SRong-En Fan case 1:
161473f0a83dSXin LI _nc_STRCAT(show, " ka3", sizeof(show));
16154a1a9510SRong-En Fan break;
16164a1a9510SRong-En Fan case 2:
161773f0a83dSXin LI _nc_STRCAT(show, " kb2", sizeof(show));
16184a1a9510SRong-En Fan break;
16194a1a9510SRong-En Fan case 3:
162073f0a83dSXin LI _nc_STRCAT(show, " kc1", sizeof(show));
16214a1a9510SRong-En Fan break;
16224a1a9510SRong-En Fan case 4:
162373f0a83dSXin LI _nc_STRCAT(show, " kc3", sizeof(show));
16244a1a9510SRong-En Fan break;
16254a1a9510SRong-En Fan }
16264a1a9510SRong-En Fan }
16274a1a9510SRong-En Fan
16284a1a9510SRong-En Fan _nc_warning("vt100 keypad order inconsistent: %s", show);
16294a1a9510SRong-En Fan }
16304a1a9510SRong-En Fan
16314a1a9510SRong-En Fan } else if (VALID_STRING(key_a1) ||
16324a1a9510SRong-En Fan VALID_STRING(key_a3) ||
16334a1a9510SRong-En Fan VALID_STRING(key_b2) ||
16344a1a9510SRong-En Fan VALID_STRING(key_c1) ||
16354a1a9510SRong-En Fan VALID_STRING(key_c3)) {
16364a1a9510SRong-En Fan show[0] = '\0';
16374a1a9510SRong-En Fan if (keypad_index(key_a1) >= 0)
163873f0a83dSXin LI _nc_STRCAT(show, " ka1", sizeof(show));
16394a1a9510SRong-En Fan if (keypad_index(key_a3) >= 0)
164073f0a83dSXin LI _nc_STRCAT(show, " ka3", sizeof(show));
16414a1a9510SRong-En Fan if (keypad_index(key_b2) >= 0)
164273f0a83dSXin LI _nc_STRCAT(show, " kb2", sizeof(show));
16434a1a9510SRong-En Fan if (keypad_index(key_c1) >= 0)
164473f0a83dSXin LI _nc_STRCAT(show, " kc1", sizeof(show));
16454a1a9510SRong-En Fan if (keypad_index(key_c3) >= 0)
164673f0a83dSXin LI _nc_STRCAT(show, " kc3", sizeof(show));
16474a1a9510SRong-En Fan if (*show != '\0')
16484a1a9510SRong-En Fan _nc_warning("vt100 keypad map incomplete:%s", show);
16494a1a9510SRong-En Fan }
165073f0a83dSXin LI
165173f0a83dSXin LI /*
165273f0a83dSXin LI * These warnings are useful for consistency checks - it is possible that
165373f0a83dSXin LI * there are real terminals with mismatches in these
165473f0a83dSXin LI */
165573f0a83dSXin LI ANDMISSING(key_ic, key_dc);
16564a1a9510SRong-En Fan }
16574a1a9510SRong-En Fan
165806bfebdeSXin LI static void
check_printer(TERMTYPE2 * tp)1659aae38d10SBaptiste Daroussin check_printer(TERMTYPE2 *tp)
166006bfebdeSXin LI {
1661aae38d10SBaptiste Daroussin (void) tp;
1662aae38d10SBaptiste Daroussin #if defined(enter_doublewide_mode) && defined(exit_doublewide_mode)
166306bfebdeSXin LI PAIRED(enter_doublewide_mode, exit_doublewide_mode);
1664aae38d10SBaptiste Daroussin #endif
1665aae38d10SBaptiste Daroussin #if defined(enter_italics_mode) && defined(exit_italics_mode)
166606bfebdeSXin LI PAIRED(enter_italics_mode, exit_italics_mode);
1667aae38d10SBaptiste Daroussin #endif
1668aae38d10SBaptiste Daroussin #if defined(enter_leftward_mode) && defined(exit_leftward_mode)
166906bfebdeSXin LI PAIRED(enter_leftward_mode, exit_leftward_mode);
1670aae38d10SBaptiste Daroussin #endif
1671aae38d10SBaptiste Daroussin #if defined(enter_micro_mode) && defined(exit_micro_mode)
167206bfebdeSXin LI PAIRED(enter_micro_mode, exit_micro_mode);
1673aae38d10SBaptiste Daroussin #endif
1674aae38d10SBaptiste Daroussin #if defined(enter_shadow_mode) && defined(exit_shadow_mode)
167506bfebdeSXin LI PAIRED(enter_shadow_mode, exit_shadow_mode);
1676aae38d10SBaptiste Daroussin #endif
1677aae38d10SBaptiste Daroussin #if defined(enter_subscript_mode) && defined(exit_subscript_mode)
167806bfebdeSXin LI PAIRED(enter_subscript_mode, exit_subscript_mode);
1679aae38d10SBaptiste Daroussin #endif
1680aae38d10SBaptiste Daroussin #if defined(enter_superscript_mode) && defined(exit_superscript_mode)
168106bfebdeSXin LI PAIRED(enter_superscript_mode, exit_superscript_mode);
1682aae38d10SBaptiste Daroussin #endif
1683aae38d10SBaptiste Daroussin #if defined(enter_upward_mode) && defined(exit_upward_mode)
168406bfebdeSXin LI PAIRED(enter_upward_mode, exit_upward_mode);
1685aae38d10SBaptiste Daroussin #endif
168606bfebdeSXin LI
1687aae38d10SBaptiste Daroussin #if defined(start_char_set_def) && defined(stop_char_set_def)
168806bfebdeSXin LI ANDMISSING(start_char_set_def, stop_char_set_def);
1689aae38d10SBaptiste Daroussin #endif
169006bfebdeSXin LI
1691*21817992SBaptiste Daroussin /*
1692*21817992SBaptiste Daroussin * If we have a parameterized form, then the non-parameterized is easy.
1693*21817992SBaptiste Daroussin * note: parameterized/non-parameterized margin settings are unrelated.
1694*21817992SBaptiste Daroussin */
1695aae38d10SBaptiste Daroussin #if defined(parm_down_micro) && defined(micro_down)
169606bfebdeSXin LI ANDMISSING(parm_down_micro, micro_down);
1697aae38d10SBaptiste Daroussin #endif
1698aae38d10SBaptiste Daroussin #if defined(parm_left_micro) && defined(micro_left)
169906bfebdeSXin LI ANDMISSING(parm_left_micro, micro_left);
1700aae38d10SBaptiste Daroussin #endif
1701aae38d10SBaptiste Daroussin #if defined(parm_right_micro) && defined(micro_right)
170206bfebdeSXin LI ANDMISSING(parm_right_micro, micro_right);
1703aae38d10SBaptiste Daroussin #endif
1704aae38d10SBaptiste Daroussin #if defined(parm_up_micro) && defined(micro_up)
170506bfebdeSXin LI ANDMISSING(parm_up_micro, micro_up);
1706aae38d10SBaptiste Daroussin #endif
170706bfebdeSXin LI }
170806bfebdeSXin LI
1709aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
171073f0a83dSXin LI static bool
uses_SGR_39_49(const char * value)171173f0a83dSXin LI uses_SGR_39_49(const char *value)
171273f0a83dSXin LI {
171373f0a83dSXin LI return (strstr(value, "39;49") != 0
171473f0a83dSXin LI || strstr(value, "49;39") != 0);
171573f0a83dSXin LI }
171673f0a83dSXin LI
171773f0a83dSXin LI /*
171873f0a83dSXin LI * Check consistency of termcap extensions related to "screen".
171973f0a83dSXin LI */
172073f0a83dSXin LI static void
check_screen(TERMTYPE2 * tp)1721aae38d10SBaptiste Daroussin check_screen(TERMTYPE2 *tp)
172273f0a83dSXin LI {
172373f0a83dSXin LI if (_nc_user_definable) {
172473f0a83dSXin LI int have_XT = tigetflag("XT");
172573f0a83dSXin LI int have_XM = tigetflag("XM");
172673f0a83dSXin LI int have_bce = back_color_erase;
172773f0a83dSXin LI bool have_kmouse = FALSE;
172873f0a83dSXin LI bool use_sgr_39_49 = FALSE;
17297a656419SBaptiste Daroussin const char *name_39_49 = "orig_pair or orig_colors";
173073f0a83dSXin LI char *name = _nc_first_name(tp->term_names);
1731aae38d10SBaptiste Daroussin bool is_screen = !strncmp(name, "screen", 6);
1732aae38d10SBaptiste Daroussin bool screen_base = (is_screen
1733*21817992SBaptiste Daroussin && strchr(name, '.') == NULL);
173473f0a83dSXin LI
173573f0a83dSXin LI if (!VALID_BOOLEAN(have_bce)) {
173673f0a83dSXin LI have_bce = FALSE;
173773f0a83dSXin LI }
173873f0a83dSXin LI if (!VALID_BOOLEAN(have_XM)) {
173973f0a83dSXin LI have_XM = FALSE;
174073f0a83dSXin LI }
174173f0a83dSXin LI if (!VALID_BOOLEAN(have_XT)) {
174273f0a83dSXin LI have_XT = FALSE;
174373f0a83dSXin LI }
174473f0a83dSXin LI if (VALID_STRING(key_mouse)) {
174573f0a83dSXin LI have_kmouse = !strcmp("\033[M", key_mouse);
174673f0a83dSXin LI }
17477a656419SBaptiste Daroussin if (have_bce) {
17487a656419SBaptiste Daroussin if (VALID_STRING(orig_pair)) {
17497a656419SBaptiste Daroussin name_39_49 = "orig_pair";
175073f0a83dSXin LI use_sgr_39_49 = uses_SGR_39_49(orig_pair);
175173f0a83dSXin LI }
17527a656419SBaptiste Daroussin if (!use_sgr_39_49 && VALID_STRING(orig_colors)) {
17537a656419SBaptiste Daroussin name_39_49 = "orig_colors";
17547a656419SBaptiste Daroussin use_sgr_39_49 = uses_SGR_39_49(orig_colors);
17557a656419SBaptiste Daroussin }
17567a656419SBaptiste Daroussin }
175773f0a83dSXin LI
175873f0a83dSXin LI if (have_XM && have_XT) {
1759aae38d10SBaptiste Daroussin _nc_warning("screen's XT capability conflicts with XM");
1760aae38d10SBaptiste Daroussin } else if (have_XT && screen_base) {
1761aae38d10SBaptiste Daroussin _nc_warning("screen's \"screen\" entries should not have XT set");
176273f0a83dSXin LI } else if (have_XT) {
1763*21817992SBaptiste Daroussin char *s;
1764*21817992SBaptiste Daroussin
1765aae38d10SBaptiste Daroussin if (!have_kmouse && is_screen) {
176673f0a83dSXin LI if (VALID_STRING(key_mouse)) {
1767aae38d10SBaptiste Daroussin _nc_warning("value of kmous inconsistent with screen's usage");
176873f0a83dSXin LI } else {
1769aae38d10SBaptiste Daroussin _nc_warning("expected kmous capability with XT");
177073f0a83dSXin LI }
177173f0a83dSXin LI }
17727a656419SBaptiste Daroussin if (max_colors > 0) {
17737a656419SBaptiste Daroussin if (!have_bce) {
1774aae38d10SBaptiste Daroussin _nc_warning("expected bce capability with XT");
17757a656419SBaptiste Daroussin } else if (!use_sgr_39_49) {
17767a656419SBaptiste Daroussin _nc_warning("expected %s capability with XT "
17777a656419SBaptiste Daroussin "to have 39/49 parameters", name_39_49);
17787a656419SBaptiste Daroussin }
17797a656419SBaptiste Daroussin }
1780*21817992SBaptiste Daroussin if (VALID_STRING(to_status_line)
1781*21817992SBaptiste Daroussin && (s = strchr(to_status_line, ';')) != NULL
1782*21817992SBaptiste Daroussin && *++s == '\0')
178373f0a83dSXin LI _nc_warning("\"tsl\" capability is redundant, given XT");
178473f0a83dSXin LI } else {
1785aae38d10SBaptiste Daroussin if (have_kmouse
1786aae38d10SBaptiste Daroussin && !have_XM
1787*21817992SBaptiste Daroussin && !screen_base && strchr(name, '+') == NULL) {
1788aae38d10SBaptiste Daroussin _nc_warning("expected XT to be set, given kmous");
178973f0a83dSXin LI }
179073f0a83dSXin LI }
1791aae38d10SBaptiste Daroussin }
1792aae38d10SBaptiste Daroussin }
1793aae38d10SBaptiste Daroussin #else
1794aae38d10SBaptiste Daroussin #define check_screen(tp) /* nothing */
179573f0a83dSXin LI #endif
179673f0a83dSXin LI
17974a1a9510SRong-En Fan /*
179818259542SPeter Wemm * Returns the expected number of parameters for the given capability.
179918259542SPeter Wemm */
180018259542SPeter Wemm static int
expected_params(const char * name)18017a69bbfbSPeter Wemm expected_params(const char *name)
180218259542SPeter Wemm {
1803aae38d10SBaptiste Daroussin #define DATA(name,count) { { name }, count }
180418259542SPeter Wemm /* *INDENT-OFF* */
180518259542SPeter Wemm static const struct {
1806aae38d10SBaptiste Daroussin const char name[9];
180718259542SPeter Wemm int count;
180818259542SPeter Wemm } table[] = {
1809aae38d10SBaptiste Daroussin DATA( "S0", 1 ), /* 'screen' extension */
1810aae38d10SBaptiste Daroussin DATA( "birep", 2 ),
1811aae38d10SBaptiste Daroussin DATA( "chr", 1 ),
1812aae38d10SBaptiste Daroussin DATA( "colornm", 1 ),
1813aae38d10SBaptiste Daroussin DATA( "cpi", 1 ),
1814aae38d10SBaptiste Daroussin DATA( "csnm", 1 ),
1815aae38d10SBaptiste Daroussin DATA( "csr", 2 ),
1816aae38d10SBaptiste Daroussin DATA( "cub", 1 ),
1817aae38d10SBaptiste Daroussin DATA( "cud", 1 ),
1818aae38d10SBaptiste Daroussin DATA( "cuf", 1 ),
1819aae38d10SBaptiste Daroussin DATA( "cup", 2 ),
1820aae38d10SBaptiste Daroussin DATA( "cuu", 1 ),
1821aae38d10SBaptiste Daroussin DATA( "cvr", 1 ),
1822aae38d10SBaptiste Daroussin DATA( "cwin", 5 ),
1823aae38d10SBaptiste Daroussin DATA( "dch", 1 ),
1824aae38d10SBaptiste Daroussin DATA( "defc", 3 ),
1825aae38d10SBaptiste Daroussin DATA( "dial", 1 ),
1826aae38d10SBaptiste Daroussin DATA( "dispc", 1 ),
1827aae38d10SBaptiste Daroussin DATA( "dl", 1 ),
1828aae38d10SBaptiste Daroussin DATA( "ech", 1 ),
1829aae38d10SBaptiste Daroussin DATA( "getm", 1 ),
1830aae38d10SBaptiste Daroussin DATA( "hpa", 1 ),
1831aae38d10SBaptiste Daroussin DATA( "ich", 1 ),
1832aae38d10SBaptiste Daroussin DATA( "il", 1 ),
1833aae38d10SBaptiste Daroussin DATA( "indn", 1 ),
1834aae38d10SBaptiste Daroussin DATA( "initc", 4 ),
1835aae38d10SBaptiste Daroussin DATA( "initp", 7 ),
1836aae38d10SBaptiste Daroussin DATA( "lpi", 1 ),
1837aae38d10SBaptiste Daroussin DATA( "mc5p", 1 ),
1838aae38d10SBaptiste Daroussin DATA( "mrcup", 2 ),
1839aae38d10SBaptiste Daroussin DATA( "mvpa", 1 ),
1840aae38d10SBaptiste Daroussin DATA( "pfkey", 2 ),
1841aae38d10SBaptiste Daroussin DATA( "pfloc", 2 ),
1842aae38d10SBaptiste Daroussin DATA( "pfx", 2 ),
1843aae38d10SBaptiste Daroussin DATA( "pfxl", 3 ),
1844aae38d10SBaptiste Daroussin DATA( "pln", 2 ),
1845aae38d10SBaptiste Daroussin DATA( "qdial", 1 ),
1846aae38d10SBaptiste Daroussin DATA( "rcsd", 1 ),
1847aae38d10SBaptiste Daroussin DATA( "rep", 2 ),
1848aae38d10SBaptiste Daroussin DATA( "rin", 1 ),
1849aae38d10SBaptiste Daroussin DATA( "sclk", 3 ),
1850aae38d10SBaptiste Daroussin DATA( "scp", 1 ),
1851aae38d10SBaptiste Daroussin DATA( "scs", 1 ),
1852aae38d10SBaptiste Daroussin DATA( "scsd", 2 ),
1853aae38d10SBaptiste Daroussin DATA( "setab", 1 ),
1854aae38d10SBaptiste Daroussin DATA( "setaf", 1 ),
1855aae38d10SBaptiste Daroussin DATA( "setb", 1 ),
1856aae38d10SBaptiste Daroussin DATA( "setcolor", 1 ),
1857aae38d10SBaptiste Daroussin DATA( "setf", 1 ),
1858aae38d10SBaptiste Daroussin DATA( "sgr", 9 ),
1859aae38d10SBaptiste Daroussin DATA( "sgr1", 6 ),
1860aae38d10SBaptiste Daroussin DATA( "slength", 1 ),
1861aae38d10SBaptiste Daroussin DATA( "slines", 1 ),
1862aae38d10SBaptiste Daroussin DATA( "smgbp", 1 ), /* 2 if smgtp is not given */
1863aae38d10SBaptiste Daroussin DATA( "smglp", 1 ),
1864aae38d10SBaptiste Daroussin DATA( "smglr", 2 ),
1865aae38d10SBaptiste Daroussin DATA( "smgrp", 1 ),
1866aae38d10SBaptiste Daroussin DATA( "smgtb", 2 ),
1867aae38d10SBaptiste Daroussin DATA( "smgtp", 1 ),
1868aae38d10SBaptiste Daroussin DATA( "tsl", 1 ),
1869aae38d10SBaptiste Daroussin DATA( "u6", -1 ),
1870aae38d10SBaptiste Daroussin DATA( "vpa", 1 ),
1871aae38d10SBaptiste Daroussin DATA( "wind", 4 ),
1872aae38d10SBaptiste Daroussin DATA( "wingo", 1 ),
187318259542SPeter Wemm };
187418259542SPeter Wemm /* *INDENT-ON* */
1875aae38d10SBaptiste Daroussin #undef DATA
1876aae38d10SBaptiste Daroussin
187718259542SPeter Wemm unsigned n;
187818259542SPeter Wemm int result = 0; /* function-keys, etc., use none */
187918259542SPeter Wemm
188018259542SPeter Wemm for (n = 0; n < SIZEOF(table); n++) {
188118259542SPeter Wemm if (!strcmp(name, table[n].name)) {
188218259542SPeter Wemm result = table[n].count;
188318259542SPeter Wemm break;
188418259542SPeter Wemm }
188518259542SPeter Wemm }
188618259542SPeter Wemm
188718259542SPeter Wemm return result;
188818259542SPeter Wemm }
188918259542SPeter Wemm
189018259542SPeter Wemm /*
1891aae38d10SBaptiste Daroussin * Check for user-capabilities that happen to be used in ncurses' terminal
1892aae38d10SBaptiste Daroussin * database.
1893aae38d10SBaptiste Daroussin */
1894aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
1895aae38d10SBaptiste Daroussin static struct user_table_entry const *
lookup_user_capability(const char * name)1896aae38d10SBaptiste Daroussin lookup_user_capability(const char *name)
1897aae38d10SBaptiste Daroussin {
1898aae38d10SBaptiste Daroussin struct user_table_entry const *result = 0;
1899aae38d10SBaptiste Daroussin if (*name != 'k') {
1900aae38d10SBaptiste Daroussin result = _nc_find_user_entry(name);
1901aae38d10SBaptiste Daroussin }
1902aae38d10SBaptiste Daroussin return result;
1903aae38d10SBaptiste Daroussin }
1904aae38d10SBaptiste Daroussin #endif
1905aae38d10SBaptiste Daroussin
1906aae38d10SBaptiste Daroussin /*
1907aae38d10SBaptiste Daroussin * If a given name is likely to be a user-capability, return the number of
1908aae38d10SBaptiste Daroussin * parameters it would be used with. If not, return -1.
1909aae38d10SBaptiste Daroussin *
1910aae38d10SBaptiste Daroussin * ncurses assumes that u6 could be used for getting the cursor-position, but
1911aae38d10SBaptiste Daroussin * that is not implemented. Make a special case for that, to quiet needless
1912aae38d10SBaptiste Daroussin * warnings.
1913aae38d10SBaptiste Daroussin *
1914aae38d10SBaptiste Daroussin * The other string-capability extensions (see terminfo.src) which could have
1915aae38d10SBaptiste Daroussin * parameters such as "Ss", "%u", are not used by ncurses. But we check those
1916aae38d10SBaptiste Daroussin * anyway, to validate the terminfo database.
1917aae38d10SBaptiste Daroussin */
1918aae38d10SBaptiste Daroussin static int
is_user_capability(const char * name)1919aae38d10SBaptiste Daroussin is_user_capability(const char *name)
1920aae38d10SBaptiste Daroussin {
1921aae38d10SBaptiste Daroussin int result = -1;
1922aae38d10SBaptiste Daroussin if (name[0] == 'u' &&
1923aae38d10SBaptiste Daroussin (name[1] >= '0' && name[1] <= '9') &&
1924aae38d10SBaptiste Daroussin name[2] == '\0') {
1925aae38d10SBaptiste Daroussin result = (name[1] == '6') ? 2 : 0;
1926aae38d10SBaptiste Daroussin }
1927aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
1928aae38d10SBaptiste Daroussin else if (using_extensions) {
1929aae38d10SBaptiste Daroussin struct user_table_entry const *p = lookup_user_capability(name);
1930aae38d10SBaptiste Daroussin if (p != 0) {
1931aae38d10SBaptiste Daroussin result = (int) p->ute_argc;
1932aae38d10SBaptiste Daroussin }
1933aae38d10SBaptiste Daroussin }
1934aae38d10SBaptiste Daroussin #endif
1935aae38d10SBaptiste Daroussin return result;
1936aae38d10SBaptiste Daroussin }
1937aae38d10SBaptiste Daroussin
1938*21817992SBaptiste Daroussin static bool
line_capability(const char * name)1939*21817992SBaptiste Daroussin line_capability(const char *name)
1940*21817992SBaptiste Daroussin {
1941*21817992SBaptiste Daroussin bool result = FALSE;
1942*21817992SBaptiste Daroussin static const char *table[] =
1943*21817992SBaptiste Daroussin {
1944*21817992SBaptiste Daroussin "csr", /* change_scroll_region */
1945*21817992SBaptiste Daroussin "clear", /* clear_screen */
1946*21817992SBaptiste Daroussin "ed", /* clr_eos */
1947*21817992SBaptiste Daroussin "cwin", /* create_window */
1948*21817992SBaptiste Daroussin "cup", /* cursor_address */
1949*21817992SBaptiste Daroussin "cud1", /* cursor_down */
1950*21817992SBaptiste Daroussin "home", /* cursor_home */
1951*21817992SBaptiste Daroussin "mrcup", /* cursor_mem_address */
1952*21817992SBaptiste Daroussin "ll", /* cursor_to_ll */
1953*21817992SBaptiste Daroussin "cuu1", /* cursor_up */
1954*21817992SBaptiste Daroussin "dl1", /* delete_line */
1955*21817992SBaptiste Daroussin "hd", /* down_half_line */
1956*21817992SBaptiste Daroussin "flash", /* flash_screen */
1957*21817992SBaptiste Daroussin "ff", /* form_feed */
1958*21817992SBaptiste Daroussin "il1", /* insert_line */
1959*21817992SBaptiste Daroussin "nel", /* newline */
1960*21817992SBaptiste Daroussin "dl", /* parm_delete_line */
1961*21817992SBaptiste Daroussin "cud", /* parm_down_cursor */
1962*21817992SBaptiste Daroussin "indn", /* parm_index */
1963*21817992SBaptiste Daroussin "il", /* parm_insert_line */
1964*21817992SBaptiste Daroussin "rin", /* parm_rindex */
1965*21817992SBaptiste Daroussin "cuu", /* parm_up_cursor */
1966*21817992SBaptiste Daroussin "mc0", /* print_screen */
1967*21817992SBaptiste Daroussin "vpa", /* row_address */
1968*21817992SBaptiste Daroussin "ind", /* scroll_forward */
1969*21817992SBaptiste Daroussin "ri", /* scroll_reverse */
1970*21817992SBaptiste Daroussin "hu", /* up_half_line */
1971*21817992SBaptiste Daroussin };
1972*21817992SBaptiste Daroussin size_t n;
1973*21817992SBaptiste Daroussin for (n = 0; n < SIZEOF(table); ++n) {
1974*21817992SBaptiste Daroussin if (!strcmp(name, table[n])) {
1975*21817992SBaptiste Daroussin result = TRUE;
1976*21817992SBaptiste Daroussin break;
1977*21817992SBaptiste Daroussin }
1978*21817992SBaptiste Daroussin }
1979*21817992SBaptiste Daroussin return result;
1980*21817992SBaptiste Daroussin }
1981*21817992SBaptiste Daroussin
1982aae38d10SBaptiste Daroussin /*
198318259542SPeter Wemm * Make a quick sanity check for the parameters which are used in the given
198418259542SPeter Wemm * strings. If there are no "%p" tokens, then there should be no other "%"
198518259542SPeter Wemm * markers.
198618259542SPeter Wemm */
198718259542SPeter Wemm static void
check_params(TERMTYPE2 * tp,const char * name,const char * value,int extended)1988*21817992SBaptiste Daroussin check_params(TERMTYPE2 *tp, const char *name, const char *value, int extended)
198918259542SPeter Wemm {
199018259542SPeter Wemm int expected = expected_params(name);
199118259542SPeter Wemm int actual = 0;
199218259542SPeter Wemm int n;
19937a656419SBaptiste Daroussin bool params[1 + NUM_PARM];
1994*21817992SBaptiste Daroussin const char *s = value;
199518259542SPeter Wemm
1996*21817992SBaptiste Daroussin #ifdef set_left_margin_parm
1997*21817992SBaptiste Daroussin if (!strcmp(name, "smgrp")
1998*21817992SBaptiste Daroussin && !VALID_STRING(set_left_margin_parm))
1999*21817992SBaptiste Daroussin expected = 2;
2000*21817992SBaptiste Daroussin #endif
2001*21817992SBaptiste Daroussin #ifdef set_right_margin_parm
2002*21817992SBaptiste Daroussin if (!strcmp(name, "smglp")
2003*21817992SBaptiste Daroussin && !VALID_STRING(set_right_margin_parm))
2004*21817992SBaptiste Daroussin expected = 2;
2005*21817992SBaptiste Daroussin #endif
20064a1a9510SRong-En Fan #ifdef set_top_margin_parm
2007b82face1SPeter Wemm if (!strcmp(name, "smgbp")
2008*21817992SBaptiste Daroussin && !VALID_STRING(set_top_margin_parm))
2009*21817992SBaptiste Daroussin expected = 2;
2010*21817992SBaptiste Daroussin #endif
2011*21817992SBaptiste Daroussin #ifdef set_bottom_margin_parm
2012*21817992SBaptiste Daroussin if (!strcmp(name, "smgtp")
2013*21817992SBaptiste Daroussin && !VALID_STRING(set_bottom_margin_parm))
2014b82face1SPeter Wemm expected = 2;
20154a1a9510SRong-En Fan #endif
2016b82face1SPeter Wemm
20177a656419SBaptiste Daroussin for (n = 0; n <= NUM_PARM; n++)
201818259542SPeter Wemm params[n] = FALSE;
201918259542SPeter Wemm
202018259542SPeter Wemm while (*s != 0) {
202118259542SPeter Wemm if (*s == '%') {
202218259542SPeter Wemm if (*++s == '\0') {
202318259542SPeter Wemm _nc_warning("expected character after %% in %s", name);
202418259542SPeter Wemm break;
202518259542SPeter Wemm } else if (*s == 'p') {
202618259542SPeter Wemm if (*++s == '\0' || !isdigit((int) *s)) {
202718259542SPeter Wemm _nc_warning("expected digit after %%p in %s", name);
202818259542SPeter Wemm return;
202918259542SPeter Wemm } else {
203018259542SPeter Wemm n = (*s - '0');
203118259542SPeter Wemm if (n > actual)
203218259542SPeter Wemm actual = n;
203318259542SPeter Wemm params[n] = TRUE;
203418259542SPeter Wemm }
203518259542SPeter Wemm }
203618259542SPeter Wemm }
203718259542SPeter Wemm s++;
203818259542SPeter Wemm }
203918259542SPeter Wemm
2040aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
2041aae38d10SBaptiste Daroussin if (extended) {
2042aae38d10SBaptiste Daroussin int check = is_user_capability(name);
2043aae38d10SBaptiste Daroussin if (check != actual && (check >= 0 && actual >= 0)) {
2044aae38d10SBaptiste Daroussin _nc_warning("extended %s capability has %d parameters, expected %d",
2045aae38d10SBaptiste Daroussin name, actual, check);
2046aae38d10SBaptiste Daroussin } else if (debug_level > 1) {
2047aae38d10SBaptiste Daroussin _nc_warning("extended %s capability has %d parameters, as expected",
2048aae38d10SBaptiste Daroussin name, actual);
2049aae38d10SBaptiste Daroussin }
2050aae38d10SBaptiste Daroussin expected = actual;
2051aae38d10SBaptiste Daroussin }
2052aae38d10SBaptiste Daroussin #else
2053aae38d10SBaptiste Daroussin (void) extended;
2054aae38d10SBaptiste Daroussin #endif
2055aae38d10SBaptiste Daroussin
205618259542SPeter Wemm if (params[0]) {
205718259542SPeter Wemm _nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name);
205818259542SPeter Wemm }
205918259542SPeter Wemm if (value == set_attributes || expected < 0) {
206018259542SPeter Wemm ;
206118259542SPeter Wemm } else if (expected != actual) {
206218259542SPeter Wemm _nc_warning("%s uses %d parameters, expected %d", name,
206318259542SPeter Wemm actual, expected);
206418259542SPeter Wemm for (n = 1; n < actual; n++) {
206518259542SPeter Wemm if (!params[n])
206618259542SPeter Wemm _nc_warning("%s omits parameter %d", name, n);
206718259542SPeter Wemm }
206818259542SPeter Wemm }
2069aae38d10SBaptiste Daroussin
2070aae38d10SBaptiste Daroussin /*
2071aae38d10SBaptiste Daroussin * Counting "%p" markers does not account for termcap expressions which
2072aae38d10SBaptiste Daroussin * may not have been fully translated. Also, tparm does its own analysis.
2073aae38d10SBaptiste Daroussin * Report differences here.
2074aae38d10SBaptiste Daroussin */
2075*21817992SBaptiste Daroussin _nc_reset_tparm(NULL);
2076aae38d10SBaptiste Daroussin if (actual >= 0) {
2077aae38d10SBaptiste Daroussin char *p_is_s[NUM_PARM];
2078aae38d10SBaptiste Daroussin int popcount;
2079*21817992SBaptiste Daroussin int analyzed = _nc_tparm_analyze(NULL, value, p_is_s, &popcount);
2080aae38d10SBaptiste Daroussin if (analyzed < popcount) {
2081aae38d10SBaptiste Daroussin analyzed = popcount;
2082aae38d10SBaptiste Daroussin }
2083aae38d10SBaptiste Daroussin if (actual != analyzed && expected != analyzed) {
2084aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
2085aae38d10SBaptiste Daroussin int user_cap = is_user_capability(name);
2086aae38d10SBaptiste Daroussin if ((user_cap == analyzed) && using_extensions) {
2087aae38d10SBaptiste Daroussin ; /* ignore */
2088aae38d10SBaptiste Daroussin } else if (user_cap >= 0) {
2089aae38d10SBaptiste Daroussin _nc_warning("tparm will use %d parameters for %s, expected %d",
2090aae38d10SBaptiste Daroussin analyzed, name, user_cap);
2091aae38d10SBaptiste Daroussin } else
2092aae38d10SBaptiste Daroussin #endif
2093aae38d10SBaptiste Daroussin {
2094aae38d10SBaptiste Daroussin _nc_warning("tparm analyzed %d parameters for %s, expected %d",
2095aae38d10SBaptiste Daroussin analyzed, name, actual);
2096aae38d10SBaptiste Daroussin }
2097*21817992SBaptiste Daroussin } else if (expected > 0
2098*21817992SBaptiste Daroussin && actual == expected
2099*21817992SBaptiste Daroussin && guess_tparm_type(expected, p_is_s) == Numbers) {
2100*21817992SBaptiste Daroussin int limit = 1;
2101aae38d10SBaptiste Daroussin
2102*21817992SBaptiste Daroussin if (!strcmp(name, "setf")
2103*21817992SBaptiste Daroussin || !strcmp(name, "setb")
2104*21817992SBaptiste Daroussin || !strcmp(name, "setaf")
2105*21817992SBaptiste Daroussin || !strcmp(name, "setab")) {
2106*21817992SBaptiste Daroussin if ((limit = max_colors) > 256)
2107*21817992SBaptiste Daroussin limit = 256;
2108*21817992SBaptiste Daroussin } else if (line_capability(name)) {
2109*21817992SBaptiste Daroussin limit = 24;
2110*21817992SBaptiste Daroussin } else if (is_user_capability(name) < 0) {
2111*21817992SBaptiste Daroussin limit = 80;
2112*21817992SBaptiste Daroussin }
2113*21817992SBaptiste Daroussin for (n = 0; n < limit; ++n) {
2114*21817992SBaptiste Daroussin _nc_reset_tparm(NULL);
2115*21817992SBaptiste Daroussin (void) TPARM_9(value, n, n, n, n, n, n, n, n, n);
2116*21817992SBaptiste Daroussin if (_nc_tparm_err) {
2117*21817992SBaptiste Daroussin _nc_warning("problem%s in tparm(%s, %d, ...)",
2118*21817992SBaptiste Daroussin (_nc_tparm_err == 1) ? "" : "s",
2119*21817992SBaptiste Daroussin name, n);
2120*21817992SBaptiste Daroussin if (debug_level < 2)
2121aae38d10SBaptiste Daroussin break;
2122aae38d10SBaptiste Daroussin }
2123aae38d10SBaptiste Daroussin }
2124*21817992SBaptiste Daroussin }
2125*21817992SBaptiste Daroussin }
2126aae38d10SBaptiste Daroussin }
2127aae38d10SBaptiste Daroussin
2128aae38d10SBaptiste Daroussin /*
2129aae38d10SBaptiste Daroussin * Check for DEC VT100 private mode for reverse video.
2130aae38d10SBaptiste Daroussin */
2131aae38d10SBaptiste Daroussin static const char *
skip_DECSCNM(const char * value,int * flag)2132aae38d10SBaptiste Daroussin skip_DECSCNM(const char *value, int *flag)
2133aae38d10SBaptiste Daroussin {
2134aae38d10SBaptiste Daroussin *flag = -1;
2135aae38d10SBaptiste Daroussin if (value != 0) {
2136aae38d10SBaptiste Daroussin int skip = csi_length(value);
2137aae38d10SBaptiste Daroussin if (skip > 0 &&
2138aae38d10SBaptiste Daroussin value[skip++] == '?' &&
2139aae38d10SBaptiste Daroussin value[skip++] == '5') {
2140aae38d10SBaptiste Daroussin if (value[skip] == 'h') {
2141aae38d10SBaptiste Daroussin *flag = 1;
2142aae38d10SBaptiste Daroussin } else if (value[skip] == 'l') {
2143aae38d10SBaptiste Daroussin *flag = 0;
2144aae38d10SBaptiste Daroussin }
2145aae38d10SBaptiste Daroussin value += skip + 1;
2146aae38d10SBaptiste Daroussin }
2147aae38d10SBaptiste Daroussin }
2148aae38d10SBaptiste Daroussin return value;
2149aae38d10SBaptiste Daroussin }
2150aae38d10SBaptiste Daroussin
2151aae38d10SBaptiste Daroussin static void
check_delays(TERMTYPE2 * tp,const char * name,const char * value)2152aae38d10SBaptiste Daroussin check_delays(TERMTYPE2 *tp, const char *name, const char *value)
2153aae38d10SBaptiste Daroussin {
2154aae38d10SBaptiste Daroussin const char *p, *q;
2155aae38d10SBaptiste Daroussin const char *first = 0;
2156aae38d10SBaptiste Daroussin const char *last = 0;
2157aae38d10SBaptiste Daroussin
2158aae38d10SBaptiste Daroussin for (p = value; *p != '\0'; ++p) {
2159aae38d10SBaptiste Daroussin if (p[0] == '$' && p[1] == '<') {
2160aae38d10SBaptiste Daroussin const char *base = p + 2;
2161aae38d10SBaptiste Daroussin const char *mark = 0;
2162aae38d10SBaptiste Daroussin bool mixed = FALSE;
2163aae38d10SBaptiste Daroussin int proportional = 0;
2164aae38d10SBaptiste Daroussin int mandatory = 0;
2165aae38d10SBaptiste Daroussin
2166aae38d10SBaptiste Daroussin first = p;
2167aae38d10SBaptiste Daroussin
2168aae38d10SBaptiste Daroussin for (q = base; *q != '\0'; ++q) {
2169aae38d10SBaptiste Daroussin if (*q == '>') {
2170*21817992SBaptiste Daroussin if (mark == NULL)
2171aae38d10SBaptiste Daroussin mark = q;
2172aae38d10SBaptiste Daroussin break;
2173aae38d10SBaptiste Daroussin } else if (*q == '*' || *q == '/') {
2174aae38d10SBaptiste Daroussin if (*q == '*')
2175aae38d10SBaptiste Daroussin ++proportional;
2176aae38d10SBaptiste Daroussin if (*q == '/')
2177aae38d10SBaptiste Daroussin ++mandatory;
2178*21817992SBaptiste Daroussin if (mark == NULL)
2179aae38d10SBaptiste Daroussin mark = q;
2180aae38d10SBaptiste Daroussin } else if (!(isalnum(UChar(*q)) || strchr("+-.", *q) != 0)) {
2181aae38d10SBaptiste Daroussin break;
2182aae38d10SBaptiste Daroussin } else if (proportional || mandatory) {
2183aae38d10SBaptiste Daroussin mixed = TRUE;
2184aae38d10SBaptiste Daroussin }
2185aae38d10SBaptiste Daroussin }
2186aae38d10SBaptiste Daroussin last = *q ? (q + 1) : q;
2187*21817992SBaptiste Daroussin if (*q != '\0') {
2188aae38d10SBaptiste Daroussin float check_f;
2189aae38d10SBaptiste Daroussin char check_c;
2190aae38d10SBaptiste Daroussin int rc = sscanf(base, "%f%c", &check_f, &check_c);
2191*21817992SBaptiste Daroussin if ((rc != 2) || (mark != NULL && (check_c != *mark)) || mixed) {
2192aae38d10SBaptiste Daroussin _nc_warning("syntax error in %s delay '%.*s'", name,
2193aae38d10SBaptiste Daroussin (int) (q - base), base);
2194aae38d10SBaptiste Daroussin } else if (*name == 'k') {
2195aae38d10SBaptiste Daroussin _nc_warning("function-key %s has delay", name);
2196aae38d10SBaptiste Daroussin } else if (proportional && !line_capability(name)) {
2197aae38d10SBaptiste Daroussin _nc_warning("non-line capability using proportional delay: %s", name);
2198aae38d10SBaptiste Daroussin } else if (!xon_xoff &&
2199aae38d10SBaptiste Daroussin !mandatory &&
2200*21817992SBaptiste Daroussin strchr(_nc_first_name(tp->term_names), '+') == NULL) {
2201aae38d10SBaptiste Daroussin _nc_warning("%s in %s is used since no xon/xoff",
2202aae38d10SBaptiste Daroussin (proportional
2203aae38d10SBaptiste Daroussin ? "proportional delay"
2204aae38d10SBaptiste Daroussin : "delay"),
2205aae38d10SBaptiste Daroussin name);
2206aae38d10SBaptiste Daroussin }
2207aae38d10SBaptiste Daroussin } else {
2208aae38d10SBaptiste Daroussin p = q - 1; /* restart scan */
2209aae38d10SBaptiste Daroussin }
2210aae38d10SBaptiste Daroussin }
2211aae38d10SBaptiste Daroussin }
2212aae38d10SBaptiste Daroussin
2213aae38d10SBaptiste Daroussin if (!strcmp(name, "flash") ||
2214aae38d10SBaptiste Daroussin !strcmp(name, "beep")) {
2215aae38d10SBaptiste Daroussin
2216aae38d10SBaptiste Daroussin if (first != 0) {
2217aae38d10SBaptiste Daroussin if (first == value || *last == 0) {
2218aae38d10SBaptiste Daroussin /*
2219aae38d10SBaptiste Daroussin * Delay is on one end or the other.
2220aae38d10SBaptiste Daroussin */
2221aae38d10SBaptiste Daroussin _nc_warning("expected delay embedded within %s", name);
2222aae38d10SBaptiste Daroussin }
2223aae38d10SBaptiste Daroussin } else {
2224aae38d10SBaptiste Daroussin int flag;
2225aae38d10SBaptiste Daroussin
2226aae38d10SBaptiste Daroussin /*
2227aae38d10SBaptiste Daroussin * Check for missing delay when using VT100 reverse-video.
2228aae38d10SBaptiste Daroussin * A real VT100 might not need this, but terminal emulators do.
2229aae38d10SBaptiste Daroussin */
2230aae38d10SBaptiste Daroussin if ((p = skip_DECSCNM(value, &flag)) != 0 &&
2231aae38d10SBaptiste Daroussin flag > 0 &&
2232*21817992SBaptiste Daroussin skip_DECSCNM(p, &flag) != 0 &&
2233aae38d10SBaptiste Daroussin flag == 0) {
2234aae38d10SBaptiste Daroussin _nc_warning("expected a delay in %s", name);
2235aae38d10SBaptiste Daroussin }
2236aae38d10SBaptiste Daroussin }
2237aae38d10SBaptiste Daroussin }
2238aae38d10SBaptiste Daroussin }
2239aae38d10SBaptiste Daroussin
2240aae38d10SBaptiste Daroussin static char *
check_1_infotocap(const char * name,NCURSES_CONST char * value,int count)2241aae38d10SBaptiste Daroussin check_1_infotocap(const char *name, NCURSES_CONST char *value, int count)
2242aae38d10SBaptiste Daroussin {
2243aae38d10SBaptiste Daroussin int k;
2244aae38d10SBaptiste Daroussin int ignored;
2245aae38d10SBaptiste Daroussin long numbers[1 + NUM_PARM];
2246aae38d10SBaptiste Daroussin char *strings[1 + NUM_PARM];
2247aae38d10SBaptiste Daroussin char *p_is_s[NUM_PARM];
2248aae38d10SBaptiste Daroussin char *result;
2249aae38d10SBaptiste Daroussin char blob[NUM_PARM * 10];
2250aae38d10SBaptiste Daroussin char *next = blob;
22517a656419SBaptiste Daroussin TParams expect;
22527a656419SBaptiste Daroussin TParams actual;
22537a656419SBaptiste Daroussin int nparam;
2254aae38d10SBaptiste Daroussin
2255aae38d10SBaptiste Daroussin *next++ = '\0';
2256aae38d10SBaptiste Daroussin for (k = 1; k <= NUM_PARM; k++) {
2257aae38d10SBaptiste Daroussin numbers[k] = count;
2258aae38d10SBaptiste Daroussin _nc_SPRINTF(next,
2259aae38d10SBaptiste Daroussin _nc_SLIMIT(sizeof(blob) - (size_t) (next - blob))
2260aae38d10SBaptiste Daroussin "XYZ%d", count);
2261aae38d10SBaptiste Daroussin strings[k] = next;
2262aae38d10SBaptiste Daroussin next += strlen(next) + 1;
2263aae38d10SBaptiste Daroussin }
2264aae38d10SBaptiste Daroussin
2265*21817992SBaptiste Daroussin _nc_reset_tparm(NULL);
22667a656419SBaptiste Daroussin expect = tparm_type(name);
2267*21817992SBaptiste Daroussin nparam = _nc_tparm_analyze(NULL, value, p_is_s, &ignored);
22687a656419SBaptiste Daroussin actual = guess_tparm_type(nparam, p_is_s);
22697a656419SBaptiste Daroussin
22707a656419SBaptiste Daroussin if (expect != actual) {
22717a656419SBaptiste Daroussin _nc_warning("%s has mismatched parameters", name);
22727a656419SBaptiste Daroussin actual = Other;
22737a656419SBaptiste Daroussin }
22747a656419SBaptiste Daroussin
2275*21817992SBaptiste Daroussin _nc_reset_tparm(NULL);
22767a656419SBaptiste Daroussin switch (actual) {
2277*21817992SBaptiste Daroussin case Str:
2278*21817992SBaptiste Daroussin result = TPARM_1(value, strings[1]);
2279*21817992SBaptiste Daroussin break;
2280aae38d10SBaptiste Daroussin case Num_Str:
2281aae38d10SBaptiste Daroussin result = TPARM_2(value, numbers[1], strings[2]);
2282aae38d10SBaptiste Daroussin break;
2283*21817992SBaptiste Daroussin case Str_Str:
2284*21817992SBaptiste Daroussin result = TPARM_2(value, strings[1], strings[2]);
2285*21817992SBaptiste Daroussin break;
2286aae38d10SBaptiste Daroussin case Num_Str_Str:
2287aae38d10SBaptiste Daroussin result = TPARM_3(value, numbers[1], strings[2], strings[3]);
2288aae38d10SBaptiste Daroussin break;
2289aae38d10SBaptiste Daroussin case Numbers:
22907a656419SBaptiste Daroussin #define myParam(n) numbers[n]
22917a656419SBaptiste Daroussin result = TIPARM_9(value,
22927a656419SBaptiste Daroussin myParam(1),
22937a656419SBaptiste Daroussin myParam(2),
22947a656419SBaptiste Daroussin myParam(3),
22957a656419SBaptiste Daroussin myParam(4),
22967a656419SBaptiste Daroussin myParam(5),
22977a656419SBaptiste Daroussin myParam(6),
22987a656419SBaptiste Daroussin myParam(7),
22997a656419SBaptiste Daroussin myParam(8),
23007a656419SBaptiste Daroussin myParam(9));
23017a656419SBaptiste Daroussin #undef myParam
23027a656419SBaptiste Daroussin break;
23037a656419SBaptiste Daroussin case Other:
2304aae38d10SBaptiste Daroussin default:
2305aae38d10SBaptiste Daroussin #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n])
2306aae38d10SBaptiste Daroussin result = TPARM_9(value,
2307aae38d10SBaptiste Daroussin myParam(1),
2308aae38d10SBaptiste Daroussin myParam(2),
2309aae38d10SBaptiste Daroussin myParam(3),
2310aae38d10SBaptiste Daroussin myParam(4),
2311aae38d10SBaptiste Daroussin myParam(5),
2312aae38d10SBaptiste Daroussin myParam(6),
2313aae38d10SBaptiste Daroussin myParam(7),
2314aae38d10SBaptiste Daroussin myParam(8),
2315aae38d10SBaptiste Daroussin myParam(9));
23167a656419SBaptiste Daroussin #undef myParam
2317aae38d10SBaptiste Daroussin break;
2318aae38d10SBaptiste Daroussin }
2319aae38d10SBaptiste Daroussin return strdup(result);
2320aae38d10SBaptiste Daroussin }
2321aae38d10SBaptiste Daroussin
2322aae38d10SBaptiste Daroussin #define IsDelay(ch) ((ch) == '.' || isdigit(UChar(ch)))
2323aae38d10SBaptiste Daroussin
2324aae38d10SBaptiste Daroussin static const char *
parse_delay_value(const char * src,double * delays,int * always)2325aae38d10SBaptiste Daroussin parse_delay_value(const char *src, double *delays, int *always)
2326aae38d10SBaptiste Daroussin {
2327aae38d10SBaptiste Daroussin int star = 0;
2328aae38d10SBaptiste Daroussin
2329aae38d10SBaptiste Daroussin *delays = 0.0;
2330aae38d10SBaptiste Daroussin if (always)
2331aae38d10SBaptiste Daroussin *always = 0;
2332aae38d10SBaptiste Daroussin
2333aae38d10SBaptiste Daroussin while (isdigit(UChar(*src))) {
2334aae38d10SBaptiste Daroussin (*delays) = (*delays) * 10 + (*src++ - '0');
2335aae38d10SBaptiste Daroussin }
2336aae38d10SBaptiste Daroussin if (*src == '.') {
2337aae38d10SBaptiste Daroussin int gotdot = 1;
2338aae38d10SBaptiste Daroussin
2339aae38d10SBaptiste Daroussin ++src;
2340aae38d10SBaptiste Daroussin while (isdigit(UChar(*src))) {
2341aae38d10SBaptiste Daroussin gotdot *= 10;
2342aae38d10SBaptiste Daroussin (*delays) += (*src++ - '0') / gotdot;
2343aae38d10SBaptiste Daroussin }
2344aae38d10SBaptiste Daroussin }
2345aae38d10SBaptiste Daroussin while (*src == '*' || *src == '/') {
2346*21817992SBaptiste Daroussin if (always == NULL && *src == '/')
2347aae38d10SBaptiste Daroussin break;
2348aae38d10SBaptiste Daroussin if (*src++ == '*') {
2349aae38d10SBaptiste Daroussin star = 1;
2350aae38d10SBaptiste Daroussin } else {
2351aae38d10SBaptiste Daroussin *always = 1;
2352aae38d10SBaptiste Daroussin }
2353aae38d10SBaptiste Daroussin }
2354aae38d10SBaptiste Daroussin if (star)
2355aae38d10SBaptiste Daroussin *delays = -(*delays);
2356aae38d10SBaptiste Daroussin return src;
2357aae38d10SBaptiste Daroussin }
2358aae38d10SBaptiste Daroussin
2359aae38d10SBaptiste Daroussin static const char *
parse_ti_delay(const char * ti,double * delays)2360aae38d10SBaptiste Daroussin parse_ti_delay(const char *ti, double *delays)
2361aae38d10SBaptiste Daroussin {
2362aae38d10SBaptiste Daroussin *delays = 0.0;
2363aae38d10SBaptiste Daroussin while (*ti != '\0') {
2364aae38d10SBaptiste Daroussin if (*ti == '\\') {
2365aae38d10SBaptiste Daroussin ++ti;
2366aae38d10SBaptiste Daroussin }
2367aae38d10SBaptiste Daroussin if (ti[0] == '$'
2368aae38d10SBaptiste Daroussin && ti[1] == '<'
2369aae38d10SBaptiste Daroussin && IsDelay(UChar(ti[2]))) {
2370aae38d10SBaptiste Daroussin int ignored;
2371aae38d10SBaptiste Daroussin const char *last = parse_delay_value(ti + 2, delays, &ignored);
2372aae38d10SBaptiste Daroussin if (*last == '>') {
2373aae38d10SBaptiste Daroussin ti = last;
2374aae38d10SBaptiste Daroussin }
2375aae38d10SBaptiste Daroussin } else {
2376aae38d10SBaptiste Daroussin ++ti;
2377aae38d10SBaptiste Daroussin }
2378aae38d10SBaptiste Daroussin }
2379aae38d10SBaptiste Daroussin return ti;
2380aae38d10SBaptiste Daroussin }
2381aae38d10SBaptiste Daroussin
2382aae38d10SBaptiste Daroussin static const char *
parse_tc_delay(const char * tc,double * delays)2383aae38d10SBaptiste Daroussin parse_tc_delay(const char *tc, double *delays)
2384aae38d10SBaptiste Daroussin {
2385aae38d10SBaptiste Daroussin return parse_delay_value(tc, delays, (int *) 0);
2386aae38d10SBaptiste Daroussin }
2387aae38d10SBaptiste Daroussin
2388aae38d10SBaptiste Daroussin /*
2389aae38d10SBaptiste Daroussin * Compare terminfo- and termcap-strings, factoring out delays.
2390aae38d10SBaptiste Daroussin */
2391aae38d10SBaptiste Daroussin static bool
same_ti_tc(const char * ti,const char * tc,bool * embedded)2392aae38d10SBaptiste Daroussin same_ti_tc(const char *ti, const char *tc, bool * embedded)
2393aae38d10SBaptiste Daroussin {
2394aae38d10SBaptiste Daroussin bool same = TRUE;
2395aae38d10SBaptiste Daroussin double ti_delay = 0.0;
2396aae38d10SBaptiste Daroussin double tc_delay = 0.0;
2397aae38d10SBaptiste Daroussin const char *ti_last;
2398aae38d10SBaptiste Daroussin
2399aae38d10SBaptiste Daroussin *embedded = FALSE;
2400aae38d10SBaptiste Daroussin ti_last = parse_ti_delay(ti, &ti_delay);
2401aae38d10SBaptiste Daroussin tc = parse_tc_delay(tc, &tc_delay);
2402aae38d10SBaptiste Daroussin
2403aae38d10SBaptiste Daroussin while ((ti < ti_last) && *tc) {
2404aae38d10SBaptiste Daroussin if (*ti == '\\' && ispunct(UChar(ti[1]))) {
2405aae38d10SBaptiste Daroussin ++ti;
2406aae38d10SBaptiste Daroussin if ((*ti == '^') && !strncmp(tc, "\\136", 4)) {
2407aae38d10SBaptiste Daroussin ti += 1;
2408aae38d10SBaptiste Daroussin tc += 4;
2409aae38d10SBaptiste Daroussin continue;
2410aae38d10SBaptiste Daroussin }
2411aae38d10SBaptiste Daroussin } else if (ti[0] == '$' && ti[1] == '<') {
2412aae38d10SBaptiste Daroussin double no_delay;
2413aae38d10SBaptiste Daroussin const char *ss = parse_ti_delay(ti, &no_delay);
2414aae38d10SBaptiste Daroussin if (ss != ti) {
2415aae38d10SBaptiste Daroussin *embedded = TRUE;
2416aae38d10SBaptiste Daroussin ti = ss;
2417aae38d10SBaptiste Daroussin continue;
2418aae38d10SBaptiste Daroussin }
2419aae38d10SBaptiste Daroussin }
2420aae38d10SBaptiste Daroussin if (*tc == '\\' && ispunct(UChar(tc[1]))) {
2421aae38d10SBaptiste Daroussin ++tc;
2422aae38d10SBaptiste Daroussin }
2423aae38d10SBaptiste Daroussin if (*ti++ != *tc++) {
2424aae38d10SBaptiste Daroussin same = FALSE;
2425aae38d10SBaptiste Daroussin break;
2426aae38d10SBaptiste Daroussin }
2427aae38d10SBaptiste Daroussin }
2428aae38d10SBaptiste Daroussin
2429aae38d10SBaptiste Daroussin if (*embedded) {
2430aae38d10SBaptiste Daroussin if (same) {
2431aae38d10SBaptiste Daroussin same = FALSE;
2432aae38d10SBaptiste Daroussin } else {
2433aae38d10SBaptiste Daroussin *embedded = FALSE; /* report only one problem */
2434aae38d10SBaptiste Daroussin }
2435aae38d10SBaptiste Daroussin }
2436aae38d10SBaptiste Daroussin
2437aae38d10SBaptiste Daroussin return same;
2438aae38d10SBaptiste Daroussin }
2439aae38d10SBaptiste Daroussin
2440aae38d10SBaptiste Daroussin /*
2441aae38d10SBaptiste Daroussin * Check terminfo to termcap translation.
2442aae38d10SBaptiste Daroussin */
2443aae38d10SBaptiste Daroussin static void
check_infotocap(TERMTYPE2 * tp,int i,const char * value)2444aae38d10SBaptiste Daroussin check_infotocap(TERMTYPE2 *tp, int i, const char *value)
2445aae38d10SBaptiste Daroussin {
2446aae38d10SBaptiste Daroussin const char *name = ExtStrname(tp, i, strnames);
2447*21817992SBaptiste Daroussin char *ti_value = NULL;
2448*21817992SBaptiste Daroussin
2449*21817992SBaptiste Daroussin assert(SIZEOF(parametrized) == STRCOUNT);
2450*21817992SBaptiste Daroussin if (!VALID_STRING(value) || (ti_value = strdup(value)) == NULL) {
2451*21817992SBaptiste Daroussin _nc_warning("tic-expansion of %s failed", name);
2452*21817992SBaptiste Daroussin } else {
2453*21817992SBaptiste Daroussin char *tc_value;
2454*21817992SBaptiste Daroussin bool embedded;
2455aae38d10SBaptiste Daroussin int params = ((i < (int) SIZEOF(parametrized))
2456aae38d10SBaptiste Daroussin ? parametrized[i]
2457aae38d10SBaptiste Daroussin : ((*value == 'k')
2458aae38d10SBaptiste Daroussin ? 0
24597a656419SBaptiste Daroussin : has_params(value, FALSE)));
2460aae38d10SBaptiste Daroussin
2461*21817992SBaptiste Daroussin if ((tc_value = _nc_infotocap(name, ti_value, params)) == ABSENT_STRING) {
2462aae38d10SBaptiste Daroussin _nc_warning("tic-conversion of %s failed", name);
2463aae38d10SBaptiste Daroussin } else if (params > 0) {
2464aae38d10SBaptiste Daroussin int limit = 5;
2465aae38d10SBaptiste Daroussin int count;
2466aae38d10SBaptiste Daroussin bool first = TRUE;
2467aae38d10SBaptiste Daroussin
2468aae38d10SBaptiste Daroussin if (!strcmp(name, "setf")
2469aae38d10SBaptiste Daroussin || !strcmp(name, "setb")
2470aae38d10SBaptiste Daroussin || !strcmp(name, "setaf")
2471aae38d10SBaptiste Daroussin || !strcmp(name, "setab")) {
2472*21817992SBaptiste Daroussin if ((limit = max_colors) > 256)
2473*21817992SBaptiste Daroussin limit = 256;
2474aae38d10SBaptiste Daroussin }
2475aae38d10SBaptiste Daroussin for (count = 0; count < limit; ++count) {
2476aae38d10SBaptiste Daroussin char *ti_check = check_1_infotocap(name, ti_value, count);
2477aae38d10SBaptiste Daroussin char *tc_check = check_1_infotocap(name, tc_value, count);
2478aae38d10SBaptiste Daroussin
2479aae38d10SBaptiste Daroussin if (strcmp(ti_check, tc_check)) {
2480aae38d10SBaptiste Daroussin if (first) {
2481aae38d10SBaptiste Daroussin fprintf(stderr, "check_infotocap(%s)\n", name);
24827a656419SBaptiste Daroussin fprintf(stderr, "...ti '%s'\n", _nc_visbuf2(0, ti_value));
24837a656419SBaptiste Daroussin fprintf(stderr, "...tc '%s'\n", _nc_visbuf2(0, tc_value));
2484aae38d10SBaptiste Daroussin first = FALSE;
2485aae38d10SBaptiste Daroussin }
2486aae38d10SBaptiste Daroussin _nc_warning("tparm-conversion of %s(%d) differs between\n\tterminfo %s\n\ttermcap %s",
24877a656419SBaptiste Daroussin name, count,
24887a656419SBaptiste Daroussin _nc_visbuf2(0, ti_check),
24897a656419SBaptiste Daroussin _nc_visbuf2(1, tc_check));
2490aae38d10SBaptiste Daroussin }
2491aae38d10SBaptiste Daroussin free(ti_check);
2492aae38d10SBaptiste Daroussin free(tc_check);
2493aae38d10SBaptiste Daroussin }
2494aae38d10SBaptiste Daroussin } else if (params == 0 && !same_ti_tc(ti_value, tc_value, &embedded)) {
2495aae38d10SBaptiste Daroussin if (embedded) {
2496aae38d10SBaptiste Daroussin _nc_warning("termcap equivalent of %s cannot use embedded delay", name);
2497aae38d10SBaptiste Daroussin } else {
2498aae38d10SBaptiste Daroussin _nc_warning("tic-conversion of %s changed value\n\tfrom %s\n\tto %s",
2499aae38d10SBaptiste Daroussin name, ti_value, tc_value);
2500aae38d10SBaptiste Daroussin }
2501aae38d10SBaptiste Daroussin }
2502*21817992SBaptiste Daroussin free(ti_value);
2503*21817992SBaptiste Daroussin }
250418259542SPeter Wemm }
250518259542SPeter Wemm
2506b82face1SPeter Wemm static char *
skip_delay(char * s)2507b82face1SPeter Wemm skip_delay(char *s)
2508b82face1SPeter Wemm {
2509b82face1SPeter Wemm while (*s == '/' || isdigit(UChar(*s)))
2510b82face1SPeter Wemm ++s;
2511b82face1SPeter Wemm return s;
2512b82face1SPeter Wemm }
2513b82face1SPeter Wemm
251418259542SPeter Wemm /*
25154a1a9510SRong-En Fan * Skip a delay altogether, e.g., when comparing a simple string to sgr,
25164a1a9510SRong-En Fan * the latter may have a worst-case delay on the end.
25174a1a9510SRong-En Fan */
25184a1a9510SRong-En Fan static char *
ignore_delays(char * s)25194a1a9510SRong-En Fan ignore_delays(char *s)
25204a1a9510SRong-En Fan {
25214a1a9510SRong-En Fan int delaying = 0;
25224a1a9510SRong-En Fan
25234a1a9510SRong-En Fan do {
25244a1a9510SRong-En Fan switch (*s) {
25254a1a9510SRong-En Fan case '$':
25264a1a9510SRong-En Fan if (delaying == 0)
25274a1a9510SRong-En Fan delaying = 1;
25284a1a9510SRong-En Fan break;
25294a1a9510SRong-En Fan case '<':
25304a1a9510SRong-En Fan if (delaying == 1)
25314a1a9510SRong-En Fan delaying = 2;
25324a1a9510SRong-En Fan break;
25334a1a9510SRong-En Fan case '\0':
25344a1a9510SRong-En Fan delaying = 0;
25354a1a9510SRong-En Fan break;
25364a1a9510SRong-En Fan default:
25374a1a9510SRong-En Fan if (delaying) {
25384a1a9510SRong-En Fan s = skip_delay(s);
25394a1a9510SRong-En Fan if (*s == '>')
25404a1a9510SRong-En Fan ++s;
25414a1a9510SRong-En Fan delaying = 0;
25424a1a9510SRong-En Fan }
25434a1a9510SRong-En Fan break;
25444a1a9510SRong-En Fan }
25454a1a9510SRong-En Fan if (delaying)
25464a1a9510SRong-En Fan ++s;
25474a1a9510SRong-En Fan } while (delaying);
25484a1a9510SRong-En Fan return s;
25494a1a9510SRong-En Fan }
25504a1a9510SRong-En Fan
2551aae38d10SBaptiste Daroussin #define DATA(name) { #name }
2552aae38d10SBaptiste Daroussin static const char sgr_names[][11] =
2553aae38d10SBaptiste Daroussin {
2554aae38d10SBaptiste Daroussin DATA(none),
2555aae38d10SBaptiste Daroussin DATA(standout),
2556aae38d10SBaptiste Daroussin DATA(underline),
2557aae38d10SBaptiste Daroussin DATA(reverse),
2558aae38d10SBaptiste Daroussin DATA(blink),
2559aae38d10SBaptiste Daroussin DATA(dim),
2560aae38d10SBaptiste Daroussin DATA(bold),
2561aae38d10SBaptiste Daroussin DATA(invis),
2562aae38d10SBaptiste Daroussin DATA(protect),
2563aae38d10SBaptiste Daroussin DATA(altcharset),
2564aae38d10SBaptiste Daroussin ""
2565aae38d10SBaptiste Daroussin };
2566aae38d10SBaptiste Daroussin #undef DATA
2567aae38d10SBaptiste Daroussin
25684a1a9510SRong-En Fan /*
256915589c42SPeter Wemm * An sgr string may contain several settings other than the one we're
257015589c42SPeter Wemm * interested in, essentially sgr0 + rmacs + whatever. As long as the
257115589c42SPeter Wemm * "whatever" is contained in the sgr string, that is close enough for our
257215589c42SPeter Wemm * sanity check.
257315589c42SPeter Wemm */
257415589c42SPeter Wemm static bool
similar_sgr(int num,char * a,char * b)2575b82face1SPeter Wemm similar_sgr(int num, char *a, char *b)
257615589c42SPeter Wemm {
2577b82face1SPeter Wemm char *base_a = a;
2578b82face1SPeter Wemm char *base_b = b;
2579b82face1SPeter Wemm int delaying = 0;
2580b82face1SPeter Wemm
258115589c42SPeter Wemm while (*b != 0) {
258215589c42SPeter Wemm while (*a != *b) {
25837a69bbfbSPeter Wemm if (*a == 0) {
2584aae38d10SBaptiste Daroussin if (num < 0) {
2585aae38d10SBaptiste Daroussin ;
2586aae38d10SBaptiste Daroussin } else if (b[0] == '$'
25877a69bbfbSPeter Wemm && b[1] == '<') {
2588aae38d10SBaptiste Daroussin _nc_warning("did not find delay %s", _nc_visbuf(b));
25897a69bbfbSPeter Wemm } else {
2590b82face1SPeter Wemm _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s",
2591aae38d10SBaptiste Daroussin sgr_names[num], _nc_visbuf2(1, base_a),
2592b82face1SPeter Wemm _nc_visbuf2(2, base_b),
2593b82face1SPeter Wemm _nc_visbuf2(3, b));
25947a69bbfbSPeter Wemm }
259515589c42SPeter Wemm return FALSE;
2596b82face1SPeter Wemm } else if (delaying) {
2597b82face1SPeter Wemm a = skip_delay(a);
2598b82face1SPeter Wemm b = skip_delay(b);
259906bfebdeSXin LI } else if ((*b == '0' || (*b == ';')) && *a == 'm') {
260006bfebdeSXin LI b++;
2601b82face1SPeter Wemm } else {
260215589c42SPeter Wemm a++;
260315589c42SPeter Wemm }
2604b82face1SPeter Wemm }
2605b82face1SPeter Wemm switch (*a) {
2606b82face1SPeter Wemm case '$':
2607b82face1SPeter Wemm if (delaying == 0)
2608b82face1SPeter Wemm delaying = 1;
2609b82face1SPeter Wemm break;
2610b82face1SPeter Wemm case '<':
2611b82face1SPeter Wemm if (delaying == 1)
2612b82face1SPeter Wemm delaying = 2;
2613b82face1SPeter Wemm break;
2614b82face1SPeter Wemm default:
2615b82face1SPeter Wemm delaying = 0;
2616b82face1SPeter Wemm break;
2617b82face1SPeter Wemm }
261815589c42SPeter Wemm a++;
261915589c42SPeter Wemm b++;
262015589c42SPeter Wemm }
26214a1a9510SRong-En Fan /* ignore delays on the end of the string */
26224a1a9510SRong-En Fan a = ignore_delays(a);
26234a1a9510SRong-En Fan return ((num != 0) || (*a == 0));
262415589c42SPeter Wemm }
262515589c42SPeter Wemm
26267a656419SBaptiste Daroussin static void
check_tparm_err(int num)26277a656419SBaptiste Daroussin check_tparm_err(int num)
26287a656419SBaptiste Daroussin {
26297a656419SBaptiste Daroussin if (_nc_tparm_err)
26307a656419SBaptiste Daroussin _nc_warning("tparam error in sgr(%d): %s", num, sgr_names[num]);
26317a656419SBaptiste Daroussin }
26327a656419SBaptiste Daroussin
26334a1a9510SRong-En Fan static char *
check_sgr(TERMTYPE2 * tp,char * zero,int num,char * cap,const char * name)2634aae38d10SBaptiste Daroussin check_sgr(TERMTYPE2 *tp, char *zero, int num, char *cap, const char *name)
263515589c42SPeter Wemm {
26364a1a9510SRong-En Fan char *test;
26374a1a9510SRong-En Fan
26384a1a9510SRong-En Fan _nc_tparm_err = 0;
26397a656419SBaptiste Daroussin test = TIPARM_9(set_attributes,
264015589c42SPeter Wemm num == 1,
264115589c42SPeter Wemm num == 2,
264215589c42SPeter Wemm num == 3,
264315589c42SPeter Wemm num == 4,
264415589c42SPeter Wemm num == 5,
264515589c42SPeter Wemm num == 6,
264615589c42SPeter Wemm num == 7,
264715589c42SPeter Wemm num == 8,
264815589c42SPeter Wemm num == 9);
264915589c42SPeter Wemm if (test != 0) {
265015589c42SPeter Wemm if (PRESENT(cap)) {
2651b82face1SPeter Wemm if (!similar_sgr(num, test, cap)) {
2652b82face1SPeter Wemm _nc_warning("%s differs from sgr(%d)\n\t%s=%s\n\tsgr(%d)=%s",
2653b82face1SPeter Wemm name, num,
2654b82face1SPeter Wemm name, _nc_visbuf2(1, cap),
2655b82face1SPeter Wemm num, _nc_visbuf2(2, test));
265615589c42SPeter Wemm }
26574a1a9510SRong-En Fan } else if (_nc_capcmp(test, zero)) {
265815589c42SPeter Wemm _nc_warning("sgr(%d) present, but not %s", num, name);
265915589c42SPeter Wemm }
266015589c42SPeter Wemm } else if (PRESENT(cap)) {
266115589c42SPeter Wemm _nc_warning("sgr(%d) missing, but %s present", num, name);
266215589c42SPeter Wemm }
26637a656419SBaptiste Daroussin check_tparm_err(num);
26644a1a9510SRong-En Fan return test;
266515589c42SPeter Wemm }
266615589c42SPeter Wemm
266715589c42SPeter Wemm #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)
266815589c42SPeter Wemm
26694a1a9510SRong-En Fan #ifdef TRACE
26704a1a9510SRong-En Fan /*
26714a1a9510SRong-En Fan * If tic is compiled with TRACE, we'll be able to see the output from the
26724a1a9510SRong-En Fan * DEBUG() macro. But since it doesn't use traceon(), it always goes to
26734a1a9510SRong-En Fan * the standard error. Use this function to make it simpler to follow the
26744a1a9510SRong-En Fan * resulting debug traces.
26754a1a9510SRong-En Fan */
26764a1a9510SRong-En Fan static void
show_where(unsigned level)26774a1a9510SRong-En Fan show_where(unsigned level)
26784a1a9510SRong-En Fan {
26794a1a9510SRong-En Fan if (_nc_tracing >= DEBUG_LEVEL(level)) {
268073f0a83dSXin LI char my_name[MAX_NAME_SIZE];
26814a1a9510SRong-En Fan _nc_get_type(my_name);
268206bfebdeSXin LI _tracef("\"%s\", line %d, '%s'",
26834a1a9510SRong-En Fan _nc_get_source(),
26844a1a9510SRong-En Fan _nc_curr_line, my_name);
26854a1a9510SRong-En Fan }
26864a1a9510SRong-En Fan }
26874a1a9510SRong-En Fan
26884a1a9510SRong-En Fan #else
26894a1a9510SRong-En Fan #define show_where(level) /* nothing */
26904a1a9510SRong-En Fan #endif
26914a1a9510SRong-En Fan
269273f0a83dSXin LI typedef struct {
269373f0a83dSXin LI int keycode;
269473f0a83dSXin LI const char *name;
269573f0a83dSXin LI const char *value;
269673f0a83dSXin LI } NAME_VALUE;
269773f0a83dSXin LI
269873f0a83dSXin LI static NAME_VALUE *
get_fkey_list(TERMTYPE2 * tp)2699aae38d10SBaptiste Daroussin get_fkey_list(TERMTYPE2 *tp)
270073f0a83dSXin LI {
270173f0a83dSXin LI NAME_VALUE *result = typeMalloc(NAME_VALUE, NUM_STRINGS(tp) + 1);
270273f0a83dSXin LI const struct tinfo_fkeys *all_fkeys = _nc_tinfo_fkeys;
270373f0a83dSXin LI int used = 0;
2704aae38d10SBaptiste Daroussin unsigned j;
270573f0a83dSXin LI
2706*21817992SBaptiste Daroussin if (result == NULL)
270773f0a83dSXin LI failed("get_fkey_list");
270873f0a83dSXin LI
270973f0a83dSXin LI for (j = 0; all_fkeys[j].code; j++) {
271073f0a83dSXin LI char *a = tp->Strings[all_fkeys[j].offset];
271173f0a83dSXin LI if (VALID_STRING(a)) {
271273f0a83dSXin LI result[used].keycode = (int) all_fkeys[j].code;
271373f0a83dSXin LI result[used].name = strnames[all_fkeys[j].offset];
271473f0a83dSXin LI result[used].value = a;
271573f0a83dSXin LI ++used;
271673f0a83dSXin LI }
271773f0a83dSXin LI }
271873f0a83dSXin LI #if NCURSES_XNAMES
271973f0a83dSXin LI for (j = STRCOUNT; j < NUM_STRINGS(tp); ++j) {
2720aae38d10SBaptiste Daroussin const char *name = ExtStrname(tp, (int) j, strnames);
272173f0a83dSXin LI if (*name == 'k') {
272273f0a83dSXin LI result[used].keycode = -1;
272373f0a83dSXin LI result[used].name = name;
272473f0a83dSXin LI result[used].value = tp->Strings[j];
272573f0a83dSXin LI ++used;
272673f0a83dSXin LI }
272773f0a83dSXin LI }
272873f0a83dSXin LI #endif
272973f0a83dSXin LI result[used].keycode = 0;
273073f0a83dSXin LI return result;
273173f0a83dSXin LI }
273273f0a83dSXin LI
273373f0a83dSXin LI static void
show_fkey_name(NAME_VALUE * data)273473f0a83dSXin LI show_fkey_name(NAME_VALUE * data)
273573f0a83dSXin LI {
273673f0a83dSXin LI if (data->keycode > 0) {
273773f0a83dSXin LI fprintf(stderr, " %s", keyname(data->keycode));
273873f0a83dSXin LI fprintf(stderr, " (capability \"%s\")", data->name);
273973f0a83dSXin LI } else {
274073f0a83dSXin LI fprintf(stderr, " capability \"%s\"", data->name);
274173f0a83dSXin LI }
274273f0a83dSXin LI }
274373f0a83dSXin LI
2744aae38d10SBaptiste Daroussin /*
2745aae38d10SBaptiste Daroussin * A terminal entry may contain more than one keycode assigned to a given
2746aae38d10SBaptiste Daroussin * string (e.g., KEY_END and KEY_LL). But curses will only return one (the
2747aae38d10SBaptiste Daroussin * last one assigned).
27480e3d5408SPeter Wemm */
274915589c42SPeter Wemm static void
check_conflict(TERMTYPE2 * tp)2750aae38d10SBaptiste Daroussin check_conflict(TERMTYPE2 *tp)
27510e3d5408SPeter Wemm {
27524a1a9510SRong-En Fan if (!(_nc_syntax == SYN_TERMCAP && capdump)) {
275373f0a83dSXin LI char *check = calloc((size_t) (NUM_STRINGS(tp) + 1), sizeof(char));
275473f0a83dSXin LI NAME_VALUE *given = get_fkey_list(tp);
2755*21817992SBaptiste Daroussin unsigned j, k;
2756*21817992SBaptiste Daroussin bool conflict = FALSE;
275773f0a83dSXin LI
2758*21817992SBaptiste Daroussin if (check == NULL)
2759aae38d10SBaptiste Daroussin failed("check_conflict");
276073f0a83dSXin LI
276173f0a83dSXin LI for (j = 0; given[j].keycode; ++j) {
276273f0a83dSXin LI const char *a = given[j].value;
27630e3d5408SPeter Wemm bool first = TRUE;
276473f0a83dSXin LI
2765aae38d10SBaptiste Daroussin if (!VALID_STRING(a))
2766aae38d10SBaptiste Daroussin continue;
2767aae38d10SBaptiste Daroussin
276873f0a83dSXin LI for (k = j + 1; given[k].keycode; k++) {
276973f0a83dSXin LI const char *b = given[k].value;
2770aae38d10SBaptiste Daroussin
2771aae38d10SBaptiste Daroussin if (!VALID_STRING(b))
2772aae38d10SBaptiste Daroussin continue;
277373f0a83dSXin LI if (check[k])
27740e3d5408SPeter Wemm continue;
2775aae38d10SBaptiste Daroussin
27764a1a9510SRong-En Fan if (!_nc_capcmp(a, b)) {
277773f0a83dSXin LI check[j] = 1;
277873f0a83dSXin LI check[k] = 1;
27790e3d5408SPeter Wemm if (first) {
27800e3d5408SPeter Wemm if (!conflict) {
2781aae38d10SBaptiste Daroussin _nc_warning("conflicting key definitions (using the last)");
27820e3d5408SPeter Wemm conflict = TRUE;
27830e3d5408SPeter Wemm }
278473f0a83dSXin LI fprintf(stderr, "...");
278573f0a83dSXin LI show_fkey_name(given + j);
278673f0a83dSXin LI fprintf(stderr, " is the same as");
278773f0a83dSXin LI show_fkey_name(given + k);
27880e3d5408SPeter Wemm first = FALSE;
27890e3d5408SPeter Wemm } else {
279073f0a83dSXin LI fprintf(stderr, ", ");
279173f0a83dSXin LI show_fkey_name(given + k);
27920e3d5408SPeter Wemm }
27930e3d5408SPeter Wemm }
27940e3d5408SPeter Wemm }
27950e3d5408SPeter Wemm if (!first)
27960e3d5408SPeter Wemm fprintf(stderr, "\n");
27970e3d5408SPeter Wemm }
2798aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
2799aae38d10SBaptiste Daroussin if (using_extensions) {
2800aae38d10SBaptiste Daroussin /* *INDENT-OFF* */
2801aae38d10SBaptiste Daroussin static struct {
2802aae38d10SBaptiste Daroussin const char *xcurses;
2803aae38d10SBaptiste Daroussin const char *shifted;
2804aae38d10SBaptiste Daroussin } table[] = {
2805aae38d10SBaptiste Daroussin { "kDC", NULL },
2806aae38d10SBaptiste Daroussin { "kDN", "kind" },
2807aae38d10SBaptiste Daroussin { "kEND", NULL },
2808aae38d10SBaptiste Daroussin { "kHOM", NULL },
2809aae38d10SBaptiste Daroussin { "kLFT", NULL },
2810aae38d10SBaptiste Daroussin { "kNXT", NULL },
2811aae38d10SBaptiste Daroussin { "kPRV", NULL },
2812aae38d10SBaptiste Daroussin { "kRIT", NULL },
2813aae38d10SBaptiste Daroussin { "kUP", "kri" },
2814aae38d10SBaptiste Daroussin { NULL, NULL },
2815aae38d10SBaptiste Daroussin };
2816aae38d10SBaptiste Daroussin /* *INDENT-ON* */
2817aae38d10SBaptiste Daroussin /*
2818aae38d10SBaptiste Daroussin * SVr4 curses defines the "xcurses" names listed above except for
2819aae38d10SBaptiste Daroussin * the special cases in the "shifted" column. When using these
2820aae38d10SBaptiste Daroussin * names for xterm's extensions, that was confusing, and resulted
2821aae38d10SBaptiste Daroussin * in adding extended capabilities with "2" (shift) suffix. This
2822aae38d10SBaptiste Daroussin * check warns about unnecessary use of extensions for this quirk.
2823aae38d10SBaptiste Daroussin */
2824aae38d10SBaptiste Daroussin for (j = 0; given[j].keycode; ++j) {
2825aae38d10SBaptiste Daroussin const char *find = given[j].name;
2826aae38d10SBaptiste Daroussin int value;
2827aae38d10SBaptiste Daroussin char ch;
2828aae38d10SBaptiste Daroussin
2829aae38d10SBaptiste Daroussin if (!VALID_STRING(given[j].value))
2830aae38d10SBaptiste Daroussin continue;
2831aae38d10SBaptiste Daroussin
2832aae38d10SBaptiste Daroussin for (k = 0; table[k].xcurses; ++k) {
2833aae38d10SBaptiste Daroussin const char *test = table[k].xcurses;
2834aae38d10SBaptiste Daroussin size_t size = strlen(test);
2835aae38d10SBaptiste Daroussin
2836aae38d10SBaptiste Daroussin if (!strncmp(find, test, size) && strcmp(find, test)) {
2837aae38d10SBaptiste Daroussin switch (sscanf(find + size, "%d%c", &value, &ch)) {
2838aae38d10SBaptiste Daroussin case 1:
2839aae38d10SBaptiste Daroussin if (value == 2) {
2840aae38d10SBaptiste Daroussin _nc_warning("expected '%s' rather than '%s'",
2841aae38d10SBaptiste Daroussin (table[k].shifted
2842aae38d10SBaptiste Daroussin ? table[k].shifted
2843aae38d10SBaptiste Daroussin : test), find);
2844aae38d10SBaptiste Daroussin } else if (value < 2 || value > 15) {
2845aae38d10SBaptiste Daroussin _nc_warning("expected numeric 2..15 '%s'", find);
2846aae38d10SBaptiste Daroussin }
2847aae38d10SBaptiste Daroussin break;
2848aae38d10SBaptiste Daroussin default:
2849aae38d10SBaptiste Daroussin _nc_warning("expected numeric suffix for '%s'", find);
2850aae38d10SBaptiste Daroussin break;
2851aae38d10SBaptiste Daroussin }
2852aae38d10SBaptiste Daroussin break;
2853aae38d10SBaptiste Daroussin }
2854aae38d10SBaptiste Daroussin }
2855aae38d10SBaptiste Daroussin }
2856aae38d10SBaptiste Daroussin }
2857aae38d10SBaptiste Daroussin #endif
285873f0a83dSXin LI free(given);
285973f0a83dSXin LI free(check);
28604a1a9510SRong-En Fan }
2861aae38d10SBaptiste Daroussin }
2862aae38d10SBaptiste Daroussin
2863aae38d10SBaptiste Daroussin /*
2864aae38d10SBaptiste Daroussin * Exiting a video mode should not duplicate sgr0
2865aae38d10SBaptiste Daroussin */
2866aae38d10SBaptiste Daroussin static void
check_exit_attribute(const char * name,char * test,char * trimmed,char * untrimmed)2867aae38d10SBaptiste Daroussin check_exit_attribute(const char *name, char *test, char *trimmed, char *untrimmed)
2868aae38d10SBaptiste Daroussin {
2869aae38d10SBaptiste Daroussin if (VALID_STRING(test) && (trimmed != 0)) {
2870aae38d10SBaptiste Daroussin if (similar_sgr(-1, trimmed, test) ||
2871aae38d10SBaptiste Daroussin similar_sgr(-1, untrimmed, test)) {
2872aae38d10SBaptiste Daroussin _nc_warning("%s matches exit_attribute_mode", name);
2873aae38d10SBaptiste Daroussin }
2874aae38d10SBaptiste Daroussin }
2875aae38d10SBaptiste Daroussin }
2876aae38d10SBaptiste Daroussin
2877aae38d10SBaptiste Daroussin /*
2878aae38d10SBaptiste Daroussin * Returns true if the string looks like a standard SGR string.
2879aae38d10SBaptiste Daroussin */
2880aae38d10SBaptiste Daroussin static bool
is_sgr_string(char * value)2881aae38d10SBaptiste Daroussin is_sgr_string(char *value)
2882aae38d10SBaptiste Daroussin {
2883aae38d10SBaptiste Daroussin bool result = FALSE;
2884aae38d10SBaptiste Daroussin
2885aae38d10SBaptiste Daroussin if (VALID_STRING(value)) {
2886aae38d10SBaptiste Daroussin int skip = csi_length(value);
2887aae38d10SBaptiste Daroussin
2888aae38d10SBaptiste Daroussin if (skip) {
2889aae38d10SBaptiste Daroussin int ch;
2890aae38d10SBaptiste Daroussin
2891aae38d10SBaptiste Daroussin result = TRUE;
2892aae38d10SBaptiste Daroussin value += skip;
2893aae38d10SBaptiste Daroussin while ((ch = UChar(*value++)) != '\0') {
2894aae38d10SBaptiste Daroussin if (isdigit(ch) || ch == ';') {
2895aae38d10SBaptiste Daroussin ;
2896aae38d10SBaptiste Daroussin } else if (ch == 'm' && *value == '\0') {
2897aae38d10SBaptiste Daroussin ;
2898aae38d10SBaptiste Daroussin } else {
2899aae38d10SBaptiste Daroussin result = FALSE;
2900aae38d10SBaptiste Daroussin break;
2901aae38d10SBaptiste Daroussin }
2902aae38d10SBaptiste Daroussin }
2903aae38d10SBaptiste Daroussin }
2904aae38d10SBaptiste Daroussin }
2905aae38d10SBaptiste Daroussin return result;
2906aae38d10SBaptiste Daroussin }
2907aae38d10SBaptiste Daroussin
2908aae38d10SBaptiste Daroussin /*
2909aae38d10SBaptiste Daroussin * Check if the given capability contains a given SGR attribute.
2910aae38d10SBaptiste Daroussin */
2911aae38d10SBaptiste Daroussin static void
check_sgr_param(TERMTYPE2 * tp,int code,const char * name,char * value)2912aae38d10SBaptiste Daroussin check_sgr_param(TERMTYPE2 *tp, int code, const char *name, char *value)
2913aae38d10SBaptiste Daroussin {
2914aae38d10SBaptiste Daroussin if (VALID_STRING(value)) {
2915aae38d10SBaptiste Daroussin int ncv = ((code != 0) ? (1 << (code - 1)) : 0);
2916aae38d10SBaptiste Daroussin char *test = tgoto(value, 0, 0);
2917aae38d10SBaptiste Daroussin if (is_sgr_string(test)) {
2918aae38d10SBaptiste Daroussin int param = 0;
2919aae38d10SBaptiste Daroussin int count = 0;
2920aae38d10SBaptiste Daroussin int skips = 0;
2921aae38d10SBaptiste Daroussin int color = (value == set_a_foreground ||
2922aae38d10SBaptiste Daroussin value == set_a_background ||
2923aae38d10SBaptiste Daroussin value == set_foreground ||
2924aae38d10SBaptiste Daroussin value == set_background);
2925aae38d10SBaptiste Daroussin while (*test != 0) {
2926aae38d10SBaptiste Daroussin if (isdigit(UChar(*test))) {
2927aae38d10SBaptiste Daroussin param = 10 * param + (*test - '0');
2928aae38d10SBaptiste Daroussin ++count;
2929aae38d10SBaptiste Daroussin } else {
2930aae38d10SBaptiste Daroussin if (count) {
2931aae38d10SBaptiste Daroussin /*
2932aae38d10SBaptiste Daroussin * Avoid unnecessary warning for xterm 256color codes.
2933aae38d10SBaptiste Daroussin */
2934aae38d10SBaptiste Daroussin if (color && (param == 38 || param == 48))
2935aae38d10SBaptiste Daroussin skips = 3;
2936aae38d10SBaptiste Daroussin if ((skips-- <= 0) && (param == code))
2937aae38d10SBaptiste Daroussin break;
2938aae38d10SBaptiste Daroussin }
2939aae38d10SBaptiste Daroussin count = 0;
2940aae38d10SBaptiste Daroussin param = 0;
2941aae38d10SBaptiste Daroussin }
2942aae38d10SBaptiste Daroussin ++test;
2943aae38d10SBaptiste Daroussin }
2944aae38d10SBaptiste Daroussin if (count != 0 && param == code) {
2945aae38d10SBaptiste Daroussin if (code == 0 ||
2946aae38d10SBaptiste Daroussin no_color_video < 0 ||
2947aae38d10SBaptiste Daroussin !(no_color_video & ncv)) {
2948aae38d10SBaptiste Daroussin _nc_warning("\"%s\" SGR-attribute used in %s",
2949aae38d10SBaptiste Daroussin sgr_names[code],
2950aae38d10SBaptiste Daroussin name);
2951aae38d10SBaptiste Daroussin }
2952aae38d10SBaptiste Daroussin }
2953aae38d10SBaptiste Daroussin }
2954aae38d10SBaptiste Daroussin }
2955aae38d10SBaptiste Daroussin }
2956aae38d10SBaptiste Daroussin
2957aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
2958aae38d10SBaptiste Daroussin static int
standard_type(const char * name)2959aae38d10SBaptiste Daroussin standard_type(const char *name)
2960aae38d10SBaptiste Daroussin {
2961aae38d10SBaptiste Daroussin int result = -1;
2962aae38d10SBaptiste Daroussin const struct name_table_entry *np;
2963aae38d10SBaptiste Daroussin
2964aae38d10SBaptiste Daroussin if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0) {
2965aae38d10SBaptiste Daroussin result = np->nte_type;
2966aae38d10SBaptiste Daroussin }
2967aae38d10SBaptiste Daroussin return result;
2968aae38d10SBaptiste Daroussin }
2969aae38d10SBaptiste Daroussin
2970aae38d10SBaptiste Daroussin static const char *
name_of_type(int type)2971aae38d10SBaptiste Daroussin name_of_type(int type)
2972aae38d10SBaptiste Daroussin {
2973aae38d10SBaptiste Daroussin const char *result = "unknown";
2974aae38d10SBaptiste Daroussin switch (type) {
2975aae38d10SBaptiste Daroussin case BOOLEAN:
2976aae38d10SBaptiste Daroussin result = "boolean";
2977aae38d10SBaptiste Daroussin break;
2978aae38d10SBaptiste Daroussin case NUMBER:
2979aae38d10SBaptiste Daroussin result = "number";
2980aae38d10SBaptiste Daroussin break;
2981aae38d10SBaptiste Daroussin case STRING:
2982aae38d10SBaptiste Daroussin result = "string";
2983aae38d10SBaptiste Daroussin break;
2984aae38d10SBaptiste Daroussin }
2985aae38d10SBaptiste Daroussin return result;
2986aae38d10SBaptiste Daroussin }
2987aae38d10SBaptiste Daroussin
2988aae38d10SBaptiste Daroussin static void
check_user_capability_type(const char * name,int actual)2989aae38d10SBaptiste Daroussin check_user_capability_type(const char *name, int actual)
2990aae38d10SBaptiste Daroussin {
2991aae38d10SBaptiste Daroussin if (lookup_user_capability(name) == 0) {
2992aae38d10SBaptiste Daroussin int expected = standard_type(name);
2993aae38d10SBaptiste Daroussin if (expected >= 0) {
2994aae38d10SBaptiste Daroussin _nc_warning("expected %s to be %s, but actually %s",
2995aae38d10SBaptiste Daroussin name,
2996aae38d10SBaptiste Daroussin name_of_type(actual),
2997aae38d10SBaptiste Daroussin name_of_type(expected)
2998aae38d10SBaptiste Daroussin );
2999aae38d10SBaptiste Daroussin } else if (*name != 'k') {
3000aae38d10SBaptiste Daroussin _nc_warning("undocumented %s capability %s",
3001aae38d10SBaptiste Daroussin name_of_type(actual),
3002aae38d10SBaptiste Daroussin name);
3003aae38d10SBaptiste Daroussin }
3004aae38d10SBaptiste Daroussin }
3005aae38d10SBaptiste Daroussin }
3006aae38d10SBaptiste Daroussin #endif
3007aae38d10SBaptiste Daroussin
3008*21817992SBaptiste Daroussin #define IN_DELAY "0123456789*/."
3009*21817992SBaptiste Daroussin
3010*21817992SBaptiste Daroussin static bool
check_ANSI_cap(const char * value,int nparams,char final)3011*21817992SBaptiste Daroussin check_ANSI_cap(const char *value, int nparams, char final)
3012*21817992SBaptiste Daroussin {
3013*21817992SBaptiste Daroussin bool result = FALSE;
3014*21817992SBaptiste Daroussin if (VALID_STRING(value) && csi_length(value) > 0) {
3015*21817992SBaptiste Daroussin char *p_is_s[NUM_PARM];
3016*21817992SBaptiste Daroussin int popcount;
3017*21817992SBaptiste Daroussin int analyzed = _nc_tparm_analyze(NULL, value, p_is_s, &popcount);
3018*21817992SBaptiste Daroussin if (analyzed < popcount) {
3019*21817992SBaptiste Daroussin analyzed = popcount;
3020*21817992SBaptiste Daroussin }
3021*21817992SBaptiste Daroussin if (analyzed == nparams) {
3022*21817992SBaptiste Daroussin bool numbers = TRUE;
3023*21817992SBaptiste Daroussin int p;
3024*21817992SBaptiste Daroussin for (p = 0; p < nparams; ++p) {
3025*21817992SBaptiste Daroussin if (p_is_s[p]) {
3026*21817992SBaptiste Daroussin numbers = FALSE;
3027*21817992SBaptiste Daroussin break;
3028*21817992SBaptiste Daroussin }
3029*21817992SBaptiste Daroussin }
3030*21817992SBaptiste Daroussin if (numbers) {
3031*21817992SBaptiste Daroussin int in_delay = 0;
3032*21817992SBaptiste Daroussin p = (int) strlen(value);
3033*21817992SBaptiste Daroussin while (p-- > 0) {
3034*21817992SBaptiste Daroussin char ch = value[p];
3035*21817992SBaptiste Daroussin if (ch == final) {
3036*21817992SBaptiste Daroussin result = TRUE;
3037*21817992SBaptiste Daroussin break;
3038*21817992SBaptiste Daroussin }
3039*21817992SBaptiste Daroussin switch (in_delay) {
3040*21817992SBaptiste Daroussin case 0:
3041*21817992SBaptiste Daroussin if (ch == '>')
3042*21817992SBaptiste Daroussin in_delay = 1;
3043*21817992SBaptiste Daroussin break;
3044*21817992SBaptiste Daroussin case 1:
3045*21817992SBaptiste Daroussin if (strchr(IN_DELAY, value[p]) != NULL)
3046*21817992SBaptiste Daroussin break;
3047*21817992SBaptiste Daroussin if (ch != '<')
3048*21817992SBaptiste Daroussin p = 0;
3049*21817992SBaptiste Daroussin in_delay = 2;
3050*21817992SBaptiste Daroussin break;
3051*21817992SBaptiste Daroussin case 2:
3052*21817992SBaptiste Daroussin if (ch != '$')
3053*21817992SBaptiste Daroussin p = 0;
3054*21817992SBaptiste Daroussin in_delay = 0;
3055*21817992SBaptiste Daroussin break;
3056*21817992SBaptiste Daroussin }
3057*21817992SBaptiste Daroussin }
3058*21817992SBaptiste Daroussin }
3059*21817992SBaptiste Daroussin }
3060*21817992SBaptiste Daroussin }
3061*21817992SBaptiste Daroussin return result;
3062*21817992SBaptiste Daroussin }
3063*21817992SBaptiste Daroussin
3064*21817992SBaptiste Daroussin static const char *
skip_Delay(const char * value)3065*21817992SBaptiste Daroussin skip_Delay(const char *value)
3066*21817992SBaptiste Daroussin {
3067*21817992SBaptiste Daroussin const char *result = value;
3068*21817992SBaptiste Daroussin
3069*21817992SBaptiste Daroussin if (*value == '$') {
3070*21817992SBaptiste Daroussin ++result;
3071*21817992SBaptiste Daroussin if (*result++ == '<') {
3072*21817992SBaptiste Daroussin while (strchr(IN_DELAY, *result) != NULL)
3073*21817992SBaptiste Daroussin ++result;
3074*21817992SBaptiste Daroussin if (*result++ != '>') {
3075*21817992SBaptiste Daroussin result = value;
3076*21817992SBaptiste Daroussin }
3077*21817992SBaptiste Daroussin } else {
3078*21817992SBaptiste Daroussin result = value;
3079*21817992SBaptiste Daroussin }
3080*21817992SBaptiste Daroussin }
3081*21817992SBaptiste Daroussin return result;
3082*21817992SBaptiste Daroussin }
3083*21817992SBaptiste Daroussin
3084*21817992SBaptiste Daroussin static bool
isValidString(const char * value,const char * expect)3085*21817992SBaptiste Daroussin isValidString(const char *value, const char *expect)
3086*21817992SBaptiste Daroussin {
3087*21817992SBaptiste Daroussin bool result = FALSE;
3088*21817992SBaptiste Daroussin if (VALID_STRING(value)) {
3089*21817992SBaptiste Daroussin if (!strcmp(value, expect))
3090*21817992SBaptiste Daroussin result = TRUE;
3091*21817992SBaptiste Daroussin }
3092*21817992SBaptiste Daroussin return result;
3093*21817992SBaptiste Daroussin }
3094*21817992SBaptiste Daroussin
3095*21817992SBaptiste Daroussin static bool
isValidEscape(const char * value,const char * expect)3096*21817992SBaptiste Daroussin isValidEscape(const char *value, const char *expect)
3097*21817992SBaptiste Daroussin {
3098*21817992SBaptiste Daroussin bool result = FALSE;
3099*21817992SBaptiste Daroussin if (VALID_STRING(value)) {
3100*21817992SBaptiste Daroussin if (*value == '\033') {
3101*21817992SBaptiste Daroussin size_t need = strlen(expect);
3102*21817992SBaptiste Daroussin size_t have = strlen(value) - 1;
3103*21817992SBaptiste Daroussin if (have >= need && !strncmp(value + 1, expect, need)) {
3104*21817992SBaptiste Daroussin if (*skip_Delay(value + need + 1) == '\0') {
3105*21817992SBaptiste Daroussin result = TRUE;
3106*21817992SBaptiste Daroussin }
3107*21817992SBaptiste Daroussin }
3108*21817992SBaptiste Daroussin }
3109*21817992SBaptiste Daroussin }
3110*21817992SBaptiste Daroussin return result;
3111*21817992SBaptiste Daroussin }
3112*21817992SBaptiste Daroussin
3113*21817992SBaptiste Daroussin static int
guess_ANSI_VTxx(TERMTYPE2 * tp)3114*21817992SBaptiste Daroussin guess_ANSI_VTxx(TERMTYPE2 *tp)
3115*21817992SBaptiste Daroussin {
3116*21817992SBaptiste Daroussin int result = -1;
3117*21817992SBaptiste Daroussin int checks = 0;
3118*21817992SBaptiste Daroussin
3119*21817992SBaptiste Daroussin /* VT100s have scrolling region, but ANSI (ECMA-48) does not specify */
3120*21817992SBaptiste Daroussin if (check_ANSI_cap(change_scroll_region, 2, 'r') &&
3121*21817992SBaptiste Daroussin (isValidEscape(scroll_forward, "D") ||
3122*21817992SBaptiste Daroussin isValidString(scroll_forward, "\n") ||
3123*21817992SBaptiste Daroussin isValidEscape(scroll_forward, "6")) &&
3124*21817992SBaptiste Daroussin (isValidEscape(scroll_reverse, "M") ||
3125*21817992SBaptiste Daroussin isValidEscape(scroll_reverse, "9"))) {
3126*21817992SBaptiste Daroussin checks |= 2;
3127*21817992SBaptiste Daroussin }
3128*21817992SBaptiste Daroussin if (check_ANSI_cap(cursor_address, 2, 'H') &&
3129*21817992SBaptiste Daroussin check_ANSI_cap(cursor_up, 0, 'A') &&
3130*21817992SBaptiste Daroussin (check_ANSI_cap(cursor_down, 0, 'B') ||
3131*21817992SBaptiste Daroussin isValidString(cursor_down, "\n")) &&
3132*21817992SBaptiste Daroussin check_ANSI_cap(cursor_right, 0, 'C') &&
3133*21817992SBaptiste Daroussin (check_ANSI_cap(cursor_left, 0, 'D') ||
3134*21817992SBaptiste Daroussin isValidString(cursor_left, "\b")) &&
3135*21817992SBaptiste Daroussin check_ANSI_cap(clr_eos, 0, 'J') &&
3136*21817992SBaptiste Daroussin check_ANSI_cap(clr_bol, 0, 'K') &&
3137*21817992SBaptiste Daroussin check_ANSI_cap(clr_eol, 0, 'K')) {
3138*21817992SBaptiste Daroussin checks |= 1;
3139*21817992SBaptiste Daroussin }
3140*21817992SBaptiste Daroussin if (checks == 3)
3141*21817992SBaptiste Daroussin result = 1;
3142*21817992SBaptiste Daroussin if (checks == 1)
3143*21817992SBaptiste Daroussin result = 0;
3144*21817992SBaptiste Daroussin return result;
3145*21817992SBaptiste Daroussin }
3146*21817992SBaptiste Daroussin
3147*21817992SBaptiste Daroussin /*
3148*21817992SBaptiste Daroussin * u6/u7 and u8/u9 are query/response extensions which most terminals support.
3149*21817992SBaptiste Daroussin * In particular, any ECMA-48 terminal should support these, though the details
3150*21817992SBaptiste Daroussin * for u9 are implementation dependent.
3151*21817992SBaptiste Daroussin */
3152*21817992SBaptiste Daroussin #if defined(user6) && defined(user7) && defined(user8) && defined(user9)
3153*21817992SBaptiste Daroussin static void
check_user_6789(TERMTYPE2 * tp)3154*21817992SBaptiste Daroussin check_user_6789(TERMTYPE2 *tp)
3155*21817992SBaptiste Daroussin {
3156*21817992SBaptiste Daroussin /*
3157*21817992SBaptiste Daroussin * Check if the terminal is known to not
3158*21817992SBaptiste Daroussin */
3159*21817992SBaptiste Daroussin #define NO_QUERY(longname,shortname) \
3160*21817992SBaptiste Daroussin if (PRESENT(longname)) _nc_warning(#shortname " is not supported")
3161*21817992SBaptiste Daroussin if (tigetflag("NQ") > 0) {
3162*21817992SBaptiste Daroussin NO_QUERY(user6, u6);
3163*21817992SBaptiste Daroussin NO_QUERY(user7, u7);
3164*21817992SBaptiste Daroussin NO_QUERY(user8, u8);
3165*21817992SBaptiste Daroussin NO_QUERY(user9, u9);
3166*21817992SBaptiste Daroussin return;
3167*21817992SBaptiste Daroussin }
3168*21817992SBaptiste Daroussin
3169*21817992SBaptiste Daroussin PAIRED(user6, user7);
3170*21817992SBaptiste Daroussin PAIRED(user8, user9);
3171*21817992SBaptiste Daroussin
3172*21817992SBaptiste Daroussin if (strchr(tp->term_names, '+') != NULL)
3173*21817992SBaptiste Daroussin return;
3174*21817992SBaptiste Daroussin
3175*21817992SBaptiste Daroussin switch (guess_ANSI_VTxx(tp)) {
3176*21817992SBaptiste Daroussin case 1:
3177*21817992SBaptiste Daroussin if (!PRESENT(user8)) {
3178*21817992SBaptiste Daroussin _nc_warning("expected u8/u9 for device-attributes");
3179*21817992SBaptiste Daroussin }
3180*21817992SBaptiste Daroussin /* FALLTHRU */
3181*21817992SBaptiste Daroussin case 0:
3182*21817992SBaptiste Daroussin if (!PRESENT(user6)) {
3183*21817992SBaptiste Daroussin _nc_warning("expected u6/u7 for cursor-position");
3184*21817992SBaptiste Daroussin }
3185*21817992SBaptiste Daroussin break;
3186*21817992SBaptiste Daroussin }
3187*21817992SBaptiste Daroussin }
3188*21817992SBaptiste Daroussin #else
3189*21817992SBaptiste Daroussin #define check_user_6789(tp) /* nothing */
3190*21817992SBaptiste Daroussin #endif
3191*21817992SBaptiste Daroussin
3192aae38d10SBaptiste Daroussin /* other sanity-checks (things that we don't want in the normal
3193aae38d10SBaptiste Daroussin * logic that reads a terminfo entry)
3194aae38d10SBaptiste Daroussin */
3195aae38d10SBaptiste Daroussin static void
check_termtype(TERMTYPE2 * tp,bool literal)3196aae38d10SBaptiste Daroussin check_termtype(TERMTYPE2 *tp, bool literal)
3197aae38d10SBaptiste Daroussin {
3198aae38d10SBaptiste Daroussin unsigned j;
3199aae38d10SBaptiste Daroussin
3200aae38d10SBaptiste Daroussin check_conflict(tp);
32010e3d5408SPeter Wemm
320273f0a83dSXin LI for_each_string(j, tp) {
320318259542SPeter Wemm char *a = tp->Strings[j];
3204aae38d10SBaptiste Daroussin if (VALID_STRING(a)) {
3205aae38d10SBaptiste Daroussin const char *name = ExtStrname(tp, (int) j, strnames);
3206aae38d10SBaptiste Daroussin /*
3207aae38d10SBaptiste Daroussin * If we expect parameters, or if there might be parameters,
3208aae38d10SBaptiste Daroussin * check for consistent number of parameters.
3209aae38d10SBaptiste Daroussin */
3210aae38d10SBaptiste Daroussin if (j >= SIZEOF(parametrized) ||
3211aae38d10SBaptiste Daroussin is_user_capability(name) >= 0 ||
3212aae38d10SBaptiste Daroussin parametrized[j] > 0) {
3213aae38d10SBaptiste Daroussin check_params(tp, name, a, (j >= STRCOUNT));
321418259542SPeter Wemm }
3215aae38d10SBaptiste Daroussin check_delays(tp, ExtStrname(tp, (int) j, strnames), a);
3216aae38d10SBaptiste Daroussin if (capdump) {
3217aae38d10SBaptiste Daroussin check_infotocap(tp, (int) j, a);
3218aae38d10SBaptiste Daroussin }
3219aae38d10SBaptiste Daroussin }
3220aae38d10SBaptiste Daroussin }
3221aae38d10SBaptiste Daroussin #if NCURSES_XNAMES
3222aae38d10SBaptiste Daroussin /* in extended mode, verify that each extension is expected type */
3223aae38d10SBaptiste Daroussin for_each_ext_boolean(j, tp) {
3224aae38d10SBaptiste Daroussin check_user_capability_type(ExtBoolname(tp, (int) j, strnames), BOOLEAN);
3225aae38d10SBaptiste Daroussin }
3226aae38d10SBaptiste Daroussin for_each_ext_number(j, tp) {
3227aae38d10SBaptiste Daroussin check_user_capability_type(ExtNumname(tp, (int) j, strnames), NUMBER);
3228aae38d10SBaptiste Daroussin }
3229aae38d10SBaptiste Daroussin for_each_ext_string(j, tp) {
3230aae38d10SBaptiste Daroussin check_user_capability_type(ExtStrname(tp, (int) j, strnames), STRING);
3231aae38d10SBaptiste Daroussin }
3232aae38d10SBaptiste Daroussin #endif /* NCURSES_XNAMES */
323318259542SPeter Wemm
32344a1a9510SRong-En Fan check_acs(tp);
32354a1a9510SRong-En Fan check_colors(tp);
323606bfebdeSXin LI check_cursor(tp);
32374a1a9510SRong-En Fan check_keypad(tp);
323806bfebdeSXin LI check_printer(tp);
323973f0a83dSXin LI check_screen(tp);
3240*21817992SBaptiste Daroussin check_user_6789(tp);
32410e3d5408SPeter Wemm
32420e3d5408SPeter Wemm /*
3243aae38d10SBaptiste Daroussin * These are probably both or none.
3244aae38d10SBaptiste Daroussin */
3245aae38d10SBaptiste Daroussin PAIRED(parm_index, parm_rindex);
3246aae38d10SBaptiste Daroussin PAIRED(parm_ich, parm_dch);
3247aae38d10SBaptiste Daroussin
3248aae38d10SBaptiste Daroussin /*
32490e3d5408SPeter Wemm * These may be mismatched because the terminal description relies on
32500e3d5408SPeter Wemm * restoring the cursor visibility by resetting it.
32510e3d5408SPeter Wemm */
325215589c42SPeter Wemm ANDMISSING(cursor_invisible, cursor_normal);
325315589c42SPeter Wemm ANDMISSING(cursor_visible, cursor_normal);
325415589c42SPeter Wemm
325515589c42SPeter Wemm if (PRESENT(cursor_visible) && PRESENT(cursor_normal)
32564a1a9510SRong-En Fan && !_nc_capcmp(cursor_visible, cursor_normal))
325715589c42SPeter Wemm _nc_warning("cursor_visible is same as cursor_normal");
32580e3d5408SPeter Wemm
32590e3d5408SPeter Wemm /*
32600e3d5408SPeter Wemm * From XSI & O'Reilly, we gather that sc/rc are required if csr is
32610e3d5408SPeter Wemm * given, because the cursor position after the scrolling operation is
32620e3d5408SPeter Wemm * performed is undefined.
32630e3d5408SPeter Wemm */
326415589c42SPeter Wemm ANDMISSING(change_scroll_region, save_cursor);
326515589c42SPeter Wemm ANDMISSING(change_scroll_region, restore_cursor);
326615589c42SPeter Wemm
326706bfebdeSXin LI /*
326806bfebdeSXin LI * If we can clear tabs, we should be able to initialize them.
326906bfebdeSXin LI */
327006bfebdeSXin LI ANDMISSING(clear_all_tabs, set_tab);
327106bfebdeSXin LI
327215589c42SPeter Wemm if (PRESENT(set_attributes)) {
32734a1a9510SRong-En Fan char *zero = 0;
327415589c42SPeter Wemm
32754a1a9510SRong-En Fan _nc_tparm_err = 0;
32764a1a9510SRong-En Fan if (PRESENT(exit_attribute_mode)) {
32774a1a9510SRong-En Fan zero = strdup(CHECK_SGR(0, exit_attribute_mode));
32784a1a9510SRong-En Fan } else {
32797a656419SBaptiste Daroussin zero = strdup(TIPARM_9(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0));
32804a1a9510SRong-En Fan }
32817a656419SBaptiste Daroussin check_tparm_err(0);
32824a1a9510SRong-En Fan
32834a1a9510SRong-En Fan if (zero != 0) {
328415589c42SPeter Wemm CHECK_SGR(1, enter_standout_mode);
328515589c42SPeter Wemm CHECK_SGR(2, enter_underline_mode);
328615589c42SPeter Wemm CHECK_SGR(3, enter_reverse_mode);
328715589c42SPeter Wemm CHECK_SGR(4, enter_blink_mode);
328815589c42SPeter Wemm CHECK_SGR(5, enter_dim_mode);
328915589c42SPeter Wemm CHECK_SGR(6, enter_bold_mode);
329015589c42SPeter Wemm CHECK_SGR(7, enter_secure_mode);
329115589c42SPeter Wemm CHECK_SGR(8, enter_protected_mode);
329215589c42SPeter Wemm CHECK_SGR(9, enter_alt_charset_mode);
329315589c42SPeter Wemm free(zero);
32944a1a9510SRong-En Fan } else {
32954a1a9510SRong-En Fan _nc_warning("sgr(0) did not return a value");
329615589c42SPeter Wemm }
32974a1a9510SRong-En Fan } else if (PRESENT(exit_attribute_mode) &&
32984a1a9510SRong-En Fan set_attributes != CANCELLED_STRING) {
32994a1a9510SRong-En Fan if (_nc_syntax == SYN_TERMINFO)
33004a1a9510SRong-En Fan _nc_warning("missing sgr string");
33014a1a9510SRong-En Fan }
3302aae38d10SBaptiste Daroussin #define CHECK_SGR0(name) check_exit_attribute(#name, name, check_sgr0, exit_attribute_mode)
33034a1a9510SRong-En Fan if (PRESENT(exit_attribute_mode)) {
33044a1a9510SRong-En Fan char *check_sgr0 = _nc_trim_sgr0(tp);
33054a1a9510SRong-En Fan
3306*21817992SBaptiste Daroussin if (check_sgr0 == NULL || *check_sgr0 == '\0') {
33074a1a9510SRong-En Fan _nc_warning("trimmed sgr0 is empty");
33084a1a9510SRong-En Fan } else {
33094a1a9510SRong-En Fan show_where(2);
33104a1a9510SRong-En Fan if (check_sgr0 != exit_attribute_mode) {
33114a1a9510SRong-En Fan DEBUG(2,
33124a1a9510SRong-En Fan ("will trim sgr0\n\toriginal sgr0=%s\n\ttrimmed sgr0=%s",
33134a1a9510SRong-En Fan _nc_visbuf2(1, exit_attribute_mode),
33144a1a9510SRong-En Fan _nc_visbuf2(2, check_sgr0)));
33154a1a9510SRong-En Fan } else {
33164a1a9510SRong-En Fan DEBUG(2,
33174a1a9510SRong-En Fan ("will not trim sgr0\n\toriginal sgr0=%s",
33184a1a9510SRong-En Fan _nc_visbuf(exit_attribute_mode)));
33194a1a9510SRong-En Fan }
33204a1a9510SRong-En Fan }
3321aae38d10SBaptiste Daroussin #if defined(exit_italics_mode)
3322aae38d10SBaptiste Daroussin CHECK_SGR0(exit_italics_mode);
3323aae38d10SBaptiste Daroussin #endif
3324aae38d10SBaptiste Daroussin CHECK_SGR0(exit_standout_mode);
3325aae38d10SBaptiste Daroussin CHECK_SGR0(exit_underline_mode);
3326aae38d10SBaptiste Daroussin if (check_sgr0 != exit_attribute_mode) {
3327aae38d10SBaptiste Daroussin free(check_sgr0);
3328aae38d10SBaptiste Daroussin }
3329aae38d10SBaptiste Daroussin }
3330aae38d10SBaptiste Daroussin #define CHECK_SGR_PARAM(code, name) check_sgr_param(tp, (int)code, #name, name)
3331aae38d10SBaptiste Daroussin for (j = 0; *sgr_names[j] != '\0'; ++j) {
3332aae38d10SBaptiste Daroussin CHECK_SGR_PARAM(j, set_a_foreground);
3333aae38d10SBaptiste Daroussin CHECK_SGR_PARAM(j, set_a_background);
3334aae38d10SBaptiste Daroussin CHECK_SGR_PARAM(j, set_foreground);
3335aae38d10SBaptiste Daroussin CHECK_SGR_PARAM(j, set_background);
33364a1a9510SRong-En Fan }
33374a1a9510SRong-En Fan #ifdef TRACE
33384a1a9510SRong-En Fan show_where(2);
33394a1a9510SRong-En Fan if (!auto_right_margin) {
33404a1a9510SRong-En Fan DEBUG(2,
33414a1a9510SRong-En Fan ("can write to lower-right directly"));
33424a1a9510SRong-En Fan } else if (PRESENT(enter_am_mode) && PRESENT(exit_am_mode)) {
33434a1a9510SRong-En Fan DEBUG(2,
33444a1a9510SRong-En Fan ("can write to lower-right by suppressing automargin"));
33454a1a9510SRong-En Fan } else if ((PRESENT(enter_insert_mode) && PRESENT(exit_insert_mode))
33464a1a9510SRong-En Fan || PRESENT(insert_character) || PRESENT(parm_ich)) {
33474a1a9510SRong-En Fan DEBUG(2,
33484a1a9510SRong-En Fan ("can write to lower-right by using inserts"));
33494a1a9510SRong-En Fan } else {
33504a1a9510SRong-En Fan DEBUG(2,
33514a1a9510SRong-En Fan ("cannot write to lower-right"));
33524a1a9510SRong-En Fan }
33534a1a9510SRong-En Fan #endif
33540e3d5408SPeter Wemm
33550e3d5408SPeter Wemm /*
33560e3d5408SPeter Wemm * Some standard applications (e.g., vi) and some non-curses
33574a1a9510SRong-En Fan * applications (e.g., jove) get confused if we have both ich1 and
33580e3d5408SPeter Wemm * smir/rmir. Let's be nice and warn about that, too, even though
33590e3d5408SPeter Wemm * ncurses handles it.
33600e3d5408SPeter Wemm */
33610e3d5408SPeter Wemm if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))
3362aae38d10SBaptiste Daroussin && PRESENT(insert_character)) {
33634a1a9510SRong-En Fan _nc_warning("non-curses applications may be confused by ich1 with smir/rmir");
33640e3d5408SPeter Wemm }
33650e3d5408SPeter Wemm
33660e3d5408SPeter Wemm /*
33670e3d5408SPeter Wemm * Finally, do the non-verbose checks
33680e3d5408SPeter Wemm */
33690e3d5408SPeter Wemm if (save_check_termtype != 0)
33704a1a9510SRong-En Fan save_check_termtype(tp, literal);
33710e3d5408SPeter Wemm }
3372