15f4613f2SJohn Marino /****************************************************************************
2*32bb5217SDaniel Fojt * Copyright 2018-2019,2020 Thomas E. Dickey *
3*32bb5217SDaniel Fojt * Copyright 1998-2017,2018 Free Software Foundation, Inc. *
45f4613f2SJohn Marino * *
55f4613f2SJohn Marino * Permission is hereby granted, free of charge, to any person obtaining a *
65f4613f2SJohn Marino * copy of this software and associated documentation files (the *
75f4613f2SJohn Marino * "Software"), to deal in the Software without restriction, including *
85f4613f2SJohn Marino * without limitation the rights to use, copy, modify, merge, publish, *
95f4613f2SJohn Marino * distribute, distribute with modifications, sublicense, and/or sell *
105f4613f2SJohn Marino * copies of the Software, and to permit persons to whom the Software is *
115f4613f2SJohn Marino * furnished to do so, subject to the following conditions: *
125f4613f2SJohn Marino * *
135f4613f2SJohn Marino * The above copyright notice and this permission notice shall be included *
145f4613f2SJohn Marino * in all copies or substantial portions of the Software. *
155f4613f2SJohn Marino * *
165f4613f2SJohn Marino * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
175f4613f2SJohn Marino * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
185f4613f2SJohn Marino * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
195f4613f2SJohn Marino * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
205f4613f2SJohn Marino * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
215f4613f2SJohn Marino * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
225f4613f2SJohn Marino * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
235f4613f2SJohn Marino * *
245f4613f2SJohn Marino * Except as contained in this notice, the name(s) of the above copyright *
255f4613f2SJohn Marino * holders shall not be used in advertising or otherwise to promote the *
265f4613f2SJohn Marino * sale, use or other dealings in this Software without prior written *
275f4613f2SJohn Marino * authorization. *
285f4613f2SJohn Marino ****************************************************************************/
295f4613f2SJohn Marino
305f4613f2SJohn Marino /****************************************************************************
315f4613f2SJohn Marino * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
325f4613f2SJohn Marino * and: Eric S. Raymond <esr@snark.thyrsus.com> *
335f4613f2SJohn Marino * and: Thomas E. Dickey 1996 on *
345f4613f2SJohn Marino ****************************************************************************/
355f4613f2SJohn Marino
365f4613f2SJohn Marino /*
375f4613f2SJohn Marino * tic.c --- Main program for terminfo compiler
385f4613f2SJohn Marino * by Eric S. Raymond
393468e90cSJohn Marino * and Thomas E Dickey
405f4613f2SJohn Marino *
415f4613f2SJohn Marino */
425f4613f2SJohn Marino
435f4613f2SJohn Marino #include <progs.priv.h>
445f4613f2SJohn Marino #include <sys/stat.h>
455f4613f2SJohn Marino
465f4613f2SJohn Marino #include <dump_entry.h>
473468e90cSJohn Marino #include <tparm_type.h>
483468e90cSJohn Marino #include <hashed_db.h>
493468e90cSJohn Marino #include <parametrized.h>
505f4613f2SJohn Marino #include <transform.h>
515f4613f2SJohn Marino
52*32bb5217SDaniel Fojt MODULE_ID("$Id: tic.c,v 1.282 2020/02/02 23:34:34 tom Exp $")
533468e90cSJohn Marino
543468e90cSJohn Marino #define STDIN_NAME "<stdin>"
555f4613f2SJohn Marino
565f4613f2SJohn Marino const char *_nc_progname = "tic";
575f4613f2SJohn Marino
585f4613f2SJohn Marino static FILE *log_fp;
595f4613f2SJohn Marino static FILE *tmp_fp;
605f4613f2SJohn Marino static bool capdump = FALSE; /* running as infotocap? */
615f4613f2SJohn Marino static bool infodump = FALSE; /* running as captoinfo? */
625f4613f2SJohn Marino static bool showsummary = FALSE;
63*32bb5217SDaniel Fojt static unsigned debug_level;
643468e90cSJohn Marino static char **namelst = 0;
655f4613f2SJohn Marino static const char *to_remove;
665f4613f2SJohn Marino
67*32bb5217SDaniel Fojt #if NCURSES_XNAMES
68*32bb5217SDaniel Fojt static bool using_extensions = FALSE;
69*32bb5217SDaniel Fojt #endif
70*32bb5217SDaniel Fojt
71*32bb5217SDaniel Fojt static void (*save_check_termtype) (TERMTYPE2 *, bool);
72*32bb5217SDaniel Fojt static void check_termtype(TERMTYPE2 *tt, bool);
735f4613f2SJohn Marino
745f4613f2SJohn Marino static const char usage_string[] = "\
755f4613f2SJohn Marino [-e names] \
765f4613f2SJohn Marino [-o dir] \
775f4613f2SJohn Marino [-R name] \
785f4613f2SJohn Marino [-v[n]] \
795f4613f2SJohn Marino [-V] \
805f4613f2SJohn Marino [-w[n]] \
815f4613f2SJohn Marino [-\
825f4613f2SJohn Marino 1\
835f4613f2SJohn Marino a\
845f4613f2SJohn Marino C\
853468e90cSJohn Marino D\
865f4613f2SJohn Marino c\
875f4613f2SJohn Marino f\
885f4613f2SJohn Marino G\
895f4613f2SJohn Marino g\
905f4613f2SJohn Marino I\
913468e90cSJohn Marino K\
925f4613f2SJohn Marino L\
935f4613f2SJohn Marino N\
945f4613f2SJohn Marino r\
955f4613f2SJohn Marino s\
965f4613f2SJohn Marino T\
975f4613f2SJohn Marino t\
985f4613f2SJohn Marino U\
995f4613f2SJohn Marino x\
1005f4613f2SJohn Marino ] \
1015f4613f2SJohn Marino source-file\n";
1025f4613f2SJohn Marino
1035f4613f2SJohn Marino #if NO_LEAKS
1045f4613f2SJohn Marino static void
free_namelist(char ** src)1055f4613f2SJohn Marino free_namelist(char **src)
1065f4613f2SJohn Marino {
1075f4613f2SJohn Marino if (src != 0) {
1085f4613f2SJohn Marino int n;
1095f4613f2SJohn Marino for (n = 0; src[n] != 0; ++n)
1105f4613f2SJohn Marino free(src[n]);
1115f4613f2SJohn Marino free(src);
1125f4613f2SJohn Marino }
1135f4613f2SJohn Marino }
1145f4613f2SJohn Marino #endif
1155f4613f2SJohn Marino
1165f4613f2SJohn Marino static void
cleanup(void)1173468e90cSJohn Marino cleanup(void)
1185f4613f2SJohn Marino {
1193468e90cSJohn Marino int rc;
1203468e90cSJohn Marino
1215f4613f2SJohn Marino #if NO_LEAKS
1225f4613f2SJohn Marino free_namelist(namelst);
123*32bb5217SDaniel Fojt _nc_leaks_dump_entry();
1245f4613f2SJohn Marino #endif
1255f4613f2SJohn Marino if (tmp_fp != 0)
1265f4613f2SJohn Marino fclose(tmp_fp);
1275f4613f2SJohn Marino if (to_remove != 0) {
1285f4613f2SJohn Marino #if HAVE_REMOVE
1293468e90cSJohn Marino rc = remove(to_remove);
1305f4613f2SJohn Marino #else
1313468e90cSJohn Marino rc = unlink(to_remove);
1325f4613f2SJohn Marino #endif
1333468e90cSJohn Marino if (rc != 0)
1343468e90cSJohn Marino perror(to_remove);
1355f4613f2SJohn Marino }
1365f4613f2SJohn Marino }
1375f4613f2SJohn Marino
1385f4613f2SJohn Marino static void
failed(const char * msg)1395f4613f2SJohn Marino failed(const char *msg)
1405f4613f2SJohn Marino {
1415f4613f2SJohn Marino perror(msg);
1425f4613f2SJohn Marino ExitProgram(EXIT_FAILURE);
1435f4613f2SJohn Marino }
1445f4613f2SJohn Marino
1455f4613f2SJohn Marino static void
usage(void)1465f4613f2SJohn Marino usage(void)
1475f4613f2SJohn Marino {
1483468e90cSJohn Marino #define DATA(s) s "\n"
1493468e90cSJohn Marino static const char options_string[] =
1505f4613f2SJohn Marino {
1513468e90cSJohn Marino DATA("Options:")
1523468e90cSJohn Marino DATA(" -0 format translation output all capabilities on one line")
1533468e90cSJohn Marino DATA(" -1 format translation output one capability per line")
1545f4613f2SJohn Marino #if NCURSES_XNAMES
1553468e90cSJohn Marino DATA(" -a retain commented-out capabilities (sets -x also)")
1565f4613f2SJohn Marino #endif
1573468e90cSJohn Marino DATA(" -C translate entries to termcap source form")
1583468e90cSJohn Marino DATA(" -D print list of tic's database locations (first must be writable)")
1593468e90cSJohn Marino DATA(" -c check only, validate input without compiling or translating")
1603468e90cSJohn Marino DATA(" -e<names> translate/compile only entries named by comma-separated list")
1613468e90cSJohn Marino DATA(" -f format complex strings for readability")
1623468e90cSJohn Marino DATA(" -G format %{number} to %'char'")
1633468e90cSJohn Marino DATA(" -g format %'char' to %{number}")
1643468e90cSJohn Marino DATA(" -I translate entries to terminfo source form")
1653468e90cSJohn Marino DATA(" -K translate entries to termcap source form with BSD syntax")
1663468e90cSJohn Marino DATA(" -L translate entries to full terminfo source form")
1673468e90cSJohn Marino DATA(" -N disable smart defaults for source translation")
1683468e90cSJohn Marino DATA(" -o<dir> set output directory for compiled entry writes")
1693468e90cSJohn Marino DATA(" -Q[n] dump compiled description")
1703468e90cSJohn Marino DATA(" -q brief listing, removes headers")
1713468e90cSJohn Marino DATA(" -R<name> restrict translation to given terminfo/termcap version")
1723468e90cSJohn Marino DATA(" -r force resolution of all use entries in source translation")
1733468e90cSJohn Marino DATA(" -s print summary statistics")
1743468e90cSJohn Marino DATA(" -T remove size-restrictions on compiled description")
1755f4613f2SJohn Marino #if NCURSES_XNAMES
1763468e90cSJohn Marino DATA(" -t suppress commented-out capabilities")
1775f4613f2SJohn Marino #endif
1783468e90cSJohn Marino DATA(" -U suppress post-processing of entries")
1793468e90cSJohn Marino DATA(" -V print version")
180*32bb5217SDaniel Fojt DATA(" -W wrap long strings according to -w[n] option")
1813468e90cSJohn Marino DATA(" -v[n] set verbosity level")
1823468e90cSJohn Marino DATA(" -w[n] set format width for translation output")
1835f4613f2SJohn Marino #if NCURSES_XNAMES
1843468e90cSJohn Marino DATA(" -x treat unknown capabilities as user-defined")
1855f4613f2SJohn Marino #endif
1863468e90cSJohn Marino DATA("")
1873468e90cSJohn Marino DATA("Parameters:")
1883468e90cSJohn Marino DATA(" <file> file to translate or compile")
1895f4613f2SJohn Marino };
1903468e90cSJohn Marino #undef DATA
1915f4613f2SJohn Marino
1925f4613f2SJohn Marino fprintf(stderr, "Usage: %s %s\n", _nc_progname, usage_string);
1933468e90cSJohn Marino fputs(options_string, stderr);
1945f4613f2SJohn Marino ExitProgram(EXIT_FAILURE);
1955f4613f2SJohn Marino }
1965f4613f2SJohn Marino
1975f4613f2SJohn Marino #define L_BRACE '{'
1985f4613f2SJohn Marino #define R_BRACE '}'
1993468e90cSJohn Marino #define S_QUOTE '\''
2005f4613f2SJohn Marino
2015f4613f2SJohn Marino static void
write_it(ENTRY * ep)2025f4613f2SJohn Marino write_it(ENTRY * ep)
2035f4613f2SJohn Marino {
2045f4613f2SJohn Marino unsigned n;
2055f4613f2SJohn Marino int ch;
2065f4613f2SJohn Marino char *s, *d, *t;
2075f4613f2SJohn Marino char result[MAX_ENTRY_SIZE];
2085f4613f2SJohn Marino
2095f4613f2SJohn Marino /*
2105f4613f2SJohn Marino * Look for strings that contain %{number}, convert them to %'char',
2115f4613f2SJohn Marino * which is shorter and runs a little faster.
2125f4613f2SJohn Marino */
2135f4613f2SJohn Marino for (n = 0; n < STRCOUNT; n++) {
2145f4613f2SJohn Marino s = ep->tterm.Strings[n];
2155f4613f2SJohn Marino if (VALID_STRING(s)
2165f4613f2SJohn Marino && strchr(s, L_BRACE) != 0) {
2175f4613f2SJohn Marino d = result;
2185f4613f2SJohn Marino t = s;
2195f4613f2SJohn Marino while ((ch = *t++) != 0) {
2205f4613f2SJohn Marino *d++ = (char) ch;
2215f4613f2SJohn Marino if (ch == '\\') {
222*32bb5217SDaniel Fojt if ((*d++ = *t++) == '\0')
223*32bb5217SDaniel Fojt break;
2245f4613f2SJohn Marino } else if ((ch == '%')
2255f4613f2SJohn Marino && (*t == L_BRACE)) {
2265f4613f2SJohn Marino char *v = 0;
2275f4613f2SJohn Marino long value = strtol(t + 1, &v, 0);
2285f4613f2SJohn Marino if (v != 0
2295f4613f2SJohn Marino && *v == R_BRACE
2305f4613f2SJohn Marino && value > 0
2315f4613f2SJohn Marino && value != '\\' /* FIXME */
2325f4613f2SJohn Marino && value < 127
2335f4613f2SJohn Marino && isprint((int) value)) {
2345f4613f2SJohn Marino *d++ = S_QUOTE;
2355f4613f2SJohn Marino *d++ = (char) value;
2365f4613f2SJohn Marino *d++ = S_QUOTE;
2375f4613f2SJohn Marino t = (v + 1);
2385f4613f2SJohn Marino }
2395f4613f2SJohn Marino }
2405f4613f2SJohn Marino }
2415f4613f2SJohn Marino *d = 0;
2425f4613f2SJohn Marino if (strlen(result) < strlen(s))
2433468e90cSJohn Marino _nc_STRCPY(s, result, strlen(s) + 1);
2445f4613f2SJohn Marino }
2455f4613f2SJohn Marino }
2465f4613f2SJohn Marino
2475f4613f2SJohn Marino _nc_set_type(_nc_first_name(ep->tterm.term_names));
2483468e90cSJohn Marino _nc_curr_line = (int) ep->startline;
2495f4613f2SJohn Marino _nc_write_entry(&ep->tterm);
2505f4613f2SJohn Marino }
2515f4613f2SJohn Marino
2525f4613f2SJohn Marino static bool
immedhook(ENTRY * ep GCC_UNUSED)2535f4613f2SJohn Marino immedhook(ENTRY * ep GCC_UNUSED)
2545f4613f2SJohn Marino /* write out entries with no use capabilities immediately to save storage */
2555f4613f2SJohn Marino {
2565f4613f2SJohn Marino #if !HAVE_BIG_CORE
2575f4613f2SJohn Marino /*
2585f4613f2SJohn Marino * This is strictly a core-economy kluge. The really clean way to handle
2595f4613f2SJohn Marino * compilation is to slurp the whole file into core and then do all the
2605f4613f2SJohn Marino * name-collision checks and entry writes in one swell foop. But the
2615f4613f2SJohn Marino * terminfo master file is large enough that some core-poor systems swap
2625f4613f2SJohn Marino * like crazy when you compile it this way...there have been reports of
2635f4613f2SJohn Marino * this process taking *three hours*, rather than the twenty seconds or
2645f4613f2SJohn Marino * less typical on my development box.
2655f4613f2SJohn Marino *
2665f4613f2SJohn Marino * So. This hook *immediately* writes out the referenced entry if it
2675f4613f2SJohn Marino * has no use capabilities. The compiler main loop refrains from
2685f4613f2SJohn Marino * adding the entry to the in-core list when this hook fires. If some
2695f4613f2SJohn Marino * other entry later needs to reference an entry that got written
2705f4613f2SJohn Marino * immediately, that's OK; the resolution code will fetch it off disk
2715f4613f2SJohn Marino * when it can't find it in core.
2725f4613f2SJohn Marino *
2735f4613f2SJohn Marino * Name collisions will still be detected, just not as cleanly. The
2745f4613f2SJohn Marino * write_entry() code complains before overwriting an entry that
2755f4613f2SJohn Marino * postdates the time of tic's first call to write_entry(). Thus
2765f4613f2SJohn Marino * it will complain about overwriting entries newly made during the
2775f4613f2SJohn Marino * tic run, but not about overwriting ones that predate it.
2785f4613f2SJohn Marino *
2795f4613f2SJohn Marino * The reason this is a hook, and not in line with the rest of the
2805f4613f2SJohn Marino * compiler code, is that the support for termcap fallback cannot assume
2815f4613f2SJohn Marino * it has anywhere to spool out these entries!
2825f4613f2SJohn Marino *
2835f4613f2SJohn Marino * The _nc_set_type() call here requires a compensating one in
2845f4613f2SJohn Marino * _nc_parse_entry().
2855f4613f2SJohn Marino *
2865f4613f2SJohn Marino * If you define HAVE_BIG_CORE, you'll disable this kluge. This will
2875f4613f2SJohn Marino * make tic a bit faster (because the resolution code won't have to do
2885f4613f2SJohn Marino * disk I/O nearly as often).
2895f4613f2SJohn Marino */
2905f4613f2SJohn Marino if (ep->nuses == 0) {
2915f4613f2SJohn Marino int oldline = _nc_curr_line;
2925f4613f2SJohn Marino
2935f4613f2SJohn Marino write_it(ep);
2945f4613f2SJohn Marino _nc_curr_line = oldline;
2955f4613f2SJohn Marino free(ep->tterm.str_table);
2965f4613f2SJohn Marino return (TRUE);
2975f4613f2SJohn Marino }
2985f4613f2SJohn Marino #endif /* HAVE_BIG_CORE */
2995f4613f2SJohn Marino return (FALSE);
3005f4613f2SJohn Marino }
3015f4613f2SJohn Marino
3025f4613f2SJohn Marino static void
put_translate(int c)3035f4613f2SJohn Marino put_translate(int c)
3045f4613f2SJohn Marino /* emit a comment char, translating terminfo names to termcap names */
3055f4613f2SJohn Marino {
3065f4613f2SJohn Marino static bool in_name = FALSE;
3075f4613f2SJohn Marino static size_t have, used;
3085f4613f2SJohn Marino static char *namebuf, *suffix;
3095f4613f2SJohn Marino
3105f4613f2SJohn Marino if (in_name) {
3115f4613f2SJohn Marino if (used + 1 >= have) {
3125f4613f2SJohn Marino have += 132;
3133468e90cSJohn Marino if ((namebuf = typeRealloc(char, have, namebuf)) == 0)
3143468e90cSJohn Marino failed("put_translate namebuf");
3153468e90cSJohn Marino if ((suffix = typeRealloc(char, have, suffix)) == 0)
3163468e90cSJohn Marino failed("put_translate suffix");
3175f4613f2SJohn Marino }
3185f4613f2SJohn Marino if (c == '\n' || c == '@') {
3195f4613f2SJohn Marino namebuf[used++] = '\0';
3205f4613f2SJohn Marino (void) putchar('<');
3215f4613f2SJohn Marino (void) fputs(namebuf, stdout);
3225f4613f2SJohn Marino putchar(c);
3235f4613f2SJohn Marino in_name = FALSE;
3245f4613f2SJohn Marino } else if (c != '>') {
3255f4613f2SJohn Marino namebuf[used++] = (char) c;
3265f4613f2SJohn Marino } else { /* ah! candidate name! */
3275f4613f2SJohn Marino char *up;
3285f4613f2SJohn Marino NCURSES_CONST char *tp;
3295f4613f2SJohn Marino
3305f4613f2SJohn Marino namebuf[used++] = '\0';
3315f4613f2SJohn Marino in_name = FALSE;
3325f4613f2SJohn Marino
3335f4613f2SJohn Marino suffix[0] = '\0';
3345f4613f2SJohn Marino if ((up = strchr(namebuf, '#')) != 0
3355f4613f2SJohn Marino || (up = strchr(namebuf, '=')) != 0
3365f4613f2SJohn Marino || ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {
3373468e90cSJohn Marino _nc_STRCPY(suffix, up, have);
3385f4613f2SJohn Marino *up = '\0';
3395f4613f2SJohn Marino }
3405f4613f2SJohn Marino
3415f4613f2SJohn Marino if ((tp = nametrans(namebuf)) != 0) {
3425f4613f2SJohn Marino (void) putchar(':');
3435f4613f2SJohn Marino (void) fputs(tp, stdout);
3445f4613f2SJohn Marino (void) fputs(suffix, stdout);
3455f4613f2SJohn Marino (void) putchar(':');
3465f4613f2SJohn Marino } else {
3475f4613f2SJohn Marino /* couldn't find a translation, just dump the name */
3485f4613f2SJohn Marino (void) putchar('<');
3495f4613f2SJohn Marino (void) fputs(namebuf, stdout);
3505f4613f2SJohn Marino (void) fputs(suffix, stdout);
3515f4613f2SJohn Marino (void) putchar('>');
3525f4613f2SJohn Marino }
3535f4613f2SJohn Marino }
3545f4613f2SJohn Marino } else {
3555f4613f2SJohn Marino used = 0;
3565f4613f2SJohn Marino if (c == '<') {
3575f4613f2SJohn Marino in_name = TRUE;
3585f4613f2SJohn Marino } else {
3595f4613f2SJohn Marino putchar(c);
3605f4613f2SJohn Marino }
3615f4613f2SJohn Marino }
3625f4613f2SJohn Marino }
3635f4613f2SJohn Marino
3645f4613f2SJohn Marino /* Returns a string, stripped of leading/trailing whitespace */
3655f4613f2SJohn Marino static char *
stripped(char * src)3665f4613f2SJohn Marino stripped(char *src)
3675f4613f2SJohn Marino {
3683468e90cSJohn Marino char *dst = 0;
3693468e90cSJohn Marino
3705f4613f2SJohn Marino while (isspace(UChar(*src)))
3715f4613f2SJohn Marino src++;
3723468e90cSJohn Marino
3735f4613f2SJohn Marino if (*src != '\0') {
3745f4613f2SJohn Marino size_t len;
3755f4613f2SJohn Marino
3763468e90cSJohn Marino if ((dst = strdup(src)) == NULL) {
3775f4613f2SJohn Marino failed("strdup");
3783468e90cSJohn Marino } else {
3795f4613f2SJohn Marino len = strlen(dst);
3805f4613f2SJohn Marino while (--len != 0 && isspace(UChar(dst[len])))
3815f4613f2SJohn Marino dst[len] = '\0';
3825f4613f2SJohn Marino }
3833468e90cSJohn Marino }
3843468e90cSJohn Marino return dst;
3855f4613f2SJohn Marino }
3865f4613f2SJohn Marino
3875f4613f2SJohn Marino static FILE *
open_tempfile(char * filename)3883468e90cSJohn Marino open_tempfile(char *filename)
3895f4613f2SJohn Marino {
3903468e90cSJohn Marino FILE *result = 0;
3913468e90cSJohn Marino
3923468e90cSJohn Marino _nc_STRCPY(filename, "/tmp/XXXXXX", PATH_MAX);
3933468e90cSJohn Marino #if HAVE_MKSTEMP
3943468e90cSJohn Marino {
3953468e90cSJohn Marino int oldmask = (int) umask(077);
3963468e90cSJohn Marino int fd = mkstemp(filename);
3973468e90cSJohn Marino if (fd >= 0)
3983468e90cSJohn Marino result = fdopen(fd, "w");
3993468e90cSJohn Marino umask((mode_t) oldmask);
4003468e90cSJohn Marino }
4013468e90cSJohn Marino #else
4023468e90cSJohn Marino if (tmpnam(filename) != 0)
4033468e90cSJohn Marino result = fopen(filename, "w");
4043468e90cSJohn Marino #endif
4053468e90cSJohn Marino return result;
4063468e90cSJohn Marino }
4073468e90cSJohn Marino
4083468e90cSJohn Marino static FILE *
copy_input(FILE * source,const char * filename,char * alt_file)4093468e90cSJohn Marino copy_input(FILE *source, const char *filename, char *alt_file)
4103468e90cSJohn Marino {
4113468e90cSJohn Marino char my_altfile[PATH_MAX];
4123468e90cSJohn Marino FILE *result = 0;
4133468e90cSJohn Marino FILE *target = 0;
4143468e90cSJohn Marino int ch;
4153468e90cSJohn Marino
4163468e90cSJohn Marino if (alt_file == 0)
4173468e90cSJohn Marino alt_file = my_altfile;
4183468e90cSJohn Marino
4193468e90cSJohn Marino if (source == 0) {
4203468e90cSJohn Marino failed("copy_input (source)");
4213468e90cSJohn Marino } else if ((target = open_tempfile(alt_file)) == 0) {
4223468e90cSJohn Marino failed("copy_input (target)");
4233468e90cSJohn Marino } else {
4243468e90cSJohn Marino clearerr(source);
4253468e90cSJohn Marino for (;;) {
4263468e90cSJohn Marino ch = fgetc(source);
4273468e90cSJohn Marino if (feof(source)) {
4283468e90cSJohn Marino break;
4293468e90cSJohn Marino } else if (ferror(source)) {
4303468e90cSJohn Marino failed(filename);
4313468e90cSJohn Marino } else if (ch == 0) {
4323468e90cSJohn Marino /* don't loop in case someone wants to convert /dev/zero */
4333468e90cSJohn Marino fprintf(stderr, "%s: %s is not a text-file\n", _nc_progname, filename);
4343468e90cSJohn Marino ExitProgram(EXIT_FAILURE);
4353468e90cSJohn Marino }
4363468e90cSJohn Marino fputc(ch, target);
4373468e90cSJohn Marino }
4383468e90cSJohn Marino fclose(source);
4393468e90cSJohn Marino /*
4403468e90cSJohn Marino * rewind() does not force the target file's data to disk (not does
4413468e90cSJohn Marino * fflush()...). So open a second stream on the data and then close
4423468e90cSJohn Marino * the one that we were writing on before starting to read from the
4433468e90cSJohn Marino * second stream.
4443468e90cSJohn Marino */
4453468e90cSJohn Marino result = fopen(alt_file, "r+");
4463468e90cSJohn Marino fclose(target);
4473468e90cSJohn Marino to_remove = strdup(alt_file);
4483468e90cSJohn Marino }
4493468e90cSJohn Marino return result;
4503468e90cSJohn Marino }
4513468e90cSJohn Marino
4523468e90cSJohn Marino static FILE *
open_input(const char * filename,char * alt_file)4533468e90cSJohn Marino open_input(const char *filename, char *alt_file)
4543468e90cSJohn Marino {
4553468e90cSJohn Marino FILE *fp;
4565f4613f2SJohn Marino struct stat sb;
4573468e90cSJohn Marino int mode;
4583468e90cSJohn Marino
4593468e90cSJohn Marino if (!strcmp(filename, "-")) {
4603468e90cSJohn Marino fp = copy_input(stdin, STDIN_NAME, alt_file);
4613468e90cSJohn Marino } else if (stat(filename, &sb) < 0) {
4623468e90cSJohn Marino fprintf(stderr, "%s: %s %s\n", _nc_progname, filename, strerror(errno));
4633468e90cSJohn Marino ExitProgram(EXIT_FAILURE);
4643468e90cSJohn Marino } else if ((mode = (sb.st_mode & S_IFMT)) == S_IFDIR
4653468e90cSJohn Marino || (mode != S_IFREG && mode != S_IFCHR && mode != S_IFIFO)) {
4663468e90cSJohn Marino fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);
4673468e90cSJohn Marino ExitProgram(EXIT_FAILURE);
4683468e90cSJohn Marino } else {
4693468e90cSJohn Marino fp = fopen(filename, "r");
4705f4613f2SJohn Marino
4715f4613f2SJohn Marino if (fp == 0) {
4725f4613f2SJohn Marino fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename);
4735f4613f2SJohn Marino ExitProgram(EXIT_FAILURE);
4745f4613f2SJohn Marino }
4753468e90cSJohn Marino if (mode != S_IFREG) {
4763468e90cSJohn Marino if (alt_file != 0) {
4773468e90cSJohn Marino FILE *fp2 = copy_input(fp, filename, alt_file);
4783468e90cSJohn Marino fp = fp2;
4793468e90cSJohn Marino } else {
4805f4613f2SJohn Marino fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);
4815f4613f2SJohn Marino ExitProgram(EXIT_FAILURE);
4825f4613f2SJohn Marino }
4833468e90cSJohn Marino }
4843468e90cSJohn Marino }
4855f4613f2SJohn Marino return fp;
4865f4613f2SJohn Marino }
4875f4613f2SJohn Marino
4885f4613f2SJohn Marino /* Parse the "-e" option-value into a list of names */
4895f4613f2SJohn Marino static char **
make_namelist(char * src)4905f4613f2SJohn Marino make_namelist(char *src)
4915f4613f2SJohn Marino {
4925f4613f2SJohn Marino char **dst = 0;
4935f4613f2SJohn Marino
4945f4613f2SJohn Marino char *s, *base;
4955f4613f2SJohn Marino unsigned pass, n, nn;
4965f4613f2SJohn Marino char buffer[BUFSIZ];
4975f4613f2SJohn Marino
4985f4613f2SJohn Marino if (src == 0) {
4995f4613f2SJohn Marino /* EMPTY */ ;
5005f4613f2SJohn Marino } else if (strchr(src, '/') != 0) { /* a filename */
5013468e90cSJohn Marino FILE *fp = open_input(src, (char *) 0);
5025f4613f2SJohn Marino
5035f4613f2SJohn Marino for (pass = 1; pass <= 2; pass++) {
5045f4613f2SJohn Marino nn = 0;
5055f4613f2SJohn Marino while (fgets(buffer, sizeof(buffer), fp) != 0) {
5065f4613f2SJohn Marino if ((s = stripped(buffer)) != 0) {
5075f4613f2SJohn Marino if (dst != 0)
5085f4613f2SJohn Marino dst[nn] = s;
5095f4613f2SJohn Marino else
5105f4613f2SJohn Marino free(s);
5115f4613f2SJohn Marino nn++;
5125f4613f2SJohn Marino }
5135f4613f2SJohn Marino }
5145f4613f2SJohn Marino if (pass == 1) {
5153468e90cSJohn Marino if ((dst = typeCalloc(char *, nn + 1)) == 0)
5163468e90cSJohn Marino failed("make_namelist");
5175f4613f2SJohn Marino rewind(fp);
5185f4613f2SJohn Marino }
5195f4613f2SJohn Marino }
5205f4613f2SJohn Marino fclose(fp);
5215f4613f2SJohn Marino } else { /* literal list of names */
5225f4613f2SJohn Marino for (pass = 1; pass <= 2; pass++) {
5235f4613f2SJohn Marino for (n = nn = 0, base = src;; n++) {
5245f4613f2SJohn Marino int mark = src[n];
5255f4613f2SJohn Marino if (mark == ',' || mark == '\0') {
5265f4613f2SJohn Marino if (pass == 1) {
5275f4613f2SJohn Marino nn++;
5285f4613f2SJohn Marino } else {
5295f4613f2SJohn Marino src[n] = '\0';
5305f4613f2SJohn Marino if ((s = stripped(base)) != 0)
5315f4613f2SJohn Marino dst[nn++] = s;
5325f4613f2SJohn Marino base = &src[n + 1];
5335f4613f2SJohn Marino }
5345f4613f2SJohn Marino }
5355f4613f2SJohn Marino if (mark == '\0')
5365f4613f2SJohn Marino break;
5375f4613f2SJohn Marino }
5383468e90cSJohn Marino if (pass == 1) {
5393468e90cSJohn Marino if ((dst = typeCalloc(char *, nn + 1)) == 0)
5403468e90cSJohn Marino failed("make_namelist");
5413468e90cSJohn Marino }
5425f4613f2SJohn Marino }
5435f4613f2SJohn Marino }
5445f4613f2SJohn Marino if (showsummary && (dst != 0)) {
5455f4613f2SJohn Marino fprintf(log_fp, "Entries that will be compiled:\n");
5465f4613f2SJohn Marino for (n = 0; dst[n] != 0; n++)
5475f4613f2SJohn Marino fprintf(log_fp, "%u:%s\n", n + 1, dst[n]);
5485f4613f2SJohn Marino }
5495f4613f2SJohn Marino return dst;
5505f4613f2SJohn Marino }
5515f4613f2SJohn Marino
5525f4613f2SJohn Marino static bool
matches(char ** needle,const char * haystack)5535f4613f2SJohn Marino matches(char **needle, const char *haystack)
5545f4613f2SJohn Marino /* does entry in needle list match |-separated field in haystack? */
5555f4613f2SJohn Marino {
5565f4613f2SJohn Marino bool code = FALSE;
5575f4613f2SJohn Marino size_t n;
5585f4613f2SJohn Marino
5595f4613f2SJohn Marino if (needle != 0) {
5605f4613f2SJohn Marino for (n = 0; needle[n] != 0; n++) {
5615f4613f2SJohn Marino if (_nc_name_match(haystack, needle[n], "|")) {
5625f4613f2SJohn Marino code = TRUE;
5635f4613f2SJohn Marino break;
5645f4613f2SJohn Marino }
5655f4613f2SJohn Marino }
5665f4613f2SJohn Marino } else
5675f4613f2SJohn Marino code = TRUE;
5685f4613f2SJohn Marino return (code);
5695f4613f2SJohn Marino }
5705f4613f2SJohn Marino
5713468e90cSJohn Marino static char *
valid_db_path(const char * nominal)5723468e90cSJohn Marino valid_db_path(const char *nominal)
5735f4613f2SJohn Marino {
5743468e90cSJohn Marino struct stat sb;
5753468e90cSJohn Marino #if USE_HASHED_DB
5763468e90cSJohn Marino char suffix[] = DBM_SUFFIX;
5773468e90cSJohn Marino size_t need = strlen(nominal) + sizeof(suffix);
5783468e90cSJohn Marino char *result = malloc(need);
5793468e90cSJohn Marino
5803468e90cSJohn Marino if (result == 0)
5813468e90cSJohn Marino failed("valid_db_path");
5823468e90cSJohn Marino _nc_STRCPY(result, nominal, need);
5833468e90cSJohn Marino if (strcmp(result + need - sizeof(suffix), suffix)) {
5843468e90cSJohn Marino _nc_STRCAT(result, suffix, need);
5853468e90cSJohn Marino }
5865f4613f2SJohn Marino #else
5873468e90cSJohn Marino char *result = strdup(nominal);
5885f4613f2SJohn Marino #endif
5893468e90cSJohn Marino
5903468e90cSJohn Marino DEBUG(1, ("** stat(%s)", result));
5913468e90cSJohn Marino if (stat(result, &sb) >= 0) {
5923468e90cSJohn Marino #if USE_HASHED_DB
5933468e90cSJohn Marino if (!S_ISREG(sb.st_mode)
5943468e90cSJohn Marino || access(result, R_OK | W_OK) != 0) {
5953468e90cSJohn Marino DEBUG(1, ("...not a writable file"));
5963468e90cSJohn Marino free(result);
5973468e90cSJohn Marino result = 0;
5983468e90cSJohn Marino }
5993468e90cSJohn Marino #else
6003468e90cSJohn Marino if (!S_ISDIR(sb.st_mode)
6013468e90cSJohn Marino || access(result, R_OK | W_OK | X_OK) != 0) {
6023468e90cSJohn Marino DEBUG(1, ("...not a writable directory"));
6033468e90cSJohn Marino free(result);
6043468e90cSJohn Marino result = 0;
6053468e90cSJohn Marino }
6063468e90cSJohn Marino #endif
6073468e90cSJohn Marino } else {
6083468e90cSJohn Marino /* check if parent is directory and is writable */
6093468e90cSJohn Marino unsigned leaf = _nc_pathlast(result);
6103468e90cSJohn Marino
6113468e90cSJohn Marino DEBUG(1, ("...not found"));
6123468e90cSJohn Marino if (leaf) {
6133468e90cSJohn Marino char save = result[leaf];
6143468e90cSJohn Marino result[leaf] = 0;
6153468e90cSJohn Marino if (stat(result, &sb) >= 0
6163468e90cSJohn Marino && S_ISDIR(sb.st_mode)
6173468e90cSJohn Marino && access(result, R_OK | W_OK | X_OK) == 0) {
6183468e90cSJohn Marino result[leaf] = save;
6193468e90cSJohn Marino } else {
6203468e90cSJohn Marino DEBUG(1, ("...parent directory %s is not writable", result));
6213468e90cSJohn Marino free(result);
6223468e90cSJohn Marino result = 0;
6233468e90cSJohn Marino }
6243468e90cSJohn Marino } else {
6253468e90cSJohn Marino DEBUG(1, ("... no parent directory"));
6263468e90cSJohn Marino free(result);
6273468e90cSJohn Marino result = 0;
6283468e90cSJohn Marino }
6293468e90cSJohn Marino }
6305f4613f2SJohn Marino return result;
6315f4613f2SJohn Marino }
6325f4613f2SJohn Marino
6333468e90cSJohn Marino /*
6343468e90cSJohn Marino * Show the databases to which tic could write. The location to which it
6353468e90cSJohn Marino * writes is always the first one. If none are writable, print an error
6363468e90cSJohn Marino * message.
6373468e90cSJohn Marino */
6383468e90cSJohn Marino static void
show_databases(const char * outdir)6393468e90cSJohn Marino show_databases(const char *outdir)
6403468e90cSJohn Marino {
6413468e90cSJohn Marino bool specific = (outdir != 0) || getenv("TERMINFO") != 0;
6423468e90cSJohn Marino char *result;
6433468e90cSJohn Marino const char *tried = 0;
6443468e90cSJohn Marino
6453468e90cSJohn Marino if (outdir == 0) {
6463468e90cSJohn Marino outdir = _nc_tic_dir(0);
6473468e90cSJohn Marino }
6483468e90cSJohn Marino if ((result = valid_db_path(outdir)) != 0) {
6493468e90cSJohn Marino printf("%s\n", result);
6503468e90cSJohn Marino free(result);
6513468e90cSJohn Marino } else {
6523468e90cSJohn Marino tried = outdir;
6533468e90cSJohn Marino }
6543468e90cSJohn Marino
6553468e90cSJohn Marino if ((outdir = _nc_home_terminfo())) {
6563468e90cSJohn Marino if ((result = valid_db_path(outdir)) != 0) {
6573468e90cSJohn Marino printf("%s\n", result);
6583468e90cSJohn Marino free(result);
6593468e90cSJohn Marino } else if (!specific) {
6603468e90cSJohn Marino tried = outdir;
6613468e90cSJohn Marino }
6623468e90cSJohn Marino }
6633468e90cSJohn Marino
6643468e90cSJohn Marino /*
6653468e90cSJohn Marino * If we can write in neither location, give an error message.
6663468e90cSJohn Marino */
6673468e90cSJohn Marino if (tried) {
6683468e90cSJohn Marino fflush(stdout);
6693468e90cSJohn Marino fprintf(stderr, "%s: %s (no permission)\n", _nc_progname, tried);
6703468e90cSJohn Marino ExitProgram(EXIT_FAILURE);
6713468e90cSJohn Marino }
6723468e90cSJohn Marino }
6733468e90cSJohn Marino
6743468e90cSJohn Marino static void
add_digit(int * target,int source)6753468e90cSJohn Marino add_digit(int *target, int source)
6763468e90cSJohn Marino {
6773468e90cSJohn Marino *target = (*target * 10) + (source - '0');
6783468e90cSJohn Marino }
6793468e90cSJohn Marino
6805f4613f2SJohn Marino int
main(int argc,char * argv[])6815f4613f2SJohn Marino main(int argc, char *argv[])
6825f4613f2SJohn Marino {
6835f4613f2SJohn Marino char my_tmpname[PATH_MAX];
6843468e90cSJohn Marino char my_altfile[PATH_MAX];
6853468e90cSJohn Marino int v_opt = -1;
6865f4613f2SJohn Marino int smart_defaults = TRUE;
6875f4613f2SJohn Marino char *termcap;
6885f4613f2SJohn Marino ENTRY *qp;
6895f4613f2SJohn Marino
6905f4613f2SJohn Marino int this_opt, last_opt = '?';
6915f4613f2SJohn Marino
6925f4613f2SJohn Marino int outform = F_TERMINFO; /* output format */
6935f4613f2SJohn Marino int sortmode = S_TERMINFO; /* sort_mode */
6945f4613f2SJohn Marino
6955f4613f2SJohn Marino int width = 60;
6963468e90cSJohn Marino int height = 65535;
6975f4613f2SJohn Marino bool formatted = FALSE; /* reformat complex strings? */
6985f4613f2SJohn Marino bool literal = FALSE; /* suppress post-processing? */
6995f4613f2SJohn Marino int numbers = 0; /* format "%'char'" to/from "%{number}" */
7005f4613f2SJohn Marino bool forceresolve = FALSE; /* force resolution */
7015f4613f2SJohn Marino bool limited = TRUE;
7025f4613f2SJohn Marino char *tversion = (char *) NULL;
7035f4613f2SJohn Marino const char *source_file = "terminfo";
7045f4613f2SJohn Marino char *outdir = (char *) NULL;
7055f4613f2SJohn Marino bool check_only = FALSE;
7065f4613f2SJohn Marino bool suppress_untranslatable = FALSE;
7073468e90cSJohn Marino int quickdump = 0;
7083468e90cSJohn Marino bool quiet = FALSE;
709*32bb5217SDaniel Fojt bool wrap_strings = FALSE;
7105f4613f2SJohn Marino
7115f4613f2SJohn Marino log_fp = stderr;
7125f4613f2SJohn Marino
7135f4613f2SJohn Marino _nc_progname = _nc_rootname(argv[0]);
7143468e90cSJohn Marino atexit(cleanup);
7155f4613f2SJohn Marino
7165f4613f2SJohn Marino if ((infodump = same_program(_nc_progname, PROG_CAPTOINFO)) != FALSE) {
7175f4613f2SJohn Marino outform = F_TERMINFO;
7185f4613f2SJohn Marino sortmode = S_TERMINFO;
7195f4613f2SJohn Marino }
7205f4613f2SJohn Marino if ((capdump = same_program(_nc_progname, PROG_INFOTOCAP)) != FALSE) {
7215f4613f2SJohn Marino outform = F_TERMCAP;
7225f4613f2SJohn Marino sortmode = S_TERMCAP;
7235f4613f2SJohn Marino }
7245f4613f2SJohn Marino #if NCURSES_XNAMES
7255f4613f2SJohn Marino use_extended_names(FALSE);
7265f4613f2SJohn Marino #endif
7273468e90cSJohn Marino _nc_strict_bsd = 0;
7285f4613f2SJohn Marino
7295f4613f2SJohn Marino /*
7305f4613f2SJohn Marino * Processing arguments is a little complicated, since someone made a
7315f4613f2SJohn Marino * design decision to allow the numeric values for -w, -v options to
7325f4613f2SJohn Marino * be optional.
7335f4613f2SJohn Marino */
7345f4613f2SJohn Marino while ((this_opt = getopt(argc, argv,
735*32bb5217SDaniel Fojt "0123456789CDIKLNQR:TUVWace:fGgo:qrstvwx")) != -1) {
7365f4613f2SJohn Marino if (isdigit(this_opt)) {
7375f4613f2SJohn Marino switch (last_opt) {
7383468e90cSJohn Marino case 'Q':
7393468e90cSJohn Marino add_digit(&quickdump, this_opt);
7403468e90cSJohn Marino break;
7415f4613f2SJohn Marino case 'v':
7423468e90cSJohn Marino add_digit(&v_opt, this_opt);
7435f4613f2SJohn Marino break;
7445f4613f2SJohn Marino case 'w':
7453468e90cSJohn Marino add_digit(&width, this_opt);
7465f4613f2SJohn Marino break;
7475f4613f2SJohn Marino default:
7483468e90cSJohn Marino switch (this_opt) {
7493468e90cSJohn Marino case '0':
7503468e90cSJohn Marino last_opt = this_opt;
7513468e90cSJohn Marino width = 65535;
7523468e90cSJohn Marino height = 1;
7533468e90cSJohn Marino break;
7543468e90cSJohn Marino case '1':
7555f4613f2SJohn Marino last_opt = this_opt;
7565f4613f2SJohn Marino width = 0;
7573468e90cSJohn Marino break;
7583468e90cSJohn Marino default:
7593468e90cSJohn Marino usage();
7603468e90cSJohn Marino }
7615f4613f2SJohn Marino }
7625f4613f2SJohn Marino continue;
7635f4613f2SJohn Marino }
7645f4613f2SJohn Marino switch (this_opt) {
7653468e90cSJohn Marino case 'K':
7663468e90cSJohn Marino _nc_strict_bsd = 1;
7673468e90cSJohn Marino /* the initial version of -K in 20110730 fell-thru here, but the
7683468e90cSJohn Marino * same flag is useful when reading sources -TD
7693468e90cSJohn Marino */
7703468e90cSJohn Marino break;
7715f4613f2SJohn Marino case 'C':
7725f4613f2SJohn Marino capdump = TRUE;
7735f4613f2SJohn Marino outform = F_TERMCAP;
7745f4613f2SJohn Marino sortmode = S_TERMCAP;
7755f4613f2SJohn Marino break;
7763468e90cSJohn Marino case 'D':
7773468e90cSJohn Marino debug_level = VtoTrace(v_opt);
7783468e90cSJohn Marino set_trace_level(debug_level);
7793468e90cSJohn Marino show_databases(outdir);
7803468e90cSJohn Marino ExitProgram(EXIT_SUCCESS);
7813468e90cSJohn Marino break;
7825f4613f2SJohn Marino case 'I':
7835f4613f2SJohn Marino infodump = TRUE;
7845f4613f2SJohn Marino outform = F_TERMINFO;
7855f4613f2SJohn Marino sortmode = S_TERMINFO;
7865f4613f2SJohn Marino break;
7875f4613f2SJohn Marino case 'L':
7885f4613f2SJohn Marino infodump = TRUE;
7895f4613f2SJohn Marino outform = F_VARIABLE;
7905f4613f2SJohn Marino sortmode = S_VARIABLE;
7915f4613f2SJohn Marino break;
7925f4613f2SJohn Marino case 'N':
7935f4613f2SJohn Marino smart_defaults = FALSE;
7945f4613f2SJohn Marino literal = TRUE;
7955f4613f2SJohn Marino break;
7963468e90cSJohn Marino case 'Q':
7973468e90cSJohn Marino quickdump = 0;
7983468e90cSJohn Marino break;
7995f4613f2SJohn Marino case 'R':
8005f4613f2SJohn Marino tversion = optarg;
8015f4613f2SJohn Marino break;
8025f4613f2SJohn Marino case 'T':
8035f4613f2SJohn Marino limited = FALSE;
8045f4613f2SJohn Marino break;
8055f4613f2SJohn Marino case 'U':
8065f4613f2SJohn Marino literal = TRUE;
8075f4613f2SJohn Marino break;
8085f4613f2SJohn Marino case 'V':
8095f4613f2SJohn Marino puts(curses_version());
8105f4613f2SJohn Marino ExitProgram(EXIT_SUCCESS);
811*32bb5217SDaniel Fojt case 'W':
812*32bb5217SDaniel Fojt wrap_strings = TRUE;
813*32bb5217SDaniel Fojt break;
8145f4613f2SJohn Marino case 'c':
8155f4613f2SJohn Marino check_only = TRUE;
8165f4613f2SJohn Marino break;
8175f4613f2SJohn Marino case 'e':
8185f4613f2SJohn Marino namelst = make_namelist(optarg);
8195f4613f2SJohn Marino break;
8205f4613f2SJohn Marino case 'f':
8215f4613f2SJohn Marino formatted = TRUE;
8225f4613f2SJohn Marino break;
8235f4613f2SJohn Marino case 'G':
8245f4613f2SJohn Marino numbers = 1;
8255f4613f2SJohn Marino break;
8265f4613f2SJohn Marino case 'g':
8275f4613f2SJohn Marino numbers = -1;
8285f4613f2SJohn Marino break;
8295f4613f2SJohn Marino case 'o':
8305f4613f2SJohn Marino outdir = optarg;
8315f4613f2SJohn Marino break;
8323468e90cSJohn Marino case 'q':
8333468e90cSJohn Marino quiet = TRUE;
8343468e90cSJohn Marino break;
8355f4613f2SJohn Marino case 'r':
8365f4613f2SJohn Marino forceresolve = TRUE;
8375f4613f2SJohn Marino break;
8385f4613f2SJohn Marino case 's':
8395f4613f2SJohn Marino showsummary = TRUE;
8405f4613f2SJohn Marino break;
8415f4613f2SJohn Marino case 'v':
8425f4613f2SJohn Marino v_opt = 0;
8435f4613f2SJohn Marino break;
8445f4613f2SJohn Marino case 'w':
8455f4613f2SJohn Marino width = 0;
8465f4613f2SJohn Marino break;
8475f4613f2SJohn Marino #if NCURSES_XNAMES
8485f4613f2SJohn Marino case 't':
8495f4613f2SJohn Marino _nc_disable_period = FALSE;
8505f4613f2SJohn Marino suppress_untranslatable = TRUE;
8515f4613f2SJohn Marino break;
8525f4613f2SJohn Marino case 'a':
8535f4613f2SJohn Marino _nc_disable_period = TRUE;
8545f4613f2SJohn Marino /* FALLTHRU */
8555f4613f2SJohn Marino case 'x':
8565f4613f2SJohn Marino use_extended_names(TRUE);
857*32bb5217SDaniel Fojt using_extensions = TRUE;
8585f4613f2SJohn Marino break;
8595f4613f2SJohn Marino #endif
8605f4613f2SJohn Marino default:
8615f4613f2SJohn Marino usage();
8625f4613f2SJohn Marino }
8635f4613f2SJohn Marino last_opt = this_opt;
8645f4613f2SJohn Marino }
8655f4613f2SJohn Marino
8663468e90cSJohn Marino debug_level = VtoTrace(v_opt);
8675f4613f2SJohn Marino set_trace_level(debug_level);
8685f4613f2SJohn Marino
8695f4613f2SJohn Marino if (_nc_tracing) {
8705f4613f2SJohn Marino save_check_termtype = _nc_check_termtype2;
8715f4613f2SJohn Marino _nc_check_termtype2 = check_termtype;
8725f4613f2SJohn Marino }
8735f4613f2SJohn Marino #if !HAVE_BIG_CORE
8745f4613f2SJohn Marino /*
8755f4613f2SJohn Marino * Aaargh! immedhook seriously hoses us!
8765f4613f2SJohn Marino *
8775f4613f2SJohn Marino * One problem with immedhook is it means we can't do -e. Problem
8785f4613f2SJohn Marino * is that we can't guarantee that for each terminal listed, all the
8795f4613f2SJohn Marino * terminals it depends on will have been kept in core for reference
8805f4613f2SJohn Marino * resolution -- in fact it's certain the primitive types at the end
8815f4613f2SJohn Marino * of reference chains *won't* be in core unless they were explicitly
8825f4613f2SJohn Marino * in the select list themselves.
8835f4613f2SJohn Marino */
8845f4613f2SJohn Marino if (namelst && (!infodump && !capdump)) {
8855f4613f2SJohn Marino (void) fprintf(stderr,
8863468e90cSJohn Marino "%s: Sorry, -e can't be used without -I or -C\n",
8873468e90cSJohn Marino _nc_progname);
8885f4613f2SJohn Marino ExitProgram(EXIT_FAILURE);
8895f4613f2SJohn Marino }
8905f4613f2SJohn Marino #endif /* HAVE_BIG_CORE */
8915f4613f2SJohn Marino
8925f4613f2SJohn Marino if (optind < argc) {
8935f4613f2SJohn Marino source_file = argv[optind++];
8945f4613f2SJohn Marino if (optind < argc) {
8955f4613f2SJohn Marino fprintf(stderr,
8965f4613f2SJohn Marino "%s: Too many file names. Usage:\n\t%s %s",
8975f4613f2SJohn Marino _nc_progname,
8985f4613f2SJohn Marino _nc_progname,
8995f4613f2SJohn Marino usage_string);
9005f4613f2SJohn Marino ExitProgram(EXIT_FAILURE);
9015f4613f2SJohn Marino }
9025f4613f2SJohn Marino } else {
9035f4613f2SJohn Marino if (infodump == TRUE) {
9045f4613f2SJohn Marino /* captoinfo's no-argument case */
9055f4613f2SJohn Marino source_file = "/etc/termcap";
9065f4613f2SJohn Marino if ((termcap = getenv("TERMCAP")) != 0
9075f4613f2SJohn Marino && (namelst = make_namelist(getenv("TERM"))) != 0) {
9085f4613f2SJohn Marino if (access(termcap, F_OK) == 0) {
9095f4613f2SJohn Marino /* file exists */
9105f4613f2SJohn Marino source_file = termcap;
9113468e90cSJohn Marino } else {
9123468e90cSJohn Marino if ((tmp_fp = open_tempfile(my_tmpname)) != 0) {
9135f4613f2SJohn Marino source_file = my_tmpname;
9145f4613f2SJohn Marino fprintf(tmp_fp, "%s\n", termcap);
9155f4613f2SJohn Marino fclose(tmp_fp);
9163468e90cSJohn Marino tmp_fp = open_input(source_file, (char *) 0);
9175f4613f2SJohn Marino to_remove = source_file;
9185f4613f2SJohn Marino } else {
9195f4613f2SJohn Marino failed("tmpnam");
9205f4613f2SJohn Marino }
9215f4613f2SJohn Marino }
9223468e90cSJohn Marino }
9235f4613f2SJohn Marino } else {
9245f4613f2SJohn Marino /* tic */
9255f4613f2SJohn Marino fprintf(stderr,
9265f4613f2SJohn Marino "%s: File name needed. Usage:\n\t%s %s",
9275f4613f2SJohn Marino _nc_progname,
9285f4613f2SJohn Marino _nc_progname,
9295f4613f2SJohn Marino usage_string);
9305f4613f2SJohn Marino ExitProgram(EXIT_FAILURE);
9315f4613f2SJohn Marino }
9325f4613f2SJohn Marino }
9335f4613f2SJohn Marino
9343468e90cSJohn Marino if (tmp_fp == 0) {
9353468e90cSJohn Marino tmp_fp = open_input(source_file, my_altfile);
9363468e90cSJohn Marino if (!strcmp(source_file, "-")) {
9373468e90cSJohn Marino source_file = STDIN_NAME;
9383468e90cSJohn Marino }
9393468e90cSJohn Marino }
9405f4613f2SJohn Marino
9413468e90cSJohn Marino if (infodump || check_only) {
9425f4613f2SJohn Marino dump_init(tversion,
943*32bb5217SDaniel Fojt (smart_defaults
9445f4613f2SJohn Marino ? outform
945*32bb5217SDaniel Fojt : F_LITERAL),
946*32bb5217SDaniel Fojt sortmode,
947*32bb5217SDaniel Fojt wrap_strings, width, height,
948*32bb5217SDaniel Fojt debug_level, formatted || check_only, check_only, quickdump);
9493468e90cSJohn Marino } else if (capdump) {
9505f4613f2SJohn Marino dump_init(tversion,
9515f4613f2SJohn Marino outform,
952*32bb5217SDaniel Fojt sortmode,
953*32bb5217SDaniel Fojt wrap_strings, width, height,
954*32bb5217SDaniel Fojt debug_level, FALSE, FALSE, FALSE);
9553468e90cSJohn Marino }
9565f4613f2SJohn Marino
9575f4613f2SJohn Marino /* parse entries out of the source file */
9585f4613f2SJohn Marino _nc_set_source(source_file);
9595f4613f2SJohn Marino #if !HAVE_BIG_CORE
9605f4613f2SJohn Marino if (!(check_only || infodump || capdump))
9615f4613f2SJohn Marino _nc_set_writedir(outdir);
9625f4613f2SJohn Marino #endif /* HAVE_BIG_CORE */
9635f4613f2SJohn Marino _nc_read_entry_source(tmp_fp, (char *) NULL,
9645f4613f2SJohn Marino !smart_defaults || literal, FALSE,
9655f4613f2SJohn Marino ((check_only || infodump || capdump)
9665f4613f2SJohn Marino ? NULLHOOK
9675f4613f2SJohn Marino : immedhook));
9685f4613f2SJohn Marino
9695f4613f2SJohn Marino /* do use resolution */
9705f4613f2SJohn Marino if (check_only || (!infodump && !capdump) || forceresolve) {
9715f4613f2SJohn Marino if (!_nc_resolve_uses2(TRUE, literal) && !check_only) {
9725f4613f2SJohn Marino ExitProgram(EXIT_FAILURE);
9735f4613f2SJohn Marino }
9745f4613f2SJohn Marino }
9755f4613f2SJohn Marino
9765f4613f2SJohn Marino /* length check */
9773468e90cSJohn Marino if (check_only && limited && (capdump || infodump)) {
9785f4613f2SJohn Marino for_entry_list(qp) {
9795f4613f2SJohn Marino if (matches(namelst, qp->tterm.term_names)) {
9805f4613f2SJohn Marino int len = fmt_entry(&qp->tterm, NULL, FALSE, TRUE, infodump, numbers);
9815f4613f2SJohn Marino
9825f4613f2SJohn Marino if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))
9835f4613f2SJohn Marino (void) fprintf(stderr,
984*32bb5217SDaniel Fojt "%s: resolved %s entry is %d bytes long\n",
985*32bb5217SDaniel Fojt _nc_progname,
9865f4613f2SJohn Marino _nc_first_name(qp->tterm.term_names),
9875f4613f2SJohn Marino len);
9885f4613f2SJohn Marino }
9895f4613f2SJohn Marino }
9905f4613f2SJohn Marino }
9915f4613f2SJohn Marino
9925f4613f2SJohn Marino /* write or dump all entries */
9933468e90cSJohn Marino if (check_only) {
9943468e90cSJohn Marino /* this is in case infotocap() generates warnings */
9953468e90cSJohn Marino _nc_curr_col = _nc_curr_line = -1;
9963468e90cSJohn Marino
9973468e90cSJohn Marino for_entry_list(qp) {
9983468e90cSJohn Marino if (matches(namelst, qp->tterm.term_names)) {
9993468e90cSJohn Marino /* this is in case infotocap() generates warnings */
10003468e90cSJohn Marino _nc_set_type(_nc_first_name(qp->tterm.term_names));
10013468e90cSJohn Marino _nc_curr_line = (int) qp->startline;
10023468e90cSJohn Marino repair_acsc(&qp->tterm);
10033468e90cSJohn Marino dump_entry(&qp->tterm, suppress_untranslatable,
10043468e90cSJohn Marino limited, numbers, NULL);
10053468e90cSJohn Marino }
10063468e90cSJohn Marino }
10073468e90cSJohn Marino } else {
10085f4613f2SJohn Marino if (!infodump && !capdump) {
10095f4613f2SJohn Marino _nc_set_writedir(outdir);
10105f4613f2SJohn Marino for_entry_list(qp) {
10115f4613f2SJohn Marino if (matches(namelst, qp->tterm.term_names))
10125f4613f2SJohn Marino write_it(qp);
10135f4613f2SJohn Marino }
10145f4613f2SJohn Marino } else {
10155f4613f2SJohn Marino /* this is in case infotocap() generates warnings */
10165f4613f2SJohn Marino _nc_curr_col = _nc_curr_line = -1;
10175f4613f2SJohn Marino
10185f4613f2SJohn Marino for_entry_list(qp) {
10195f4613f2SJohn Marino if (matches(namelst, qp->tterm.term_names)) {
10203468e90cSJohn Marino long j = qp->cend - qp->cstart;
10215f4613f2SJohn Marino int len = 0;
10225f4613f2SJohn Marino
10235f4613f2SJohn Marino /* this is in case infotocap() generates warnings */
10245f4613f2SJohn Marino _nc_set_type(_nc_first_name(qp->tterm.term_names));
10255f4613f2SJohn Marino
10263468e90cSJohn Marino if (!quiet) {
10275f4613f2SJohn Marino (void) fseek(tmp_fp, qp->cstart, SEEK_SET);
10285f4613f2SJohn Marino while (j-- > 0) {
1029*32bb5217SDaniel Fojt int ch = fgetc(tmp_fp);
1030*32bb5217SDaniel Fojt if (ch == EOF || ferror(tmp_fp)) {
1031*32bb5217SDaniel Fojt break;
1032*32bb5217SDaniel Fojt } else if (infodump) {
1033*32bb5217SDaniel Fojt (void) putchar(ch);
1034*32bb5217SDaniel Fojt } else {
1035*32bb5217SDaniel Fojt put_translate(ch);
1036*32bb5217SDaniel Fojt }
10375f4613f2SJohn Marino }
10383468e90cSJohn Marino }
10395f4613f2SJohn Marino
10405f4613f2SJohn Marino repair_acsc(&qp->tterm);
10415f4613f2SJohn Marino dump_entry(&qp->tterm, suppress_untranslatable,
10425f4613f2SJohn Marino limited, numbers, NULL);
10433468e90cSJohn Marino for (j = 0; j < (long) qp->nuses; j++)
10445f4613f2SJohn Marino dump_uses(qp->uses[j].name, !capdump);
10455f4613f2SJohn Marino len = show_entry();
10465f4613f2SJohn Marino if (debug_level != 0 && !limited)
10475f4613f2SJohn Marino printf("# length=%d\n", len);
10485f4613f2SJohn Marino }
10495f4613f2SJohn Marino }
10503468e90cSJohn Marino if (!namelst && _nc_tail && !quiet) {
10515f4613f2SJohn Marino int c, oldc = '\0';
10525f4613f2SJohn Marino bool in_comment = FALSE;
10535f4613f2SJohn Marino bool trailing_comment = FALSE;
10545f4613f2SJohn Marino
10555f4613f2SJohn Marino (void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET);
10565f4613f2SJohn Marino while ((c = fgetc(tmp_fp)) != EOF) {
10575f4613f2SJohn Marino if (oldc == '\n') {
10585f4613f2SJohn Marino if (c == '#') {
10595f4613f2SJohn Marino trailing_comment = TRUE;
10605f4613f2SJohn Marino in_comment = TRUE;
10615f4613f2SJohn Marino } else {
10625f4613f2SJohn Marino in_comment = FALSE;
10635f4613f2SJohn Marino }
10645f4613f2SJohn Marino }
10655f4613f2SJohn Marino if (trailing_comment
10665f4613f2SJohn Marino && (in_comment || (oldc == '\n' && c == '\n')))
10675f4613f2SJohn Marino putchar(c);
10685f4613f2SJohn Marino oldc = c;
10695f4613f2SJohn Marino }
10705f4613f2SJohn Marino }
10715f4613f2SJohn Marino }
10725f4613f2SJohn Marino }
10735f4613f2SJohn Marino
10745f4613f2SJohn Marino /* Show the directory into which entries were written, and the total
10755f4613f2SJohn Marino * number of entries
10765f4613f2SJohn Marino */
10775f4613f2SJohn Marino if (showsummary
10785f4613f2SJohn Marino && (!(check_only || infodump || capdump))) {
10795f4613f2SJohn Marino int total = _nc_tic_written();
10805f4613f2SJohn Marino if (total != 0)
10815f4613f2SJohn Marino fprintf(log_fp, "%d entries written to %s\n",
10825f4613f2SJohn Marino total,
10835f4613f2SJohn Marino _nc_tic_dir((char *) 0));
10845f4613f2SJohn Marino else
10855f4613f2SJohn Marino fprintf(log_fp, "No entries written\n");
10865f4613f2SJohn Marino }
10875f4613f2SJohn Marino ExitProgram(EXIT_SUCCESS);
10885f4613f2SJohn Marino }
10895f4613f2SJohn Marino
10905f4613f2SJohn Marino /*
10915f4613f2SJohn Marino * This bit of legerdemain turns all the terminfo variable names into
10925f4613f2SJohn Marino * references to locations in the arrays Booleans, Numbers, and Strings ---
10935f4613f2SJohn Marino * precisely what's needed (see comp_parse.c).
10945f4613f2SJohn Marino */
10955f4613f2SJohn Marino #undef CUR
10965f4613f2SJohn Marino #define CUR tp->
10975f4613f2SJohn Marino
10985f4613f2SJohn Marino /*
10995f4613f2SJohn Marino * Check if the alternate character-set capabilities are consistent.
11005f4613f2SJohn Marino */
11015f4613f2SJohn Marino static void
check_acs(TERMTYPE2 * tp)1102*32bb5217SDaniel Fojt check_acs(TERMTYPE2 *tp)
11035f4613f2SJohn Marino {
1104*32bb5217SDaniel Fojt int vt100_smacs = 0;
1105*32bb5217SDaniel Fojt int vt100_rmacs = 0;
1106*32bb5217SDaniel Fojt int vt100_enacs = 0;
1107*32bb5217SDaniel Fojt
1108*32bb5217SDaniel Fojt /*
1109*32bb5217SDaniel Fojt * ena_acs is not always necessary, but if it is present, the enter/exit
1110*32bb5217SDaniel Fojt * capabilities should be.
1111*32bb5217SDaniel Fojt */
1112*32bb5217SDaniel Fojt ANDMISSING(ena_acs, enter_alt_charset_mode);
1113*32bb5217SDaniel Fojt ANDMISSING(ena_acs, exit_alt_charset_mode);
1114*32bb5217SDaniel Fojt PAIRED(exit_alt_charset_mode, exit_alt_charset_mode);
1115*32bb5217SDaniel Fojt
1116*32bb5217SDaniel Fojt /*
1117*32bb5217SDaniel Fojt * vt100-like is frequently used, but perhaps ena_acs is missing, etc.
1118*32bb5217SDaniel Fojt */
1119*32bb5217SDaniel Fojt if (VALID_STRING(enter_alt_charset_mode)) {
1120*32bb5217SDaniel Fojt vt100_smacs = (!strcmp("\033(0", enter_alt_charset_mode)
1121*32bb5217SDaniel Fojt ? 2
1122*32bb5217SDaniel Fojt : (!strcmp("\016", enter_alt_charset_mode)
1123*32bb5217SDaniel Fojt ? 1
1124*32bb5217SDaniel Fojt : 0));
1125*32bb5217SDaniel Fojt }
1126*32bb5217SDaniel Fojt if (VALID_STRING(exit_alt_charset_mode)) {
1127*32bb5217SDaniel Fojt vt100_rmacs = (!strcmp("\033(B", exit_alt_charset_mode)
1128*32bb5217SDaniel Fojt ? 2
1129*32bb5217SDaniel Fojt : (!strcmp("\017", exit_alt_charset_mode)
1130*32bb5217SDaniel Fojt ? 1
1131*32bb5217SDaniel Fojt : 0));
1132*32bb5217SDaniel Fojt }
1133*32bb5217SDaniel Fojt if (VALID_STRING(ena_acs)) {
1134*32bb5217SDaniel Fojt vt100_enacs = (!strcmp("\033(B\033)0", ena_acs)
1135*32bb5217SDaniel Fojt ? 2
1136*32bb5217SDaniel Fojt : 0);
1137*32bb5217SDaniel Fojt }
1138*32bb5217SDaniel Fojt if (vt100_rmacs && vt100_smacs && (vt100_rmacs != vt100_smacs)) {
1139*32bb5217SDaniel Fojt _nc_warning("rmacs/smacs are inconsistent");
1140*32bb5217SDaniel Fojt }
1141*32bb5217SDaniel Fojt if ((vt100_rmacs == 2) && (vt100_smacs == 2) && vt100_enacs) {
1142*32bb5217SDaniel Fojt _nc_warning("rmacs/smacs make enacs redundant");
1143*32bb5217SDaniel Fojt }
1144*32bb5217SDaniel Fojt if ((vt100_rmacs == 1) && (vt100_smacs == 1) && !vt100_enacs) {
1145*32bb5217SDaniel Fojt _nc_warning("VT100-style rmacs/smacs require enacs");
1146*32bb5217SDaniel Fojt }
1147*32bb5217SDaniel Fojt
11485f4613f2SJohn Marino if (VALID_STRING(acs_chars)) {
11495f4613f2SJohn Marino const char *boxes = "lmkjtuvwqxn";
11505f4613f2SJohn Marino char mapped[256];
11515f4613f2SJohn Marino char missing[256];
11525f4613f2SJohn Marino const char *p;
11535f4613f2SJohn Marino char *q;
11545f4613f2SJohn Marino
11555f4613f2SJohn Marino memset(mapped, 0, sizeof(mapped));
11565f4613f2SJohn Marino for (p = acs_chars; *p != '\0'; p += 2) {
11575f4613f2SJohn Marino if (p[1] == '\0') {
11585f4613f2SJohn Marino _nc_warning("acsc has odd number of characters");
11595f4613f2SJohn Marino break;
11605f4613f2SJohn Marino }
11615f4613f2SJohn Marino mapped[UChar(p[0])] = p[1];
11625f4613f2SJohn Marino }
11635f4613f2SJohn Marino
11645f4613f2SJohn Marino if (mapped[UChar('I')] && !mapped[UChar('i')]) {
11655f4613f2SJohn Marino _nc_warning("acsc refers to 'I', which is probably an error");
11665f4613f2SJohn Marino }
11675f4613f2SJohn Marino
11685f4613f2SJohn Marino for (p = boxes, q = missing; *p != '\0'; ++p) {
11695f4613f2SJohn Marino if (!mapped[UChar(p[0])]) {
11705f4613f2SJohn Marino *q++ = p[0];
11715f4613f2SJohn Marino }
11725f4613f2SJohn Marino }
11735f4613f2SJohn Marino *q = '\0';
11745f4613f2SJohn Marino
11755f4613f2SJohn Marino assert(strlen(missing) <= strlen(boxes));
11765f4613f2SJohn Marino if (*missing != '\0' && strcmp(missing, boxes)) {
11775f4613f2SJohn Marino _nc_warning("acsc is missing some line-drawing mapping: %s", missing);
11785f4613f2SJohn Marino }
11795f4613f2SJohn Marino }
11805f4613f2SJohn Marino }
11815f4613f2SJohn Marino
1182*32bb5217SDaniel Fojt static bool
same_color(NCURSES_CONST char * oldcap,NCURSES_CONST char * newcap,int limit)1183*32bb5217SDaniel Fojt same_color(NCURSES_CONST char *oldcap, NCURSES_CONST char *newcap, int limit)
1184*32bb5217SDaniel Fojt {
1185*32bb5217SDaniel Fojt bool result = FALSE;
1186*32bb5217SDaniel Fojt if (limit > 16)
1187*32bb5217SDaniel Fojt limit = 16;
1188*32bb5217SDaniel Fojt if (limit >= 8) {
1189*32bb5217SDaniel Fojt int n;
1190*32bb5217SDaniel Fojt int same;
1191*32bb5217SDaniel Fojt for (n = same = 0; n < limit; ++n) {
1192*32bb5217SDaniel Fojt char *oldvalue = strdup(TPARM_1(oldcap, n));
1193*32bb5217SDaniel Fojt char *newvalue = strdup(TPARM_1(newcap, n));
1194*32bb5217SDaniel Fojt same += !strcmp(oldvalue, newvalue);
1195*32bb5217SDaniel Fojt free(oldvalue);
1196*32bb5217SDaniel Fojt free(newvalue);
1197*32bb5217SDaniel Fojt }
1198*32bb5217SDaniel Fojt result = (same == limit);
1199*32bb5217SDaniel Fojt }
1200*32bb5217SDaniel Fojt return result;
1201*32bb5217SDaniel Fojt }
1202*32bb5217SDaniel Fojt
12035f4613f2SJohn Marino /*
12045f4613f2SJohn Marino * Check if the color capabilities are consistent
12055f4613f2SJohn Marino */
12065f4613f2SJohn Marino static void
check_colors(TERMTYPE2 * tp)1207*32bb5217SDaniel Fojt check_colors(TERMTYPE2 *tp)
12085f4613f2SJohn Marino {
1209*32bb5217SDaniel Fojt char *value;
1210*32bb5217SDaniel Fojt
12115f4613f2SJohn Marino if ((max_colors > 0) != (max_pairs > 0)
12125f4613f2SJohn Marino || ((max_colors > max_pairs) && (initialize_pair == 0)))
12135f4613f2SJohn Marino _nc_warning("inconsistent values for max_colors (%d) and max_pairs (%d)",
12145f4613f2SJohn Marino max_colors, max_pairs);
12155f4613f2SJohn Marino
12165f4613f2SJohn Marino PAIRED(set_foreground, set_background);
12175f4613f2SJohn Marino PAIRED(set_a_foreground, set_a_background);
12185f4613f2SJohn Marino PAIRED(set_color_pair, initialize_pair);
12195f4613f2SJohn Marino
12205f4613f2SJohn Marino if (VALID_STRING(set_foreground)
1221*32bb5217SDaniel Fojt && VALID_STRING(set_a_foreground)) {
1222*32bb5217SDaniel Fojt if (!_nc_capcmp(set_foreground, set_a_foreground)) {
12235f4613f2SJohn Marino _nc_warning("expected setf/setaf to be different");
1224*32bb5217SDaniel Fojt } else if (same_color(set_foreground, set_a_foreground, max_colors)) {
1225*32bb5217SDaniel Fojt _nc_warning("setf/setaf are equivalent");
1226*32bb5217SDaniel Fojt }
1227*32bb5217SDaniel Fojt }
12285f4613f2SJohn Marino
12295f4613f2SJohn Marino if (VALID_STRING(set_background)
1230*32bb5217SDaniel Fojt && VALID_STRING(set_a_background)) {
1231*32bb5217SDaniel Fojt if (!_nc_capcmp(set_background, set_a_background)) {
12325f4613f2SJohn Marino _nc_warning("expected setb/setab to be different");
1233*32bb5217SDaniel Fojt } else if (same_color(set_background, set_a_background, max_colors)) {
1234*32bb5217SDaniel Fojt _nc_warning("setb/setab are equivalent");
1235*32bb5217SDaniel Fojt }
1236*32bb5217SDaniel Fojt }
12375f4613f2SJohn Marino
12385f4613f2SJohn Marino /* see: has_colors() */
12395f4613f2SJohn Marino if (VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs)
1240*32bb5217SDaniel Fojt && ((VALID_STRING(set_foreground)
1241*32bb5217SDaniel Fojt && VALID_STRING(set_background))
1242*32bb5217SDaniel Fojt || (VALID_STRING(set_a_foreground)
1243*32bb5217SDaniel Fojt && VALID_STRING(set_a_background))
12445f4613f2SJohn Marino || set_color_pair)) {
12455f4613f2SJohn Marino if (!VALID_STRING(orig_pair) && !VALID_STRING(orig_colors))
12465f4613f2SJohn Marino _nc_warning("expected either op/oc string for resetting colors");
12475f4613f2SJohn Marino }
12483468e90cSJohn Marino if (can_change) {
12493468e90cSJohn Marino if (!VALID_STRING(initialize_pair) &&
12503468e90cSJohn Marino !VALID_STRING(initialize_color)) {
12513468e90cSJohn Marino _nc_warning("expected initc or initp because ccc is given");
12523468e90cSJohn Marino }
12533468e90cSJohn Marino } else {
12543468e90cSJohn Marino if (VALID_STRING(initialize_pair) ||
12553468e90cSJohn Marino VALID_STRING(initialize_color)) {
12563468e90cSJohn Marino _nc_warning("expected ccc because initc is given");
12573468e90cSJohn Marino }
12583468e90cSJohn Marino }
1259*32bb5217SDaniel Fojt value = tigetstr("RGB");
1260*32bb5217SDaniel Fojt if (VALID_STRING(value)) {
1261*32bb5217SDaniel Fojt int r, g, b;
1262*32bb5217SDaniel Fojt char bad;
1263*32bb5217SDaniel Fojt int code = sscanf(value, "%d/%d/%d%c", &r, &g, &b, &bad);
1264*32bb5217SDaniel Fojt if (code != 3 || r <= 0 || g <= 0 || b <= 0) {
1265*32bb5217SDaniel Fojt _nc_warning("unexpected value for RGB capability: %s", value);
1266*32bb5217SDaniel Fojt }
1267*32bb5217SDaniel Fojt }
1268*32bb5217SDaniel Fojt }
1269*32bb5217SDaniel Fojt
1270*32bb5217SDaniel Fojt static int
csi_length(const char * value)1271*32bb5217SDaniel Fojt csi_length(const char *value)
1272*32bb5217SDaniel Fojt {
1273*32bb5217SDaniel Fojt int result = 0;
1274*32bb5217SDaniel Fojt
1275*32bb5217SDaniel Fojt if (value[0] == '\033' && value[1] == '[') {
1276*32bb5217SDaniel Fojt result = 2;
1277*32bb5217SDaniel Fojt } else if (UChar(value[0]) == 0x9a) {
1278*32bb5217SDaniel Fojt result = 1;
1279*32bb5217SDaniel Fojt }
1280*32bb5217SDaniel Fojt return result;
12815f4613f2SJohn Marino }
12825f4613f2SJohn Marino
12835f4613f2SJohn Marino static char
keypad_final(const char * string)12845f4613f2SJohn Marino keypad_final(const char *string)
12855f4613f2SJohn Marino {
12865f4613f2SJohn Marino char result = '\0';
12875f4613f2SJohn Marino
12885f4613f2SJohn Marino if (VALID_STRING(string)
12895f4613f2SJohn Marino && *string++ == '\033'
12905f4613f2SJohn Marino && *string++ == 'O'
12915f4613f2SJohn Marino && strlen(string) == 1) {
12925f4613f2SJohn Marino result = *string;
12935f4613f2SJohn Marino }
12945f4613f2SJohn Marino
12955f4613f2SJohn Marino return result;
12965f4613f2SJohn Marino }
12975f4613f2SJohn Marino
12983468e90cSJohn Marino static long
keypad_index(const char * string)12995f4613f2SJohn Marino keypad_index(const char *string)
13005f4613f2SJohn Marino {
13015f4613f2SJohn Marino char *test;
13025f4613f2SJohn Marino const char *list = "PQRSwxymtuvlqrsPpn"; /* app-keypad except "Enter" */
13035f4613f2SJohn Marino int ch;
13043468e90cSJohn Marino long result = -1;
13055f4613f2SJohn Marino
13065f4613f2SJohn Marino if ((ch = keypad_final(string)) != '\0') {
13073468e90cSJohn Marino test = (strchr) (list, ch);
13085f4613f2SJohn Marino if (test != 0)
13093468e90cSJohn Marino result = (long) (test - list);
13105f4613f2SJohn Marino }
13115f4613f2SJohn Marino return result;
13125f4613f2SJohn Marino }
13135f4613f2SJohn Marino
13145f4613f2SJohn Marino /*
13155f4613f2SJohn Marino * list[] is down, up, left, right
13165f4613f2SJohn Marino * "left" may be ^H rather than \E[D
13175f4613f2SJohn Marino * "down" may be ^J rather than \E[B
13185f4613f2SJohn Marino * But up/right are generally consistently escape sequences for ANSI terminals.
13195f4613f2SJohn Marino */
13205f4613f2SJohn Marino static void
check_ansi_cursor(char * list[4])13215f4613f2SJohn Marino check_ansi_cursor(char *list[4])
13225f4613f2SJohn Marino {
13235f4613f2SJohn Marino int j, k;
13245f4613f2SJohn Marino int want;
13255f4613f2SJohn Marino size_t suffix;
13265f4613f2SJohn Marino bool skip[4];
13275f4613f2SJohn Marino bool repeated = FALSE;
13285f4613f2SJohn Marino
13295f4613f2SJohn Marino for (j = 0; j < 4; ++j) {
13305f4613f2SJohn Marino skip[j] = FALSE;
13315f4613f2SJohn Marino for (k = 0; k < j; ++k) {
13325f4613f2SJohn Marino if (j != k
13335f4613f2SJohn Marino && !strcmp(list[j], list[k])) {
13345f4613f2SJohn Marino char *value = _nc_tic_expand(list[k], TRUE, 0);
13355f4613f2SJohn Marino _nc_warning("repeated cursor control %s\n", value);
13365f4613f2SJohn Marino repeated = TRUE;
13375f4613f2SJohn Marino }
13385f4613f2SJohn Marino }
13395f4613f2SJohn Marino }
13405f4613f2SJohn Marino if (!repeated) {
13415f4613f2SJohn Marino char *up = list[1];
1342*32bb5217SDaniel Fojt size_t prefix = (size_t) csi_length(up);
13435f4613f2SJohn Marino
13445f4613f2SJohn Marino if (prefix) {
13455f4613f2SJohn Marino suffix = prefix;
13465f4613f2SJohn Marino while (up[suffix] && isdigit(UChar(up[suffix])))
13475f4613f2SJohn Marino ++suffix;
13485f4613f2SJohn Marino }
13495f4613f2SJohn Marino if (prefix && up[suffix] == 'A') {
13505f4613f2SJohn Marino skip[1] = TRUE;
13515f4613f2SJohn Marino if (!strcmp(list[0], "\n"))
13525f4613f2SJohn Marino skip[0] = TRUE;
13535f4613f2SJohn Marino if (!strcmp(list[2], "\b"))
13545f4613f2SJohn Marino skip[2] = TRUE;
13555f4613f2SJohn Marino
13565f4613f2SJohn Marino for (j = 0; j < 4; ++j) {
13575f4613f2SJohn Marino if (skip[j] || strlen(list[j]) == 1)
13585f4613f2SJohn Marino continue;
13595f4613f2SJohn Marino if (memcmp(list[j], up, prefix)) {
13605f4613f2SJohn Marino char *value = _nc_tic_expand(list[j], TRUE, 0);
13615f4613f2SJohn Marino _nc_warning("inconsistent prefix for %s\n", value);
13625f4613f2SJohn Marino continue;
13635f4613f2SJohn Marino }
13645f4613f2SJohn Marino if (strlen(list[j]) < suffix) {
13655f4613f2SJohn Marino char *value = _nc_tic_expand(list[j], TRUE, 0);
13665f4613f2SJohn Marino _nc_warning("inconsistent length for %s, expected %d\n",
13675f4613f2SJohn Marino value, (int) suffix + 1);
13685f4613f2SJohn Marino continue;
13695f4613f2SJohn Marino }
13705f4613f2SJohn Marino want = "BADC"[j];
13715f4613f2SJohn Marino if (list[j][suffix] != want) {
13725f4613f2SJohn Marino char *value = _nc_tic_expand(list[j], TRUE, 0);
13735f4613f2SJohn Marino _nc_warning("inconsistent suffix for %s, expected %c, have %c\n",
13745f4613f2SJohn Marino value, want, list[j][suffix]);
13755f4613f2SJohn Marino }
13765f4613f2SJohn Marino }
13775f4613f2SJohn Marino }
13785f4613f2SJohn Marino }
13795f4613f2SJohn Marino }
13805f4613f2SJohn Marino
13815f4613f2SJohn Marino #define EXPECTED(name) if (!PRESENT(name)) _nc_warning("expected " #name)
13823468e90cSJohn Marino #define UNEXPECTED(name) if (PRESENT(name)) _nc_warning("unexpected " #name ", for %s", why)
13833468e90cSJohn Marino
13843468e90cSJohn Marino static void
check_noaddress(TERMTYPE2 * tp,const char * why)1385*32bb5217SDaniel Fojt check_noaddress(TERMTYPE2 *tp, const char *why)
13863468e90cSJohn Marino {
13873468e90cSJohn Marino UNEXPECTED(column_address);
13883468e90cSJohn Marino UNEXPECTED(cursor_address);
13893468e90cSJohn Marino UNEXPECTED(cursor_home);
13903468e90cSJohn Marino UNEXPECTED(cursor_mem_address);
13913468e90cSJohn Marino UNEXPECTED(cursor_to_ll);
13923468e90cSJohn Marino UNEXPECTED(row_address);
13933468e90cSJohn Marino UNEXPECTED(row_address);
13943468e90cSJohn Marino }
13955f4613f2SJohn Marino
13965f4613f2SJohn Marino static void
check_cursor(TERMTYPE2 * tp)1397*32bb5217SDaniel Fojt check_cursor(TERMTYPE2 *tp)
13985f4613f2SJohn Marino {
13995f4613f2SJohn Marino int count;
14005f4613f2SJohn Marino char *list[4];
14015f4613f2SJohn Marino
14023468e90cSJohn Marino if (hard_copy) {
14033468e90cSJohn Marino check_noaddress(tp, "hard_copy");
14043468e90cSJohn Marino } else if (generic_type) {
14053468e90cSJohn Marino check_noaddress(tp, "generic_type");
14063468e90cSJohn Marino } else if (strchr(tp->term_names, '+') == 0) {
14073468e90cSJohn Marino int y = 0;
14083468e90cSJohn Marino int x = 0;
14093468e90cSJohn Marino if (PRESENT(column_address))
14103468e90cSJohn Marino ++y;
14113468e90cSJohn Marino if (PRESENT(cursor_address))
14123468e90cSJohn Marino y = x = 10;
14133468e90cSJohn Marino if (PRESENT(cursor_home))
14143468e90cSJohn Marino ++y, ++x;
14153468e90cSJohn Marino if (PRESENT(cursor_mem_address))
14163468e90cSJohn Marino y = x = 10;
14173468e90cSJohn Marino if (PRESENT(cursor_to_ll))
14183468e90cSJohn Marino ++y, ++x;
14193468e90cSJohn Marino if (PRESENT(row_address))
14203468e90cSJohn Marino ++x;
14213468e90cSJohn Marino if (PRESENT(cursor_down))
14223468e90cSJohn Marino ++y;
14233468e90cSJohn Marino if (PRESENT(cursor_up))
14243468e90cSJohn Marino ++y;
14253468e90cSJohn Marino if (PRESENT(cursor_left))
14263468e90cSJohn Marino ++x;
14273468e90cSJohn Marino if (PRESENT(cursor_right))
14283468e90cSJohn Marino ++x;
14293468e90cSJohn Marino if (x < 2 && y < 2) {
14303468e90cSJohn Marino _nc_warning("terminal lacks cursor addressing");
14313468e90cSJohn Marino } else {
14323468e90cSJohn Marino if (x < 2)
14333468e90cSJohn Marino _nc_warning("terminal lacks cursor column-addressing");
14343468e90cSJohn Marino if (y < 2)
14353468e90cSJohn Marino _nc_warning("terminal lacks cursor row-addressing");
14363468e90cSJohn Marino }
14373468e90cSJohn Marino }
14383468e90cSJohn Marino
14393468e90cSJohn Marino /* it is rare to have an insert-line feature without a matching delete */
14403468e90cSJohn Marino ANDMISSING(parm_insert_line, insert_line);
14413468e90cSJohn Marino ANDMISSING(parm_delete_line, delete_line);
14423468e90cSJohn Marino ANDMISSING(parm_insert_line, parm_delete_line);
14433468e90cSJohn Marino
14445f4613f2SJohn Marino /* if we have a parameterized form, then the non-parameterized is easy */
14455f4613f2SJohn Marino ANDMISSING(parm_down_cursor, cursor_down);
14465f4613f2SJohn Marino ANDMISSING(parm_up_cursor, cursor_up);
14475f4613f2SJohn Marino ANDMISSING(parm_left_cursor, cursor_left);
14485f4613f2SJohn Marino ANDMISSING(parm_right_cursor, cursor_right);
14495f4613f2SJohn Marino
14505f4613f2SJohn Marino /* Given any of a set of cursor movement, the whole set should be present.
14515f4613f2SJohn Marino * Technically this is not true (we could use cursor_address to fill in
14525f4613f2SJohn Marino * unsupported controls), but it is likely.
14535f4613f2SJohn Marino */
14545f4613f2SJohn Marino count = 0;
14555f4613f2SJohn Marino if (PRESENT(parm_down_cursor)) {
14565f4613f2SJohn Marino list[count++] = parm_down_cursor;
14575f4613f2SJohn Marino }
14585f4613f2SJohn Marino if (PRESENT(parm_up_cursor)) {
14595f4613f2SJohn Marino list[count++] = parm_up_cursor;
14605f4613f2SJohn Marino }
14615f4613f2SJohn Marino if (PRESENT(parm_left_cursor)) {
14625f4613f2SJohn Marino list[count++] = parm_left_cursor;
14635f4613f2SJohn Marino }
14645f4613f2SJohn Marino if (PRESENT(parm_right_cursor)) {
14655f4613f2SJohn Marino list[count++] = parm_right_cursor;
14665f4613f2SJohn Marino }
14675f4613f2SJohn Marino if (count == 4) {
14685f4613f2SJohn Marino check_ansi_cursor(list);
14695f4613f2SJohn Marino } else if (count != 0) {
14705f4613f2SJohn Marino EXPECTED(parm_down_cursor);
14715f4613f2SJohn Marino EXPECTED(parm_up_cursor);
14725f4613f2SJohn Marino EXPECTED(parm_left_cursor);
14735f4613f2SJohn Marino EXPECTED(parm_right_cursor);
14745f4613f2SJohn Marino }
14755f4613f2SJohn Marino
14765f4613f2SJohn Marino count = 0;
14775f4613f2SJohn Marino if (PRESENT(cursor_down)) {
14785f4613f2SJohn Marino list[count++] = cursor_down;
14795f4613f2SJohn Marino }
14805f4613f2SJohn Marino if (PRESENT(cursor_up)) {
14815f4613f2SJohn Marino list[count++] = cursor_up;
14825f4613f2SJohn Marino }
14835f4613f2SJohn Marino if (PRESENT(cursor_left)) {
14845f4613f2SJohn Marino list[count++] = cursor_left;
14855f4613f2SJohn Marino }
14865f4613f2SJohn Marino if (PRESENT(cursor_right)) {
14875f4613f2SJohn Marino list[count++] = cursor_right;
14885f4613f2SJohn Marino }
14895f4613f2SJohn Marino if (count == 4) {
14905f4613f2SJohn Marino check_ansi_cursor(list);
14915f4613f2SJohn Marino } else if (count != 0) {
14925f4613f2SJohn Marino count = 0;
14935f4613f2SJohn Marino if (PRESENT(cursor_down) && strcmp(cursor_down, "\n"))
14945f4613f2SJohn Marino ++count;
14955f4613f2SJohn Marino if (PRESENT(cursor_left) && strcmp(cursor_left, "\b"))
14965f4613f2SJohn Marino ++count;
14975f4613f2SJohn Marino if (PRESENT(cursor_up) && strlen(cursor_up) > 1)
14985f4613f2SJohn Marino ++count;
14995f4613f2SJohn Marino if (PRESENT(cursor_right) && strlen(cursor_right) > 1)
15005f4613f2SJohn Marino ++count;
15015f4613f2SJohn Marino if (count) {
15025f4613f2SJohn Marino EXPECTED(cursor_down);
15035f4613f2SJohn Marino EXPECTED(cursor_up);
15045f4613f2SJohn Marino EXPECTED(cursor_left);
15055f4613f2SJohn Marino EXPECTED(cursor_right);
15065f4613f2SJohn Marino }
15075f4613f2SJohn Marino }
15085f4613f2SJohn Marino }
15095f4613f2SJohn Marino
15105f4613f2SJohn Marino #define MAX_KP 5
15115f4613f2SJohn Marino /*
15125f4613f2SJohn Marino * Do a quick sanity-check for vt100-style keypads to see if the 5-key keypad
15135f4613f2SJohn Marino * is mapped inconsistently.
15145f4613f2SJohn Marino */
15155f4613f2SJohn Marino static void
check_keypad(TERMTYPE2 * tp)1516*32bb5217SDaniel Fojt check_keypad(TERMTYPE2 *tp)
15175f4613f2SJohn Marino {
15185f4613f2SJohn Marino char show[80];
15195f4613f2SJohn Marino
15205f4613f2SJohn Marino if (VALID_STRING(key_a1) &&
15215f4613f2SJohn Marino VALID_STRING(key_a3) &&
15225f4613f2SJohn Marino VALID_STRING(key_b2) &&
15235f4613f2SJohn Marino VALID_STRING(key_c1) &&
15245f4613f2SJohn Marino VALID_STRING(key_c3)) {
15255f4613f2SJohn Marino char final[MAX_KP + 1];
15263468e90cSJohn Marino long list[MAX_KP];
15275f4613f2SJohn Marino int increase = 0;
15285f4613f2SJohn Marino int j, k, kk;
15293468e90cSJohn Marino long last;
15303468e90cSJohn Marino long test;
15315f4613f2SJohn Marino
15325f4613f2SJohn Marino final[0] = keypad_final(key_a1);
15335f4613f2SJohn Marino final[1] = keypad_final(key_a3);
15345f4613f2SJohn Marino final[2] = keypad_final(key_b2);
15355f4613f2SJohn Marino final[3] = keypad_final(key_c1);
15365f4613f2SJohn Marino final[4] = keypad_final(key_c3);
15375f4613f2SJohn Marino final[5] = '\0';
15385f4613f2SJohn Marino
15395f4613f2SJohn Marino /* special case: legacy coding using 1,2,3,0,. on the bottom */
15405f4613f2SJohn Marino assert(strlen(final) <= MAX_KP);
15415f4613f2SJohn Marino if (!strcmp(final, "qsrpn"))
15425f4613f2SJohn Marino return;
15435f4613f2SJohn Marino
15445f4613f2SJohn Marino list[0] = keypad_index(key_a1);
15455f4613f2SJohn Marino list[1] = keypad_index(key_a3);
15465f4613f2SJohn Marino list[2] = keypad_index(key_b2);
15475f4613f2SJohn Marino list[3] = keypad_index(key_c1);
15485f4613f2SJohn Marino list[4] = keypad_index(key_c3);
15495f4613f2SJohn Marino
15505f4613f2SJohn Marino /* check that they're all vt100 keys */
15515f4613f2SJohn Marino for (j = 0; j < MAX_KP; ++j) {
15525f4613f2SJohn Marino if (list[j] < 0) {
15535f4613f2SJohn Marino return;
15545f4613f2SJohn Marino }
15555f4613f2SJohn Marino }
15565f4613f2SJohn Marino
15575f4613f2SJohn Marino /* check if they're all in increasing order */
15585f4613f2SJohn Marino for (j = 1; j < MAX_KP; ++j) {
15595f4613f2SJohn Marino if (list[j] > list[j - 1]) {
15605f4613f2SJohn Marino ++increase;
15615f4613f2SJohn Marino }
15625f4613f2SJohn Marino }
15635f4613f2SJohn Marino if (increase != (MAX_KP - 1)) {
15645f4613f2SJohn Marino show[0] = '\0';
15655f4613f2SJohn Marino
15665f4613f2SJohn Marino for (j = 0, last = -1; j < MAX_KP; ++j) {
15675f4613f2SJohn Marino for (k = 0, kk = -1, test = 100; k < 5; ++k) {
15685f4613f2SJohn Marino if (list[k] > last &&
15695f4613f2SJohn Marino list[k] < test) {
15705f4613f2SJohn Marino test = list[k];
15715f4613f2SJohn Marino kk = k;
15725f4613f2SJohn Marino }
15735f4613f2SJohn Marino }
15745f4613f2SJohn Marino last = test;
15755f4613f2SJohn Marino assert(strlen(show) < (MAX_KP * 4));
15765f4613f2SJohn Marino switch (kk) {
15775f4613f2SJohn Marino case 0:
15783468e90cSJohn Marino _nc_STRCAT(show, " ka1", sizeof(show));
15795f4613f2SJohn Marino break;
15805f4613f2SJohn Marino case 1:
15813468e90cSJohn Marino _nc_STRCAT(show, " ka3", sizeof(show));
15825f4613f2SJohn Marino break;
15835f4613f2SJohn Marino case 2:
15843468e90cSJohn Marino _nc_STRCAT(show, " kb2", sizeof(show));
15855f4613f2SJohn Marino break;
15865f4613f2SJohn Marino case 3:
15873468e90cSJohn Marino _nc_STRCAT(show, " kc1", sizeof(show));
15885f4613f2SJohn Marino break;
15895f4613f2SJohn Marino case 4:
15903468e90cSJohn Marino _nc_STRCAT(show, " kc3", sizeof(show));
15915f4613f2SJohn Marino break;
15925f4613f2SJohn Marino }
15935f4613f2SJohn Marino }
15945f4613f2SJohn Marino
15955f4613f2SJohn Marino _nc_warning("vt100 keypad order inconsistent: %s", show);
15965f4613f2SJohn Marino }
15975f4613f2SJohn Marino
15985f4613f2SJohn Marino } else if (VALID_STRING(key_a1) ||
15995f4613f2SJohn Marino VALID_STRING(key_a3) ||
16005f4613f2SJohn Marino VALID_STRING(key_b2) ||
16015f4613f2SJohn Marino VALID_STRING(key_c1) ||
16025f4613f2SJohn Marino VALID_STRING(key_c3)) {
16035f4613f2SJohn Marino show[0] = '\0';
16045f4613f2SJohn Marino if (keypad_index(key_a1) >= 0)
16053468e90cSJohn Marino _nc_STRCAT(show, " ka1", sizeof(show));
16065f4613f2SJohn Marino if (keypad_index(key_a3) >= 0)
16073468e90cSJohn Marino _nc_STRCAT(show, " ka3", sizeof(show));
16085f4613f2SJohn Marino if (keypad_index(key_b2) >= 0)
16093468e90cSJohn Marino _nc_STRCAT(show, " kb2", sizeof(show));
16105f4613f2SJohn Marino if (keypad_index(key_c1) >= 0)
16113468e90cSJohn Marino _nc_STRCAT(show, " kc1", sizeof(show));
16125f4613f2SJohn Marino if (keypad_index(key_c3) >= 0)
16133468e90cSJohn Marino _nc_STRCAT(show, " kc3", sizeof(show));
16145f4613f2SJohn Marino if (*show != '\0')
16155f4613f2SJohn Marino _nc_warning("vt100 keypad map incomplete:%s", show);
16165f4613f2SJohn Marino }
16173468e90cSJohn Marino
16183468e90cSJohn Marino /*
16193468e90cSJohn Marino * These warnings are useful for consistency checks - it is possible that
16203468e90cSJohn Marino * there are real terminals with mismatches in these
16213468e90cSJohn Marino */
16223468e90cSJohn Marino ANDMISSING(key_ic, key_dc);
16235f4613f2SJohn Marino }
16245f4613f2SJohn Marino
16255f4613f2SJohn Marino static void
check_printer(TERMTYPE2 * tp)1626*32bb5217SDaniel Fojt check_printer(TERMTYPE2 *tp)
16275f4613f2SJohn Marino {
1628*32bb5217SDaniel Fojt (void) tp;
1629*32bb5217SDaniel Fojt #if defined(enter_doublewide_mode) && defined(exit_doublewide_mode)
16305f4613f2SJohn Marino PAIRED(enter_doublewide_mode, exit_doublewide_mode);
1631*32bb5217SDaniel Fojt #endif
1632*32bb5217SDaniel Fojt #if defined(enter_italics_mode) && defined(exit_italics_mode)
16335f4613f2SJohn Marino PAIRED(enter_italics_mode, exit_italics_mode);
1634*32bb5217SDaniel Fojt #endif
1635*32bb5217SDaniel Fojt #if defined(enter_leftward_mode) && defined(exit_leftward_mode)
16365f4613f2SJohn Marino PAIRED(enter_leftward_mode, exit_leftward_mode);
1637*32bb5217SDaniel Fojt #endif
1638*32bb5217SDaniel Fojt #if defined(enter_micro_mode) && defined(exit_micro_mode)
16395f4613f2SJohn Marino PAIRED(enter_micro_mode, exit_micro_mode);
1640*32bb5217SDaniel Fojt #endif
1641*32bb5217SDaniel Fojt #if defined(enter_shadow_mode) && defined(exit_shadow_mode)
16425f4613f2SJohn Marino PAIRED(enter_shadow_mode, exit_shadow_mode);
1643*32bb5217SDaniel Fojt #endif
1644*32bb5217SDaniel Fojt #if defined(enter_subscript_mode) && defined(exit_subscript_mode)
16455f4613f2SJohn Marino PAIRED(enter_subscript_mode, exit_subscript_mode);
1646*32bb5217SDaniel Fojt #endif
1647*32bb5217SDaniel Fojt #if defined(enter_superscript_mode) && defined(exit_superscript_mode)
16485f4613f2SJohn Marino PAIRED(enter_superscript_mode, exit_superscript_mode);
1649*32bb5217SDaniel Fojt #endif
1650*32bb5217SDaniel Fojt #if defined(enter_upward_mode) && defined(exit_upward_mode)
16515f4613f2SJohn Marino PAIRED(enter_upward_mode, exit_upward_mode);
1652*32bb5217SDaniel Fojt #endif
16535f4613f2SJohn Marino
1654*32bb5217SDaniel Fojt #if defined(start_char_set_def) && defined(stop_char_set_def)
16555f4613f2SJohn Marino ANDMISSING(start_char_set_def, stop_char_set_def);
1656*32bb5217SDaniel Fojt #endif
16575f4613f2SJohn Marino
16585f4613f2SJohn Marino /* if we have a parameterized form, then the non-parameterized is easy */
1659*32bb5217SDaniel Fojt #if defined(set_bottom_margin_parm) && defined(set_bottom_margin)
16605f4613f2SJohn Marino ANDMISSING(set_bottom_margin_parm, set_bottom_margin);
1661*32bb5217SDaniel Fojt #endif
1662*32bb5217SDaniel Fojt #if defined(set_left_margin_parm) && defined(set_left_margin)
16635f4613f2SJohn Marino ANDMISSING(set_left_margin_parm, set_left_margin);
1664*32bb5217SDaniel Fojt #endif
1665*32bb5217SDaniel Fojt #if defined(set_right_margin_parm) && defined(set_right_margin)
16665f4613f2SJohn Marino ANDMISSING(set_right_margin_parm, set_right_margin);
1667*32bb5217SDaniel Fojt #endif
1668*32bb5217SDaniel Fojt #if defined(set_top_margin_parm) && defined(set_top_margin)
16695f4613f2SJohn Marino ANDMISSING(set_top_margin_parm, set_top_margin);
1670*32bb5217SDaniel Fojt #endif
16715f4613f2SJohn Marino
1672*32bb5217SDaniel Fojt #if defined(parm_down_micro) && defined(micro_down)
16735f4613f2SJohn Marino ANDMISSING(parm_down_micro, micro_down);
1674*32bb5217SDaniel Fojt #endif
1675*32bb5217SDaniel Fojt #if defined(parm_left_micro) && defined(micro_left)
16765f4613f2SJohn Marino ANDMISSING(parm_left_micro, micro_left);
1677*32bb5217SDaniel Fojt #endif
1678*32bb5217SDaniel Fojt #if defined(parm_right_micro) && defined(micro_right)
16795f4613f2SJohn Marino ANDMISSING(parm_right_micro, micro_right);
1680*32bb5217SDaniel Fojt #endif
1681*32bb5217SDaniel Fojt #if defined(parm_up_micro) && defined(micro_up)
16825f4613f2SJohn Marino ANDMISSING(parm_up_micro, micro_up);
1683*32bb5217SDaniel Fojt #endif
16845f4613f2SJohn Marino }
16855f4613f2SJohn Marino
1686*32bb5217SDaniel Fojt #if NCURSES_XNAMES
16873468e90cSJohn Marino static bool
uses_SGR_39_49(const char * value)16883468e90cSJohn Marino uses_SGR_39_49(const char *value)
16893468e90cSJohn Marino {
16903468e90cSJohn Marino return (strstr(value, "39;49") != 0
16913468e90cSJohn Marino || strstr(value, "49;39") != 0);
16923468e90cSJohn Marino }
16933468e90cSJohn Marino
16943468e90cSJohn Marino /*
16953468e90cSJohn Marino * Check consistency of termcap extensions related to "screen".
16963468e90cSJohn Marino */
16973468e90cSJohn Marino static void
check_screen(TERMTYPE2 * tp)1698*32bb5217SDaniel Fojt check_screen(TERMTYPE2 *tp)
16993468e90cSJohn Marino {
17003468e90cSJohn Marino if (_nc_user_definable) {
17013468e90cSJohn Marino int have_XT = tigetflag("XT");
17023468e90cSJohn Marino int have_XM = tigetflag("XM");
17033468e90cSJohn Marino int have_bce = back_color_erase;
17043468e90cSJohn Marino bool have_kmouse = FALSE;
17053468e90cSJohn Marino bool use_sgr_39_49 = FALSE;
17063468e90cSJohn Marino char *name = _nc_first_name(tp->term_names);
1707*32bb5217SDaniel Fojt bool is_screen = !strncmp(name, "screen", 6);
1708*32bb5217SDaniel Fojt bool screen_base = (is_screen
1709*32bb5217SDaniel Fojt && strchr(name, '.') == 0);
17103468e90cSJohn Marino
17113468e90cSJohn Marino if (!VALID_BOOLEAN(have_bce)) {
17123468e90cSJohn Marino have_bce = FALSE;
17133468e90cSJohn Marino }
17143468e90cSJohn Marino if (!VALID_BOOLEAN(have_XM)) {
17153468e90cSJohn Marino have_XM = FALSE;
17163468e90cSJohn Marino }
17173468e90cSJohn Marino if (!VALID_BOOLEAN(have_XT)) {
17183468e90cSJohn Marino have_XT = FALSE;
17193468e90cSJohn Marino }
17203468e90cSJohn Marino if (VALID_STRING(key_mouse)) {
17213468e90cSJohn Marino have_kmouse = !strcmp("\033[M", key_mouse);
17223468e90cSJohn Marino }
17233468e90cSJohn Marino if (VALID_STRING(orig_colors)) {
17243468e90cSJohn Marino use_sgr_39_49 = uses_SGR_39_49(orig_colors);
17253468e90cSJohn Marino } else if (VALID_STRING(orig_pair)) {
17263468e90cSJohn Marino use_sgr_39_49 = uses_SGR_39_49(orig_pair);
17273468e90cSJohn Marino }
17283468e90cSJohn Marino
17293468e90cSJohn Marino if (have_XM && have_XT) {
1730*32bb5217SDaniel Fojt _nc_warning("screen's XT capability conflicts with XM");
1731*32bb5217SDaniel Fojt } else if (have_XT && screen_base) {
1732*32bb5217SDaniel Fojt _nc_warning("screen's \"screen\" entries should not have XT set");
17333468e90cSJohn Marino } else if (have_XT) {
1734*32bb5217SDaniel Fojt if (!have_kmouse && is_screen) {
17353468e90cSJohn Marino if (VALID_STRING(key_mouse)) {
1736*32bb5217SDaniel Fojt _nc_warning("value of kmous inconsistent with screen's usage");
17373468e90cSJohn Marino } else {
1738*32bb5217SDaniel Fojt _nc_warning("expected kmous capability with XT");
17393468e90cSJohn Marino }
17403468e90cSJohn Marino }
17413468e90cSJohn Marino if (!have_bce && max_colors > 0)
1742*32bb5217SDaniel Fojt _nc_warning("expected bce capability with XT");
17433468e90cSJohn Marino if (!use_sgr_39_49 && have_bce && max_colors > 0)
1744*32bb5217SDaniel Fojt _nc_warning("expected orig_colors capability with XT to have 39/49 parameters");
17453468e90cSJohn Marino if (VALID_STRING(to_status_line))
17463468e90cSJohn Marino _nc_warning("\"tsl\" capability is redundant, given XT");
17473468e90cSJohn Marino } else {
1748*32bb5217SDaniel Fojt if (have_kmouse
1749*32bb5217SDaniel Fojt && !have_XM
1750*32bb5217SDaniel Fojt && !screen_base && strchr(name, '+') == 0) {
1751*32bb5217SDaniel Fojt _nc_warning("expected XT to be set, given kmous");
17523468e90cSJohn Marino }
17533468e90cSJohn Marino }
1754*32bb5217SDaniel Fojt }
1755*32bb5217SDaniel Fojt }
1756*32bb5217SDaniel Fojt #else
1757*32bb5217SDaniel Fojt #define check_screen(tp) /* nothing */
17583468e90cSJohn Marino #endif
17593468e90cSJohn Marino
17605f4613f2SJohn Marino /*
17615f4613f2SJohn Marino * Returns the expected number of parameters for the given capability.
17625f4613f2SJohn Marino */
17635f4613f2SJohn Marino static int
expected_params(const char * name)17645f4613f2SJohn Marino expected_params(const char *name)
17655f4613f2SJohn Marino {
17663468e90cSJohn Marino #define DATA(name,count) { { name }, count }
17675f4613f2SJohn Marino /* *INDENT-OFF* */
17685f4613f2SJohn Marino static const struct {
17693468e90cSJohn Marino const char name[9];
17705f4613f2SJohn Marino int count;
17715f4613f2SJohn Marino } table[] = {
17723468e90cSJohn Marino DATA( "S0", 1 ), /* 'screen' extension */
17733468e90cSJohn Marino DATA( "birep", 2 ),
17743468e90cSJohn Marino DATA( "chr", 1 ),
17753468e90cSJohn Marino DATA( "colornm", 1 ),
17763468e90cSJohn Marino DATA( "cpi", 1 ),
17773468e90cSJohn Marino DATA( "csnm", 1 ),
17783468e90cSJohn Marino DATA( "csr", 2 ),
17793468e90cSJohn Marino DATA( "cub", 1 ),
17803468e90cSJohn Marino DATA( "cud", 1 ),
17813468e90cSJohn Marino DATA( "cuf", 1 ),
17823468e90cSJohn Marino DATA( "cup", 2 ),
17833468e90cSJohn Marino DATA( "cuu", 1 ),
17843468e90cSJohn Marino DATA( "cvr", 1 ),
17853468e90cSJohn Marino DATA( "cwin", 5 ),
17863468e90cSJohn Marino DATA( "dch", 1 ),
17873468e90cSJohn Marino DATA( "defc", 3 ),
17883468e90cSJohn Marino DATA( "dial", 1 ),
17893468e90cSJohn Marino DATA( "dispc", 1 ),
17903468e90cSJohn Marino DATA( "dl", 1 ),
17913468e90cSJohn Marino DATA( "ech", 1 ),
17923468e90cSJohn Marino DATA( "getm", 1 ),
17933468e90cSJohn Marino DATA( "hpa", 1 ),
17943468e90cSJohn Marino DATA( "ich", 1 ),
17953468e90cSJohn Marino DATA( "il", 1 ),
17963468e90cSJohn Marino DATA( "indn", 1 ),
17973468e90cSJohn Marino DATA( "initc", 4 ),
17983468e90cSJohn Marino DATA( "initp", 7 ),
17993468e90cSJohn Marino DATA( "lpi", 1 ),
18003468e90cSJohn Marino DATA( "mc5p", 1 ),
18013468e90cSJohn Marino DATA( "mrcup", 2 ),
18023468e90cSJohn Marino DATA( "mvpa", 1 ),
18033468e90cSJohn Marino DATA( "pfkey", 2 ),
18043468e90cSJohn Marino DATA( "pfloc", 2 ),
18053468e90cSJohn Marino DATA( "pfx", 2 ),
18063468e90cSJohn Marino DATA( "pfxl", 3 ),
18073468e90cSJohn Marino DATA( "pln", 2 ),
18083468e90cSJohn Marino DATA( "qdial", 1 ),
18093468e90cSJohn Marino DATA( "rcsd", 1 ),
18103468e90cSJohn Marino DATA( "rep", 2 ),
18113468e90cSJohn Marino DATA( "rin", 1 ),
18123468e90cSJohn Marino DATA( "sclk", 3 ),
18133468e90cSJohn Marino DATA( "scp", 1 ),
18143468e90cSJohn Marino DATA( "scs", 1 ),
18153468e90cSJohn Marino DATA( "scsd", 2 ),
18163468e90cSJohn Marino DATA( "setab", 1 ),
18173468e90cSJohn Marino DATA( "setaf", 1 ),
18183468e90cSJohn Marino DATA( "setb", 1 ),
18193468e90cSJohn Marino DATA( "setcolor", 1 ),
18203468e90cSJohn Marino DATA( "setf", 1 ),
18213468e90cSJohn Marino DATA( "sgr", 9 ),
18223468e90cSJohn Marino DATA( "sgr1", 6 ),
18233468e90cSJohn Marino DATA( "slength", 1 ),
18243468e90cSJohn Marino DATA( "slines", 1 ),
18253468e90cSJohn Marino DATA( "smgbp", 1 ), /* 2 if smgtp is not given */
18263468e90cSJohn Marino DATA( "smglp", 1 ),
18273468e90cSJohn Marino DATA( "smglr", 2 ),
18283468e90cSJohn Marino DATA( "smgrp", 1 ),
18293468e90cSJohn Marino DATA( "smgtb", 2 ),
18303468e90cSJohn Marino DATA( "smgtp", 1 ),
18313468e90cSJohn Marino DATA( "tsl", 1 ),
18323468e90cSJohn Marino DATA( "u6", -1 ),
18333468e90cSJohn Marino DATA( "vpa", 1 ),
18343468e90cSJohn Marino DATA( "wind", 4 ),
18353468e90cSJohn Marino DATA( "wingo", 1 ),
18365f4613f2SJohn Marino };
18375f4613f2SJohn Marino /* *INDENT-ON* */
18385f4613f2SJohn Marino
18393468e90cSJohn Marino #undef DATA
18403468e90cSJohn Marino
18415f4613f2SJohn Marino unsigned n;
18425f4613f2SJohn Marino int result = 0; /* function-keys, etc., use none */
18435f4613f2SJohn Marino
18445f4613f2SJohn Marino for (n = 0; n < SIZEOF(table); n++) {
18455f4613f2SJohn Marino if (!strcmp(name, table[n].name)) {
18465f4613f2SJohn Marino result = table[n].count;
18475f4613f2SJohn Marino break;
18485f4613f2SJohn Marino }
18495f4613f2SJohn Marino }
18505f4613f2SJohn Marino
18515f4613f2SJohn Marino return result;
18525f4613f2SJohn Marino }
18535f4613f2SJohn Marino
18545f4613f2SJohn Marino /*
1855*32bb5217SDaniel Fojt * Check for user-capabilities that happen to be used in ncurses' terminal
1856*32bb5217SDaniel Fojt * database.
1857*32bb5217SDaniel Fojt */
1858*32bb5217SDaniel Fojt #if NCURSES_XNAMES
1859*32bb5217SDaniel Fojt static struct user_table_entry const *
lookup_user_capability(const char * name)1860*32bb5217SDaniel Fojt lookup_user_capability(const char *name)
1861*32bb5217SDaniel Fojt {
1862*32bb5217SDaniel Fojt struct user_table_entry const *result = 0;
1863*32bb5217SDaniel Fojt if (*name != 'k') {
1864*32bb5217SDaniel Fojt result = _nc_find_user_entry(name);
1865*32bb5217SDaniel Fojt }
1866*32bb5217SDaniel Fojt return result;
1867*32bb5217SDaniel Fojt }
1868*32bb5217SDaniel Fojt #endif
1869*32bb5217SDaniel Fojt
1870*32bb5217SDaniel Fojt /*
1871*32bb5217SDaniel Fojt * If a given name is likely to be a user-capability, return the number of
1872*32bb5217SDaniel Fojt * parameters it would be used with. If not, return -1.
1873*32bb5217SDaniel Fojt *
1874*32bb5217SDaniel Fojt * ncurses assumes that u6 could be used for getting the cursor-position, but
1875*32bb5217SDaniel Fojt * that is not implemented. Make a special case for that, to quiet needless
1876*32bb5217SDaniel Fojt * warnings.
1877*32bb5217SDaniel Fojt *
1878*32bb5217SDaniel Fojt * The other string-capability extensions (see terminfo.src) which could have
1879*32bb5217SDaniel Fojt * parameters such as "Ss", "%u", are not used by ncurses. But we check those
1880*32bb5217SDaniel Fojt * anyway, to validate the terminfo database.
1881*32bb5217SDaniel Fojt */
1882*32bb5217SDaniel Fojt static int
is_user_capability(const char * name)1883*32bb5217SDaniel Fojt is_user_capability(const char *name)
1884*32bb5217SDaniel Fojt {
1885*32bb5217SDaniel Fojt int result = -1;
1886*32bb5217SDaniel Fojt if (name[0] == 'u' &&
1887*32bb5217SDaniel Fojt (name[1] >= '0' && name[1] <= '9') &&
1888*32bb5217SDaniel Fojt name[2] == '\0') {
1889*32bb5217SDaniel Fojt result = (name[1] == '6') ? 2 : 0;
1890*32bb5217SDaniel Fojt }
1891*32bb5217SDaniel Fojt #if NCURSES_XNAMES
1892*32bb5217SDaniel Fojt else if (using_extensions) {
1893*32bb5217SDaniel Fojt struct user_table_entry const *p = lookup_user_capability(name);
1894*32bb5217SDaniel Fojt if (p != 0) {
1895*32bb5217SDaniel Fojt result = (int) p->ute_argc;
1896*32bb5217SDaniel Fojt }
1897*32bb5217SDaniel Fojt }
1898*32bb5217SDaniel Fojt #endif
1899*32bb5217SDaniel Fojt return result;
1900*32bb5217SDaniel Fojt }
1901*32bb5217SDaniel Fojt
1902*32bb5217SDaniel Fojt /*
19035f4613f2SJohn Marino * Make a quick sanity check for the parameters which are used in the given
19045f4613f2SJohn Marino * strings. If there are no "%p" tokens, then there should be no other "%"
19055f4613f2SJohn Marino * markers.
19065f4613f2SJohn Marino */
19075f4613f2SJohn Marino static void
check_params(TERMTYPE2 * tp,const char * name,char * value,int extended)1908*32bb5217SDaniel Fojt check_params(TERMTYPE2 *tp, const char *name, char *value, int extended)
19095f4613f2SJohn Marino {
19105f4613f2SJohn Marino int expected = expected_params(name);
19115f4613f2SJohn Marino int actual = 0;
19125f4613f2SJohn Marino int n;
19133468e90cSJohn Marino bool params[NUM_PARM];
19145f4613f2SJohn Marino char *s = value;
19155f4613f2SJohn Marino
19165f4613f2SJohn Marino #ifdef set_top_margin_parm
19175f4613f2SJohn Marino if (!strcmp(name, "smgbp")
19185f4613f2SJohn Marino && set_top_margin_parm == 0)
19195f4613f2SJohn Marino expected = 2;
19205f4613f2SJohn Marino #endif
19215f4613f2SJohn Marino
19223468e90cSJohn Marino for (n = 0; n < NUM_PARM; n++)
19235f4613f2SJohn Marino params[n] = FALSE;
19245f4613f2SJohn Marino
19255f4613f2SJohn Marino while (*s != 0) {
19265f4613f2SJohn Marino if (*s == '%') {
19275f4613f2SJohn Marino if (*++s == '\0') {
19285f4613f2SJohn Marino _nc_warning("expected character after %% in %s", name);
19295f4613f2SJohn Marino break;
19305f4613f2SJohn Marino } else if (*s == 'p') {
19315f4613f2SJohn Marino if (*++s == '\0' || !isdigit((int) *s)) {
19325f4613f2SJohn Marino _nc_warning("expected digit after %%p in %s", name);
19335f4613f2SJohn Marino return;
19345f4613f2SJohn Marino } else {
19355f4613f2SJohn Marino n = (*s - '0');
19365f4613f2SJohn Marino if (n > actual)
19375f4613f2SJohn Marino actual = n;
19385f4613f2SJohn Marino params[n] = TRUE;
19395f4613f2SJohn Marino }
19405f4613f2SJohn Marino }
19415f4613f2SJohn Marino }
19425f4613f2SJohn Marino s++;
19435f4613f2SJohn Marino }
19445f4613f2SJohn Marino
1945*32bb5217SDaniel Fojt #if NCURSES_XNAMES
1946*32bb5217SDaniel Fojt if (extended) {
1947*32bb5217SDaniel Fojt int check = is_user_capability(name);
1948*32bb5217SDaniel Fojt if (check != actual && (check >= 0 && actual >= 0)) {
1949*32bb5217SDaniel Fojt _nc_warning("extended %s capability has %d parameters, expected %d",
1950*32bb5217SDaniel Fojt name, actual, check);
1951*32bb5217SDaniel Fojt } else if (debug_level > 1) {
1952*32bb5217SDaniel Fojt _nc_warning("extended %s capability has %d parameters, as expected",
1953*32bb5217SDaniel Fojt name, actual);
1954*32bb5217SDaniel Fojt }
1955*32bb5217SDaniel Fojt expected = actual;
1956*32bb5217SDaniel Fojt }
1957*32bb5217SDaniel Fojt #else
1958*32bb5217SDaniel Fojt (void) extended;
1959*32bb5217SDaniel Fojt #endif
1960*32bb5217SDaniel Fojt
19615f4613f2SJohn Marino if (params[0]) {
19625f4613f2SJohn Marino _nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name);
19635f4613f2SJohn Marino }
19645f4613f2SJohn Marino if (value == set_attributes || expected < 0) {
19655f4613f2SJohn Marino ;
19665f4613f2SJohn Marino } else if (expected != actual) {
19675f4613f2SJohn Marino _nc_warning("%s uses %d parameters, expected %d", name,
19685f4613f2SJohn Marino actual, expected);
19695f4613f2SJohn Marino for (n = 1; n < actual; n++) {
19705f4613f2SJohn Marino if (!params[n])
19715f4613f2SJohn Marino _nc_warning("%s omits parameter %d", name, n);
19725f4613f2SJohn Marino }
19735f4613f2SJohn Marino }
1974*32bb5217SDaniel Fojt
1975*32bb5217SDaniel Fojt /*
1976*32bb5217SDaniel Fojt * Counting "%p" markers does not account for termcap expressions which
1977*32bb5217SDaniel Fojt * may not have been fully translated. Also, tparm does its own analysis.
1978*32bb5217SDaniel Fojt * Report differences here.
1979*32bb5217SDaniel Fojt */
1980*32bb5217SDaniel Fojt if (actual >= 0) {
1981*32bb5217SDaniel Fojt char *p_is_s[NUM_PARM];
1982*32bb5217SDaniel Fojt int popcount;
1983*32bb5217SDaniel Fojt int analyzed = _nc_tparm_analyze(value, p_is_s, &popcount);
1984*32bb5217SDaniel Fojt if (analyzed < popcount) {
1985*32bb5217SDaniel Fojt analyzed = popcount;
1986*32bb5217SDaniel Fojt }
1987*32bb5217SDaniel Fojt if (actual != analyzed && expected != analyzed) {
1988*32bb5217SDaniel Fojt #if NCURSES_XNAMES
1989*32bb5217SDaniel Fojt int user_cap = is_user_capability(name);
1990*32bb5217SDaniel Fojt if ((user_cap == analyzed) && using_extensions) {
1991*32bb5217SDaniel Fojt ; /* ignore */
1992*32bb5217SDaniel Fojt } else if (user_cap >= 0) {
1993*32bb5217SDaniel Fojt _nc_warning("tparm will use %d parameters for %s, expected %d",
1994*32bb5217SDaniel Fojt analyzed, name, user_cap);
1995*32bb5217SDaniel Fojt } else
1996*32bb5217SDaniel Fojt #endif
1997*32bb5217SDaniel Fojt {
1998*32bb5217SDaniel Fojt _nc_warning("tparm analyzed %d parameters for %s, expected %d",
1999*32bb5217SDaniel Fojt analyzed, name, actual);
2000*32bb5217SDaniel Fojt }
2001*32bb5217SDaniel Fojt }
2002*32bb5217SDaniel Fojt }
2003*32bb5217SDaniel Fojt }
2004*32bb5217SDaniel Fojt
2005*32bb5217SDaniel Fojt static bool
line_capability(const char * name)2006*32bb5217SDaniel Fojt line_capability(const char *name)
2007*32bb5217SDaniel Fojt {
2008*32bb5217SDaniel Fojt bool result = FALSE;
2009*32bb5217SDaniel Fojt static const char *table[] =
2010*32bb5217SDaniel Fojt {
2011*32bb5217SDaniel Fojt "csr", /* change_scroll_region */
2012*32bb5217SDaniel Fojt "clear", /* clear_screen */
2013*32bb5217SDaniel Fojt "ed", /* clr_eos */
2014*32bb5217SDaniel Fojt "cwin", /* create_window */
2015*32bb5217SDaniel Fojt "cup", /* cursor_address */
2016*32bb5217SDaniel Fojt "cud1", /* cursor_down */
2017*32bb5217SDaniel Fojt "home", /* cursor_home */
2018*32bb5217SDaniel Fojt "mrcup", /* cursor_mem_address */
2019*32bb5217SDaniel Fojt "ll", /* cursor_to_ll */
2020*32bb5217SDaniel Fojt "cuu1", /* cursor_up */
2021*32bb5217SDaniel Fojt "dl1", /* delete_line */
2022*32bb5217SDaniel Fojt "hd", /* down_half_line */
2023*32bb5217SDaniel Fojt "flash", /* flash_screen */
2024*32bb5217SDaniel Fojt "ff", /* form_feed */
2025*32bb5217SDaniel Fojt "il1", /* insert_line */
2026*32bb5217SDaniel Fojt "nel", /* newline */
2027*32bb5217SDaniel Fojt "dl", /* parm_delete_line */
2028*32bb5217SDaniel Fojt "cud", /* parm_down_cursor */
2029*32bb5217SDaniel Fojt "indn", /* parm_index */
2030*32bb5217SDaniel Fojt "il", /* parm_insert_line */
2031*32bb5217SDaniel Fojt "rin", /* parm_rindex */
2032*32bb5217SDaniel Fojt "cuu", /* parm_up_cursor */
2033*32bb5217SDaniel Fojt "mc0", /* print_screen */
2034*32bb5217SDaniel Fojt "vpa", /* row_address */
2035*32bb5217SDaniel Fojt "ind", /* scroll_forward */
2036*32bb5217SDaniel Fojt "ri", /* scroll_reverse */
2037*32bb5217SDaniel Fojt "hu", /* up_half_line */
2038*32bb5217SDaniel Fojt };
2039*32bb5217SDaniel Fojt size_t n;
2040*32bb5217SDaniel Fojt for (n = 0; n < SIZEOF(table); ++n) {
2041*32bb5217SDaniel Fojt if (!strcmp(name, table[n])) {
2042*32bb5217SDaniel Fojt result = TRUE;
2043*32bb5217SDaniel Fojt break;
2044*32bb5217SDaniel Fojt }
2045*32bb5217SDaniel Fojt }
2046*32bb5217SDaniel Fojt return result;
2047*32bb5217SDaniel Fojt }
2048*32bb5217SDaniel Fojt
2049*32bb5217SDaniel Fojt /*
2050*32bb5217SDaniel Fojt * Check for DEC VT100 private mode for reverse video.
2051*32bb5217SDaniel Fojt */
2052*32bb5217SDaniel Fojt static const char *
skip_DECSCNM(const char * value,int * flag)2053*32bb5217SDaniel Fojt skip_DECSCNM(const char *value, int *flag)
2054*32bb5217SDaniel Fojt {
2055*32bb5217SDaniel Fojt *flag = -1;
2056*32bb5217SDaniel Fojt if (value != 0) {
2057*32bb5217SDaniel Fojt int skip = csi_length(value);
2058*32bb5217SDaniel Fojt if (skip > 0 &&
2059*32bb5217SDaniel Fojt value[skip++] == '?' &&
2060*32bb5217SDaniel Fojt value[skip++] == '5') {
2061*32bb5217SDaniel Fojt if (value[skip] == 'h') {
2062*32bb5217SDaniel Fojt *flag = 1;
2063*32bb5217SDaniel Fojt } else if (value[skip] == 'l') {
2064*32bb5217SDaniel Fojt *flag = 0;
2065*32bb5217SDaniel Fojt }
2066*32bb5217SDaniel Fojt value += skip + 1;
2067*32bb5217SDaniel Fojt }
2068*32bb5217SDaniel Fojt }
2069*32bb5217SDaniel Fojt return value;
2070*32bb5217SDaniel Fojt }
2071*32bb5217SDaniel Fojt
2072*32bb5217SDaniel Fojt static void
check_delays(TERMTYPE2 * tp,const char * name,const char * value)2073*32bb5217SDaniel Fojt check_delays(TERMTYPE2 *tp, const char *name, const char *value)
2074*32bb5217SDaniel Fojt {
2075*32bb5217SDaniel Fojt const char *p, *q;
2076*32bb5217SDaniel Fojt const char *first = 0;
2077*32bb5217SDaniel Fojt const char *last = 0;
2078*32bb5217SDaniel Fojt
2079*32bb5217SDaniel Fojt for (p = value; *p != '\0'; ++p) {
2080*32bb5217SDaniel Fojt if (p[0] == '$' && p[1] == '<') {
2081*32bb5217SDaniel Fojt const char *base = p + 2;
2082*32bb5217SDaniel Fojt const char *mark = 0;
2083*32bb5217SDaniel Fojt bool maybe = TRUE;
2084*32bb5217SDaniel Fojt bool mixed = FALSE;
2085*32bb5217SDaniel Fojt int proportional = 0;
2086*32bb5217SDaniel Fojt int mandatory = 0;
2087*32bb5217SDaniel Fojt
2088*32bb5217SDaniel Fojt first = p;
2089*32bb5217SDaniel Fojt
2090*32bb5217SDaniel Fojt for (q = base; *q != '\0'; ++q) {
2091*32bb5217SDaniel Fojt if (*q == '>') {
2092*32bb5217SDaniel Fojt if (mark == 0)
2093*32bb5217SDaniel Fojt mark = q;
2094*32bb5217SDaniel Fojt break;
2095*32bb5217SDaniel Fojt } else if (*q == '*' || *q == '/') {
2096*32bb5217SDaniel Fojt if (*q == '*')
2097*32bb5217SDaniel Fojt ++proportional;
2098*32bb5217SDaniel Fojt if (*q == '/')
2099*32bb5217SDaniel Fojt ++mandatory;
2100*32bb5217SDaniel Fojt if (mark == 0)
2101*32bb5217SDaniel Fojt mark = q;
2102*32bb5217SDaniel Fojt } else if (!(isalnum(UChar(*q)) || strchr("+-.", *q) != 0)) {
2103*32bb5217SDaniel Fojt maybe = FALSE;
2104*32bb5217SDaniel Fojt break;
2105*32bb5217SDaniel Fojt } else if (proportional || mandatory) {
2106*32bb5217SDaniel Fojt mixed = TRUE;
2107*32bb5217SDaniel Fojt }
2108*32bb5217SDaniel Fojt }
2109*32bb5217SDaniel Fojt last = *q ? (q + 1) : q;
2110*32bb5217SDaniel Fojt if (*q == '\0') {
2111*32bb5217SDaniel Fojt maybe = FALSE; /* just an isolated "$<" */
2112*32bb5217SDaniel Fojt } else if (maybe) {
2113*32bb5217SDaniel Fojt float check_f;
2114*32bb5217SDaniel Fojt char check_c;
2115*32bb5217SDaniel Fojt int rc = sscanf(base, "%f%c", &check_f, &check_c);
2116*32bb5217SDaniel Fojt if ((rc != 2) || (check_c != *mark) || mixed) {
2117*32bb5217SDaniel Fojt _nc_warning("syntax error in %s delay '%.*s'", name,
2118*32bb5217SDaniel Fojt (int) (q - base), base);
2119*32bb5217SDaniel Fojt } else if (*name == 'k') {
2120*32bb5217SDaniel Fojt _nc_warning("function-key %s has delay", name);
2121*32bb5217SDaniel Fojt } else if (proportional && !line_capability(name)) {
2122*32bb5217SDaniel Fojt _nc_warning("non-line capability using proportional delay: %s", name);
2123*32bb5217SDaniel Fojt } else if (!xon_xoff &&
2124*32bb5217SDaniel Fojt !mandatory &&
2125*32bb5217SDaniel Fojt strchr(_nc_first_name(tp->term_names), '+') == 0) {
2126*32bb5217SDaniel Fojt _nc_warning("%s in %s is used since no xon/xoff",
2127*32bb5217SDaniel Fojt (proportional
2128*32bb5217SDaniel Fojt ? "proportional delay"
2129*32bb5217SDaniel Fojt : "delay"),
2130*32bb5217SDaniel Fojt name);
2131*32bb5217SDaniel Fojt }
2132*32bb5217SDaniel Fojt } else {
2133*32bb5217SDaniel Fojt p = q - 1; /* restart scan */
2134*32bb5217SDaniel Fojt }
2135*32bb5217SDaniel Fojt }
2136*32bb5217SDaniel Fojt }
2137*32bb5217SDaniel Fojt
2138*32bb5217SDaniel Fojt if (!strcmp(name, "flash") ||
2139*32bb5217SDaniel Fojt !strcmp(name, "beep")) {
2140*32bb5217SDaniel Fojt
2141*32bb5217SDaniel Fojt if (first != 0) {
2142*32bb5217SDaniel Fojt if (first == value || *last == 0) {
2143*32bb5217SDaniel Fojt /*
2144*32bb5217SDaniel Fojt * Delay is on one end or the other.
2145*32bb5217SDaniel Fojt */
2146*32bb5217SDaniel Fojt _nc_warning("expected delay embedded within %s", name);
2147*32bb5217SDaniel Fojt }
2148*32bb5217SDaniel Fojt } else {
2149*32bb5217SDaniel Fojt int flag;
2150*32bb5217SDaniel Fojt
2151*32bb5217SDaniel Fojt /*
2152*32bb5217SDaniel Fojt * Check for missing delay when using VT100 reverse-video.
2153*32bb5217SDaniel Fojt * A real VT100 might not need this, but terminal emulators do.
2154*32bb5217SDaniel Fojt */
2155*32bb5217SDaniel Fojt if ((p = skip_DECSCNM(value, &flag)) != 0 &&
2156*32bb5217SDaniel Fojt flag > 0 &&
2157*32bb5217SDaniel Fojt (q = skip_DECSCNM(p, &flag)) != 0 &&
2158*32bb5217SDaniel Fojt flag == 0) {
2159*32bb5217SDaniel Fojt _nc_warning("expected a delay in %s", name);
2160*32bb5217SDaniel Fojt }
2161*32bb5217SDaniel Fojt }
2162*32bb5217SDaniel Fojt }
21635f4613f2SJohn Marino }
21645f4613f2SJohn Marino
21655f4613f2SJohn Marino static char *
check_1_infotocap(const char * name,NCURSES_CONST char * value,int count)21663468e90cSJohn Marino check_1_infotocap(const char *name, NCURSES_CONST char *value, int count)
21673468e90cSJohn Marino {
21683468e90cSJohn Marino int k;
21693468e90cSJohn Marino int ignored;
21703468e90cSJohn Marino long numbers[1 + NUM_PARM];
21713468e90cSJohn Marino char *strings[1 + NUM_PARM];
21723468e90cSJohn Marino char *p_is_s[NUM_PARM];
21733468e90cSJohn Marino char *result;
21743468e90cSJohn Marino char blob[NUM_PARM * 10];
21753468e90cSJohn Marino char *next = blob;
21763468e90cSJohn Marino
21773468e90cSJohn Marino *next++ = '\0';
21783468e90cSJohn Marino for (k = 1; k <= NUM_PARM; k++) {
21793468e90cSJohn Marino numbers[k] = count;
2180*32bb5217SDaniel Fojt _nc_SPRINTF(next,
2181*32bb5217SDaniel Fojt _nc_SLIMIT(sizeof(blob) - (size_t) (next - blob))
2182*32bb5217SDaniel Fojt "XYZ%d", count);
21833468e90cSJohn Marino strings[k] = next;
21843468e90cSJohn Marino next += strlen(next) + 1;
21853468e90cSJohn Marino }
21863468e90cSJohn Marino
21873468e90cSJohn Marino switch (tparm_type(name)) {
21883468e90cSJohn Marino case Num_Str:
21893468e90cSJohn Marino result = TPARM_2(value, numbers[1], strings[2]);
21903468e90cSJohn Marino break;
21913468e90cSJohn Marino case Num_Str_Str:
21923468e90cSJohn Marino result = TPARM_3(value, numbers[1], strings[2], strings[3]);
21933468e90cSJohn Marino break;
21943468e90cSJohn Marino case Numbers:
21953468e90cSJohn Marino default:
21963468e90cSJohn Marino (void) _nc_tparm_analyze(value, p_is_s, &ignored);
21973468e90cSJohn Marino #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n])
21983468e90cSJohn Marino result = TPARM_9(value,
21993468e90cSJohn Marino myParam(1),
22003468e90cSJohn Marino myParam(2),
22013468e90cSJohn Marino myParam(3),
22023468e90cSJohn Marino myParam(4),
22033468e90cSJohn Marino myParam(5),
22043468e90cSJohn Marino myParam(6),
22053468e90cSJohn Marino myParam(7),
22063468e90cSJohn Marino myParam(8),
22073468e90cSJohn Marino myParam(9));
22083468e90cSJohn Marino break;
22093468e90cSJohn Marino }
2210*32bb5217SDaniel Fojt return strdup(result);
22113468e90cSJohn Marino }
22123468e90cSJohn Marino
22133468e90cSJohn Marino #define IsDelay(ch) ((ch) == '.' || isdigit(UChar(ch)))
22143468e90cSJohn Marino
22153468e90cSJohn Marino static const char *
parse_delay_value(const char * src,double * delays,int * always)22163468e90cSJohn Marino parse_delay_value(const char *src, double *delays, int *always)
22173468e90cSJohn Marino {
22183468e90cSJohn Marino int star = 0;
22193468e90cSJohn Marino
22203468e90cSJohn Marino *delays = 0.0;
22213468e90cSJohn Marino if (always)
22223468e90cSJohn Marino *always = 0;
22233468e90cSJohn Marino
22243468e90cSJohn Marino while (isdigit(UChar(*src))) {
22253468e90cSJohn Marino (*delays) = (*delays) * 10 + (*src++ - '0');
22263468e90cSJohn Marino }
22273468e90cSJohn Marino if (*src == '.') {
22283468e90cSJohn Marino int gotdot = 1;
22293468e90cSJohn Marino
22303468e90cSJohn Marino ++src;
22313468e90cSJohn Marino while (isdigit(UChar(*src))) {
22323468e90cSJohn Marino gotdot *= 10;
22333468e90cSJohn Marino (*delays) += (*src++ - '0') / gotdot;
22343468e90cSJohn Marino }
22353468e90cSJohn Marino }
22363468e90cSJohn Marino while (*src == '*' || *src == '/') {
22373468e90cSJohn Marino if (always == 0 && *src == '/')
22383468e90cSJohn Marino break;
22393468e90cSJohn Marino if (*src++ == '*') {
22403468e90cSJohn Marino star = 1;
22413468e90cSJohn Marino } else {
22423468e90cSJohn Marino *always = 1;
22433468e90cSJohn Marino }
22443468e90cSJohn Marino }
22453468e90cSJohn Marino if (star)
22463468e90cSJohn Marino *delays = -(*delays);
22473468e90cSJohn Marino return src;
22483468e90cSJohn Marino }
22493468e90cSJohn Marino
22503468e90cSJohn Marino static const char *
parse_ti_delay(const char * ti,double * delays)22513468e90cSJohn Marino parse_ti_delay(const char *ti, double *delays)
22523468e90cSJohn Marino {
22533468e90cSJohn Marino *delays = 0.0;
22543468e90cSJohn Marino while (*ti != '\0') {
22553468e90cSJohn Marino if (*ti == '\\') {
22563468e90cSJohn Marino ++ti;
22573468e90cSJohn Marino }
22583468e90cSJohn Marino if (ti[0] == '$'
22593468e90cSJohn Marino && ti[1] == '<'
22603468e90cSJohn Marino && IsDelay(UChar(ti[2]))) {
22613468e90cSJohn Marino int ignored;
22623468e90cSJohn Marino const char *last = parse_delay_value(ti + 2, delays, &ignored);
22633468e90cSJohn Marino if (*last == '>') {
22643468e90cSJohn Marino ti = last;
22653468e90cSJohn Marino }
22663468e90cSJohn Marino } else {
22673468e90cSJohn Marino ++ti;
22683468e90cSJohn Marino }
22693468e90cSJohn Marino }
22703468e90cSJohn Marino return ti;
22713468e90cSJohn Marino }
22723468e90cSJohn Marino
22733468e90cSJohn Marino static const char *
parse_tc_delay(const char * tc,double * delays)22743468e90cSJohn Marino parse_tc_delay(const char *tc, double *delays)
22753468e90cSJohn Marino {
22763468e90cSJohn Marino return parse_delay_value(tc, delays, (int *) 0);
22773468e90cSJohn Marino }
22783468e90cSJohn Marino
22793468e90cSJohn Marino /*
22803468e90cSJohn Marino * Compare terminfo- and termcap-strings, factoring out delays.
22813468e90cSJohn Marino */
22823468e90cSJohn Marino static bool
same_ti_tc(const char * ti,const char * tc,bool * embedded)22833468e90cSJohn Marino same_ti_tc(const char *ti, const char *tc, bool * embedded)
22843468e90cSJohn Marino {
22853468e90cSJohn Marino bool same = TRUE;
22863468e90cSJohn Marino double ti_delay = 0.0;
22873468e90cSJohn Marino double tc_delay = 0.0;
22883468e90cSJohn Marino const char *ti_last;
22893468e90cSJohn Marino
22903468e90cSJohn Marino *embedded = FALSE;
22913468e90cSJohn Marino ti_last = parse_ti_delay(ti, &ti_delay);
22923468e90cSJohn Marino tc = parse_tc_delay(tc, &tc_delay);
22933468e90cSJohn Marino
22943468e90cSJohn Marino while ((ti < ti_last) && *tc) {
22953468e90cSJohn Marino if (*ti == '\\' && ispunct(UChar(ti[1]))) {
22963468e90cSJohn Marino ++ti;
22973468e90cSJohn Marino if ((*ti == '^') && !strncmp(tc, "\\136", 4)) {
22983468e90cSJohn Marino ti += 1;
22993468e90cSJohn Marino tc += 4;
23003468e90cSJohn Marino continue;
23013468e90cSJohn Marino }
23023468e90cSJohn Marino } else if (ti[0] == '$' && ti[1] == '<') {
23033468e90cSJohn Marino double no_delay;
23043468e90cSJohn Marino const char *ss = parse_ti_delay(ti, &no_delay);
23053468e90cSJohn Marino if (ss != ti) {
23063468e90cSJohn Marino *embedded = TRUE;
23073468e90cSJohn Marino ti = ss;
23083468e90cSJohn Marino continue;
23093468e90cSJohn Marino }
23103468e90cSJohn Marino }
23113468e90cSJohn Marino if (*tc == '\\' && ispunct(UChar(tc[1]))) {
23123468e90cSJohn Marino ++tc;
23133468e90cSJohn Marino }
23143468e90cSJohn Marino if (*ti++ != *tc++) {
23153468e90cSJohn Marino same = FALSE;
23163468e90cSJohn Marino break;
23173468e90cSJohn Marino }
23183468e90cSJohn Marino }
23193468e90cSJohn Marino
23203468e90cSJohn Marino if (*embedded) {
23213468e90cSJohn Marino if (same) {
23223468e90cSJohn Marino same = FALSE;
23233468e90cSJohn Marino } else {
23243468e90cSJohn Marino *embedded = FALSE; /* report only one problem */
23253468e90cSJohn Marino }
23263468e90cSJohn Marino }
23273468e90cSJohn Marino
23283468e90cSJohn Marino return same;
23293468e90cSJohn Marino }
23303468e90cSJohn Marino
23313468e90cSJohn Marino /*
23323468e90cSJohn Marino * Check terminfo to termcap translation.
23333468e90cSJohn Marino */
23343468e90cSJohn Marino static void
check_infotocap(TERMTYPE2 * tp,int i,const char * value)2335*32bb5217SDaniel Fojt check_infotocap(TERMTYPE2 *tp, int i, const char *value)
23363468e90cSJohn Marino {
23373468e90cSJohn Marino const char *name = ExtStrname(tp, i, strnames);
2338*32bb5217SDaniel Fojt int params = ((i < (int) SIZEOF(parametrized))
23393468e90cSJohn Marino ? parametrized[i]
23403468e90cSJohn Marino : ((*value == 'k')
23413468e90cSJohn Marino ? 0
23423468e90cSJohn Marino : has_params(value)));
23433468e90cSJohn Marino int to_char = 0;
23443468e90cSJohn Marino char *ti_value;
23453468e90cSJohn Marino char *tc_value;
23463468e90cSJohn Marino bool embedded;
23473468e90cSJohn Marino
2348*32bb5217SDaniel Fojt assert(SIZEOF(parametrized) == STRCOUNT);
23493468e90cSJohn Marino if ((ti_value = _nc_tic_expand(value, TRUE, to_char)) == ABSENT_STRING) {
23503468e90cSJohn Marino _nc_warning("tic-expansion of %s failed", name);
23513468e90cSJohn Marino } else if ((tc_value = _nc_infotocap(name, ti_value, params)) == ABSENT_STRING) {
23523468e90cSJohn Marino _nc_warning("tic-conversion of %s failed", name);
23533468e90cSJohn Marino } else if (params > 0) {
23543468e90cSJohn Marino int limit = 5;
23553468e90cSJohn Marino int count;
23563468e90cSJohn Marino bool first = TRUE;
23573468e90cSJohn Marino
23583468e90cSJohn Marino if (!strcmp(name, "setf")
23593468e90cSJohn Marino || !strcmp(name, "setb")
23603468e90cSJohn Marino || !strcmp(name, "setaf")
23613468e90cSJohn Marino || !strcmp(name, "setab")) {
2362*32bb5217SDaniel Fojt if ((limit = max_colors) > 16)
2363*32bb5217SDaniel Fojt limit = 16;
23643468e90cSJohn Marino }
23653468e90cSJohn Marino for (count = 0; count < limit; ++count) {
23663468e90cSJohn Marino char *ti_check = check_1_infotocap(name, ti_value, count);
23673468e90cSJohn Marino char *tc_check = check_1_infotocap(name, tc_value, count);
23683468e90cSJohn Marino
23693468e90cSJohn Marino if (strcmp(ti_check, tc_check)) {
23703468e90cSJohn Marino if (first) {
23713468e90cSJohn Marino fprintf(stderr, "check_infotocap(%s)\n", name);
23723468e90cSJohn Marino fprintf(stderr, "...ti '%s'\n", ti_value);
23733468e90cSJohn Marino fprintf(stderr, "...tc '%s'\n", tc_value);
23743468e90cSJohn Marino first = FALSE;
23753468e90cSJohn Marino }
23763468e90cSJohn Marino _nc_warning("tparm-conversion of %s(%d) differs between\n\tterminfo %s\n\ttermcap %s",
23773468e90cSJohn Marino name, count, ti_check, tc_check);
23783468e90cSJohn Marino }
2379*32bb5217SDaniel Fojt free(ti_check);
2380*32bb5217SDaniel Fojt free(tc_check);
23813468e90cSJohn Marino }
23823468e90cSJohn Marino } else if (params == 0 && !same_ti_tc(ti_value, tc_value, &embedded)) {
23833468e90cSJohn Marino if (embedded) {
23843468e90cSJohn Marino _nc_warning("termcap equivalent of %s cannot use embedded delay", name);
23853468e90cSJohn Marino } else {
23863468e90cSJohn Marino _nc_warning("tic-conversion of %s changed value\n\tfrom %s\n\tto %s",
23873468e90cSJohn Marino name, ti_value, tc_value);
23883468e90cSJohn Marino }
23893468e90cSJohn Marino }
23903468e90cSJohn Marino }
23913468e90cSJohn Marino
23923468e90cSJohn Marino static char *
skip_delay(char * s)23935f4613f2SJohn Marino skip_delay(char *s)
23945f4613f2SJohn Marino {
23955f4613f2SJohn Marino while (*s == '/' || isdigit(UChar(*s)))
23965f4613f2SJohn Marino ++s;
23975f4613f2SJohn Marino return s;
23985f4613f2SJohn Marino }
23995f4613f2SJohn Marino
24005f4613f2SJohn Marino /*
24015f4613f2SJohn Marino * Skip a delay altogether, e.g., when comparing a simple string to sgr,
24025f4613f2SJohn Marino * the latter may have a worst-case delay on the end.
24035f4613f2SJohn Marino */
24045f4613f2SJohn Marino static char *
ignore_delays(char * s)24055f4613f2SJohn Marino ignore_delays(char *s)
24065f4613f2SJohn Marino {
24075f4613f2SJohn Marino int delaying = 0;
24085f4613f2SJohn Marino
24095f4613f2SJohn Marino do {
24105f4613f2SJohn Marino switch (*s) {
24115f4613f2SJohn Marino case '$':
24125f4613f2SJohn Marino if (delaying == 0)
24135f4613f2SJohn Marino delaying = 1;
24145f4613f2SJohn Marino break;
24155f4613f2SJohn Marino case '<':
24165f4613f2SJohn Marino if (delaying == 1)
24175f4613f2SJohn Marino delaying = 2;
24185f4613f2SJohn Marino break;
24195f4613f2SJohn Marino case '\0':
24205f4613f2SJohn Marino delaying = 0;
24215f4613f2SJohn Marino break;
24225f4613f2SJohn Marino default:
24235f4613f2SJohn Marino if (delaying) {
24245f4613f2SJohn Marino s = skip_delay(s);
24255f4613f2SJohn Marino if (*s == '>')
24265f4613f2SJohn Marino ++s;
24275f4613f2SJohn Marino delaying = 0;
24285f4613f2SJohn Marino }
24295f4613f2SJohn Marino break;
24305f4613f2SJohn Marino }
24315f4613f2SJohn Marino if (delaying)
24325f4613f2SJohn Marino ++s;
24335f4613f2SJohn Marino } while (delaying);
24345f4613f2SJohn Marino return s;
24355f4613f2SJohn Marino }
24365f4613f2SJohn Marino
24373468e90cSJohn Marino #define DATA(name) { #name }
24383468e90cSJohn Marino static const char sgr_names[][11] =
24393468e90cSJohn Marino {
24403468e90cSJohn Marino DATA(none),
24413468e90cSJohn Marino DATA(standout),
24423468e90cSJohn Marino DATA(underline),
24433468e90cSJohn Marino DATA(reverse),
24443468e90cSJohn Marino DATA(blink),
24453468e90cSJohn Marino DATA(dim),
24463468e90cSJohn Marino DATA(bold),
24473468e90cSJohn Marino DATA(invis),
24483468e90cSJohn Marino DATA(protect),
24493468e90cSJohn Marino DATA(altcharset),
24503468e90cSJohn Marino ""
24513468e90cSJohn Marino };
24523468e90cSJohn Marino #undef DATA
24533468e90cSJohn Marino
24545f4613f2SJohn Marino /*
24555f4613f2SJohn Marino * An sgr string may contain several settings other than the one we're
24565f4613f2SJohn Marino * interested in, essentially sgr0 + rmacs + whatever. As long as the
24575f4613f2SJohn Marino * "whatever" is contained in the sgr string, that is close enough for our
24585f4613f2SJohn Marino * sanity check.
24595f4613f2SJohn Marino */
24605f4613f2SJohn Marino static bool
similar_sgr(int num,char * a,char * b)24615f4613f2SJohn Marino similar_sgr(int num, char *a, char *b)
24625f4613f2SJohn Marino {
24635f4613f2SJohn Marino char *base_a = a;
24645f4613f2SJohn Marino char *base_b = b;
24655f4613f2SJohn Marino int delaying = 0;
24665f4613f2SJohn Marino
24675f4613f2SJohn Marino while (*b != 0) {
24685f4613f2SJohn Marino while (*a != *b) {
24695f4613f2SJohn Marino if (*a == 0) {
24703468e90cSJohn Marino if (num < 0) {
24713468e90cSJohn Marino ;
24723468e90cSJohn Marino } else if (b[0] == '$'
24735f4613f2SJohn Marino && b[1] == '<') {
2474*32bb5217SDaniel Fojt _nc_warning("did not find delay %s", _nc_visbuf(b));
24755f4613f2SJohn Marino } else {
24765f4613f2SJohn Marino _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s",
24773468e90cSJohn Marino sgr_names[num], _nc_visbuf2(1, base_a),
24785f4613f2SJohn Marino _nc_visbuf2(2, base_b),
24795f4613f2SJohn Marino _nc_visbuf2(3, b));
24805f4613f2SJohn Marino }
24815f4613f2SJohn Marino return FALSE;
24825f4613f2SJohn Marino } else if (delaying) {
24835f4613f2SJohn Marino a = skip_delay(a);
24845f4613f2SJohn Marino b = skip_delay(b);
24855f4613f2SJohn Marino } else if ((*b == '0' || (*b == ';')) && *a == 'm') {
24865f4613f2SJohn Marino b++;
24875f4613f2SJohn Marino } else {
24885f4613f2SJohn Marino a++;
24895f4613f2SJohn Marino }
24905f4613f2SJohn Marino }
24915f4613f2SJohn Marino switch (*a) {
24925f4613f2SJohn Marino case '$':
24935f4613f2SJohn Marino if (delaying == 0)
24945f4613f2SJohn Marino delaying = 1;
24955f4613f2SJohn Marino break;
24965f4613f2SJohn Marino case '<':
24975f4613f2SJohn Marino if (delaying == 1)
24985f4613f2SJohn Marino delaying = 2;
24995f4613f2SJohn Marino break;
25005f4613f2SJohn Marino default:
25015f4613f2SJohn Marino delaying = 0;
25025f4613f2SJohn Marino break;
25035f4613f2SJohn Marino }
25045f4613f2SJohn Marino a++;
25055f4613f2SJohn Marino b++;
25065f4613f2SJohn Marino }
25075f4613f2SJohn Marino /* ignore delays on the end of the string */
25085f4613f2SJohn Marino a = ignore_delays(a);
25095f4613f2SJohn Marino return ((num != 0) || (*a == 0));
25105f4613f2SJohn Marino }
25115f4613f2SJohn Marino
25125f4613f2SJohn Marino static char *
check_sgr(TERMTYPE2 * tp,char * zero,int num,char * cap,const char * name)2513*32bb5217SDaniel Fojt check_sgr(TERMTYPE2 *tp, char *zero, int num, char *cap, const char *name)
25145f4613f2SJohn Marino {
25155f4613f2SJohn Marino char *test;
25165f4613f2SJohn Marino
25175f4613f2SJohn Marino _nc_tparm_err = 0;
25185f4613f2SJohn Marino test = TPARM_9(set_attributes,
25195f4613f2SJohn Marino num == 1,
25205f4613f2SJohn Marino num == 2,
25215f4613f2SJohn Marino num == 3,
25225f4613f2SJohn Marino num == 4,
25235f4613f2SJohn Marino num == 5,
25245f4613f2SJohn Marino num == 6,
25255f4613f2SJohn Marino num == 7,
25265f4613f2SJohn Marino num == 8,
25275f4613f2SJohn Marino num == 9);
25285f4613f2SJohn Marino if (test != 0) {
25295f4613f2SJohn Marino if (PRESENT(cap)) {
25305f4613f2SJohn Marino if (!similar_sgr(num, test, cap)) {
25315f4613f2SJohn Marino _nc_warning("%s differs from sgr(%d)\n\t%s=%s\n\tsgr(%d)=%s",
25325f4613f2SJohn Marino name, num,
25335f4613f2SJohn Marino name, _nc_visbuf2(1, cap),
25345f4613f2SJohn Marino num, _nc_visbuf2(2, test));
25355f4613f2SJohn Marino }
25365f4613f2SJohn Marino } else if (_nc_capcmp(test, zero)) {
25375f4613f2SJohn Marino _nc_warning("sgr(%d) present, but not %s", num, name);
25385f4613f2SJohn Marino }
25395f4613f2SJohn Marino } else if (PRESENT(cap)) {
25405f4613f2SJohn Marino _nc_warning("sgr(%d) missing, but %s present", num, name);
25415f4613f2SJohn Marino }
25425f4613f2SJohn Marino if (_nc_tparm_err)
25435f4613f2SJohn Marino _nc_warning("stack error in sgr(%d) string", num);
25445f4613f2SJohn Marino return test;
25455f4613f2SJohn Marino }
25465f4613f2SJohn Marino
25475f4613f2SJohn Marino #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)
25485f4613f2SJohn Marino
25495f4613f2SJohn Marino #ifdef TRACE
25505f4613f2SJohn Marino /*
25515f4613f2SJohn Marino * If tic is compiled with TRACE, we'll be able to see the output from the
25525f4613f2SJohn Marino * DEBUG() macro. But since it doesn't use traceon(), it always goes to
25535f4613f2SJohn Marino * the standard error. Use this function to make it simpler to follow the
25545f4613f2SJohn Marino * resulting debug traces.
25555f4613f2SJohn Marino */
25565f4613f2SJohn Marino static void
show_where(unsigned level)25575f4613f2SJohn Marino show_where(unsigned level)
25585f4613f2SJohn Marino {
25595f4613f2SJohn Marino if (_nc_tracing >= DEBUG_LEVEL(level)) {
25603468e90cSJohn Marino char my_name[MAX_NAME_SIZE];
25615f4613f2SJohn Marino _nc_get_type(my_name);
25625f4613f2SJohn Marino _tracef("\"%s\", line %d, '%s'",
25635f4613f2SJohn Marino _nc_get_source(),
25645f4613f2SJohn Marino _nc_curr_line, my_name);
25655f4613f2SJohn Marino }
25665f4613f2SJohn Marino }
25675f4613f2SJohn Marino
25685f4613f2SJohn Marino #else
25695f4613f2SJohn Marino #define show_where(level) /* nothing */
25705f4613f2SJohn Marino #endif
25715f4613f2SJohn Marino
25723468e90cSJohn Marino typedef struct {
25733468e90cSJohn Marino int keycode;
25743468e90cSJohn Marino const char *name;
25753468e90cSJohn Marino const char *value;
25763468e90cSJohn Marino } NAME_VALUE;
25773468e90cSJohn Marino
25783468e90cSJohn Marino static NAME_VALUE *
get_fkey_list(TERMTYPE2 * tp)2579*32bb5217SDaniel Fojt get_fkey_list(TERMTYPE2 *tp)
25803468e90cSJohn Marino {
25813468e90cSJohn Marino NAME_VALUE *result = typeMalloc(NAME_VALUE, NUM_STRINGS(tp) + 1);
25823468e90cSJohn Marino const struct tinfo_fkeys *all_fkeys = _nc_tinfo_fkeys;
25833468e90cSJohn Marino int used = 0;
25843468e90cSJohn Marino unsigned j;
25853468e90cSJohn Marino
25863468e90cSJohn Marino if (result == 0)
25873468e90cSJohn Marino failed("get_fkey_list");
25883468e90cSJohn Marino
25893468e90cSJohn Marino for (j = 0; all_fkeys[j].code; j++) {
25903468e90cSJohn Marino char *a = tp->Strings[all_fkeys[j].offset];
25913468e90cSJohn Marino if (VALID_STRING(a)) {
25923468e90cSJohn Marino result[used].keycode = (int) all_fkeys[j].code;
25933468e90cSJohn Marino result[used].name = strnames[all_fkeys[j].offset];
25943468e90cSJohn Marino result[used].value = a;
25953468e90cSJohn Marino ++used;
25963468e90cSJohn Marino }
25973468e90cSJohn Marino }
25983468e90cSJohn Marino #if NCURSES_XNAMES
25993468e90cSJohn Marino for (j = STRCOUNT; j < NUM_STRINGS(tp); ++j) {
26003468e90cSJohn Marino const char *name = ExtStrname(tp, (int) j, strnames);
26013468e90cSJohn Marino if (*name == 'k') {
26023468e90cSJohn Marino result[used].keycode = -1;
26033468e90cSJohn Marino result[used].name = name;
26043468e90cSJohn Marino result[used].value = tp->Strings[j];
26053468e90cSJohn Marino ++used;
26063468e90cSJohn Marino }
26073468e90cSJohn Marino }
26083468e90cSJohn Marino #endif
26093468e90cSJohn Marino result[used].keycode = 0;
26103468e90cSJohn Marino return result;
26113468e90cSJohn Marino }
26123468e90cSJohn Marino
26133468e90cSJohn Marino static void
show_fkey_name(NAME_VALUE * data)26143468e90cSJohn Marino show_fkey_name(NAME_VALUE * data)
26153468e90cSJohn Marino {
26163468e90cSJohn Marino if (data->keycode > 0) {
26173468e90cSJohn Marino fprintf(stderr, " %s", keyname(data->keycode));
26183468e90cSJohn Marino fprintf(stderr, " (capability \"%s\")", data->name);
26193468e90cSJohn Marino } else {
26203468e90cSJohn Marino fprintf(stderr, " capability \"%s\"", data->name);
26213468e90cSJohn Marino }
26223468e90cSJohn Marino }
26233468e90cSJohn Marino
26243468e90cSJohn Marino /*
26253468e90cSJohn Marino * A terminal entry may contain more than one keycode assigned to a given
26263468e90cSJohn Marino * string (e.g., KEY_END and KEY_LL). But curses will only return one (the
26273468e90cSJohn Marino * last one assigned).
26285f4613f2SJohn Marino */
26295f4613f2SJohn Marino static void
check_conflict(TERMTYPE2 * tp)2630*32bb5217SDaniel Fojt check_conflict(TERMTYPE2 *tp)
26315f4613f2SJohn Marino {
26325f4613f2SJohn Marino bool conflict = FALSE;
26335f4613f2SJohn Marino unsigned j, k;
26345f4613f2SJohn Marino
26355f4613f2SJohn Marino if (!(_nc_syntax == SYN_TERMCAP && capdump)) {
26363468e90cSJohn Marino char *check = calloc((size_t) (NUM_STRINGS(tp) + 1), sizeof(char));
26373468e90cSJohn Marino NAME_VALUE *given = get_fkey_list(tp);
26383468e90cSJohn Marino
26393468e90cSJohn Marino if (check == 0)
2640*32bb5217SDaniel Fojt failed("check_conflict");
26413468e90cSJohn Marino
26423468e90cSJohn Marino for (j = 0; given[j].keycode; ++j) {
26433468e90cSJohn Marino const char *a = given[j].value;
26445f4613f2SJohn Marino bool first = TRUE;
26453468e90cSJohn Marino
2646*32bb5217SDaniel Fojt if (!VALID_STRING(a))
2647*32bb5217SDaniel Fojt continue;
2648*32bb5217SDaniel Fojt
26493468e90cSJohn Marino for (k = j + 1; given[k].keycode; k++) {
26503468e90cSJohn Marino const char *b = given[k].value;
2651*32bb5217SDaniel Fojt
2652*32bb5217SDaniel Fojt if (!VALID_STRING(b))
2653*32bb5217SDaniel Fojt continue;
26543468e90cSJohn Marino if (check[k])
26555f4613f2SJohn Marino continue;
2656*32bb5217SDaniel Fojt
26575f4613f2SJohn Marino if (!_nc_capcmp(a, b)) {
26583468e90cSJohn Marino check[j] = 1;
26593468e90cSJohn Marino check[k] = 1;
26605f4613f2SJohn Marino if (first) {
26615f4613f2SJohn Marino if (!conflict) {
2662*32bb5217SDaniel Fojt _nc_warning("conflicting key definitions (using the last)");
26635f4613f2SJohn Marino conflict = TRUE;
26645f4613f2SJohn Marino }
26653468e90cSJohn Marino fprintf(stderr, "...");
26663468e90cSJohn Marino show_fkey_name(given + j);
26673468e90cSJohn Marino fprintf(stderr, " is the same as");
26683468e90cSJohn Marino show_fkey_name(given + k);
26695f4613f2SJohn Marino first = FALSE;
26705f4613f2SJohn Marino } else {
26713468e90cSJohn Marino fprintf(stderr, ", ");
26723468e90cSJohn Marino show_fkey_name(given + k);
26735f4613f2SJohn Marino }
26745f4613f2SJohn Marino }
26755f4613f2SJohn Marino }
26765f4613f2SJohn Marino if (!first)
26775f4613f2SJohn Marino fprintf(stderr, "\n");
26785f4613f2SJohn Marino }
2679*32bb5217SDaniel Fojt #if NCURSES_XNAMES
2680*32bb5217SDaniel Fojt if (using_extensions) {
2681*32bb5217SDaniel Fojt /* *INDENT-OFF* */
2682*32bb5217SDaniel Fojt static struct {
2683*32bb5217SDaniel Fojt const char *xcurses;
2684*32bb5217SDaniel Fojt const char *shifted;
2685*32bb5217SDaniel Fojt } table[] = {
2686*32bb5217SDaniel Fojt { "kDC", NULL },
2687*32bb5217SDaniel Fojt { "kDN", "kind" },
2688*32bb5217SDaniel Fojt { "kEND", NULL },
2689*32bb5217SDaniel Fojt { "kHOM", NULL },
2690*32bb5217SDaniel Fojt { "kLFT", NULL },
2691*32bb5217SDaniel Fojt { "kNXT", NULL },
2692*32bb5217SDaniel Fojt { "kPRV", NULL },
2693*32bb5217SDaniel Fojt { "kRIT", NULL },
2694*32bb5217SDaniel Fojt { "kUP", "kri" },
2695*32bb5217SDaniel Fojt { NULL, NULL },
2696*32bb5217SDaniel Fojt };
2697*32bb5217SDaniel Fojt /* *INDENT-ON* */
2698*32bb5217SDaniel Fojt
2699*32bb5217SDaniel Fojt /*
2700*32bb5217SDaniel Fojt * SVr4 curses defines the "xcurses" names listed above except for
2701*32bb5217SDaniel Fojt * the special cases in the "shifted" column. When using these
2702*32bb5217SDaniel Fojt * names for xterm's extensions, that was confusing, and resulted
2703*32bb5217SDaniel Fojt * in adding extended capabilities with "2" (shift) suffix. This
2704*32bb5217SDaniel Fojt * check warns about unnecessary use of extensions for this quirk.
2705*32bb5217SDaniel Fojt */
2706*32bb5217SDaniel Fojt for (j = 0; given[j].keycode; ++j) {
2707*32bb5217SDaniel Fojt const char *find = given[j].name;
2708*32bb5217SDaniel Fojt int value;
2709*32bb5217SDaniel Fojt char ch;
2710*32bb5217SDaniel Fojt
2711*32bb5217SDaniel Fojt if (!VALID_STRING(given[j].value))
2712*32bb5217SDaniel Fojt continue;
2713*32bb5217SDaniel Fojt
2714*32bb5217SDaniel Fojt for (k = 0; table[k].xcurses; ++k) {
2715*32bb5217SDaniel Fojt const char *test = table[k].xcurses;
2716*32bb5217SDaniel Fojt size_t size = strlen(test);
2717*32bb5217SDaniel Fojt
2718*32bb5217SDaniel Fojt if (!strncmp(find, test, size) && strcmp(find, test)) {
2719*32bb5217SDaniel Fojt switch (sscanf(find + size, "%d%c", &value, &ch)) {
2720*32bb5217SDaniel Fojt case 1:
2721*32bb5217SDaniel Fojt if (value == 2) {
2722*32bb5217SDaniel Fojt _nc_warning("expected '%s' rather than '%s'",
2723*32bb5217SDaniel Fojt (table[k].shifted
2724*32bb5217SDaniel Fojt ? table[k].shifted
2725*32bb5217SDaniel Fojt : test), find);
2726*32bb5217SDaniel Fojt } else if (value < 2 || value > 15) {
2727*32bb5217SDaniel Fojt _nc_warning("expected numeric 2..15 '%s'", find);
2728*32bb5217SDaniel Fojt }
2729*32bb5217SDaniel Fojt break;
2730*32bb5217SDaniel Fojt default:
2731*32bb5217SDaniel Fojt _nc_warning("expected numeric suffix for '%s'", find);
2732*32bb5217SDaniel Fojt break;
2733*32bb5217SDaniel Fojt }
2734*32bb5217SDaniel Fojt break;
2735*32bb5217SDaniel Fojt }
2736*32bb5217SDaniel Fojt }
2737*32bb5217SDaniel Fojt }
2738*32bb5217SDaniel Fojt }
2739*32bb5217SDaniel Fojt #endif
27403468e90cSJohn Marino free(given);
27413468e90cSJohn Marino free(check);
27423468e90cSJohn Marino }
27435f4613f2SJohn Marino }
27445f4613f2SJohn Marino
27453468e90cSJohn Marino /*
27463468e90cSJohn Marino * Exiting a video mode should not duplicate sgr0
27473468e90cSJohn Marino */
27483468e90cSJohn Marino static void
check_exit_attribute(const char * name,char * test,char * trimmed,char * untrimmed)27493468e90cSJohn Marino check_exit_attribute(const char *name, char *test, char *trimmed, char *untrimmed)
27503468e90cSJohn Marino {
2751*32bb5217SDaniel Fojt if (VALID_STRING(test) && (trimmed != 0)) {
27523468e90cSJohn Marino if (similar_sgr(-1, trimmed, test) ||
27533468e90cSJohn Marino similar_sgr(-1, untrimmed, test)) {
27543468e90cSJohn Marino _nc_warning("%s matches exit_attribute_mode", name);
27553468e90cSJohn Marino }
27563468e90cSJohn Marino }
27573468e90cSJohn Marino }
27583468e90cSJohn Marino
27593468e90cSJohn Marino /*
27603468e90cSJohn Marino * Returns true if the string looks like a standard SGR string.
27613468e90cSJohn Marino */
27623468e90cSJohn Marino static bool
is_sgr_string(char * value)27633468e90cSJohn Marino is_sgr_string(char *value)
27643468e90cSJohn Marino {
27653468e90cSJohn Marino bool result = FALSE;
27663468e90cSJohn Marino
27673468e90cSJohn Marino if (VALID_STRING(value)) {
2768*32bb5217SDaniel Fojt int skip = csi_length(value);
2769*32bb5217SDaniel Fojt
2770*32bb5217SDaniel Fojt if (skip) {
27713468e90cSJohn Marino int ch;
2772*32bb5217SDaniel Fojt
2773*32bb5217SDaniel Fojt result = TRUE;
2774*32bb5217SDaniel Fojt value += skip;
27753468e90cSJohn Marino while ((ch = UChar(*value++)) != '\0') {
27763468e90cSJohn Marino if (isdigit(ch) || ch == ';') {
27773468e90cSJohn Marino ;
27783468e90cSJohn Marino } else if (ch == 'm' && *value == '\0') {
27793468e90cSJohn Marino ;
27803468e90cSJohn Marino } else {
27813468e90cSJohn Marino result = FALSE;
27823468e90cSJohn Marino break;
27833468e90cSJohn Marino }
27843468e90cSJohn Marino }
27853468e90cSJohn Marino }
27863468e90cSJohn Marino }
27873468e90cSJohn Marino return result;
27883468e90cSJohn Marino }
27893468e90cSJohn Marino
27903468e90cSJohn Marino /*
27913468e90cSJohn Marino * Check if the given capability contains a given SGR attribute.
27923468e90cSJohn Marino */
27933468e90cSJohn Marino static void
check_sgr_param(TERMTYPE2 * tp,int code,const char * name,char * value)2794*32bb5217SDaniel Fojt check_sgr_param(TERMTYPE2 *tp, int code, const char *name, char *value)
27953468e90cSJohn Marino {
27963468e90cSJohn Marino if (VALID_STRING(value)) {
27973468e90cSJohn Marino int ncv = ((code != 0) ? (1 << (code - 1)) : 0);
27983468e90cSJohn Marino char *test = tgoto(value, 0, 0);
27993468e90cSJohn Marino if (is_sgr_string(test)) {
28003468e90cSJohn Marino int param = 0;
28013468e90cSJohn Marino int count = 0;
28023468e90cSJohn Marino int skips = 0;
28033468e90cSJohn Marino int color = (value == set_a_foreground ||
28043468e90cSJohn Marino value == set_a_background ||
28053468e90cSJohn Marino value == set_foreground ||
28063468e90cSJohn Marino value == set_background);
28073468e90cSJohn Marino while (*test != 0) {
28083468e90cSJohn Marino if (isdigit(UChar(*test))) {
28093468e90cSJohn Marino param = 10 * param + (*test - '0');
28103468e90cSJohn Marino ++count;
28113468e90cSJohn Marino } else {
28123468e90cSJohn Marino if (count) {
28133468e90cSJohn Marino /*
28143468e90cSJohn Marino * Avoid unnecessary warning for xterm 256color codes.
28153468e90cSJohn Marino */
28163468e90cSJohn Marino if (color && (param == 38 || param == 48))
28173468e90cSJohn Marino skips = 3;
28183468e90cSJohn Marino if ((skips-- <= 0) && (param == code))
28193468e90cSJohn Marino break;
28203468e90cSJohn Marino }
28213468e90cSJohn Marino count = 0;
28223468e90cSJohn Marino param = 0;
28233468e90cSJohn Marino }
28243468e90cSJohn Marino ++test;
28253468e90cSJohn Marino }
28263468e90cSJohn Marino if (count != 0 && param == code) {
28273468e90cSJohn Marino if (code == 0 ||
28283468e90cSJohn Marino no_color_video < 0 ||
28293468e90cSJohn Marino !(no_color_video & ncv)) {
28303468e90cSJohn Marino _nc_warning("\"%s\" SGR-attribute used in %s",
28313468e90cSJohn Marino sgr_names[code],
28323468e90cSJohn Marino name);
28333468e90cSJohn Marino }
28343468e90cSJohn Marino }
28353468e90cSJohn Marino }
28363468e90cSJohn Marino }
28373468e90cSJohn Marino }
28383468e90cSJohn Marino
2839*32bb5217SDaniel Fojt #if NCURSES_XNAMES
2840*32bb5217SDaniel Fojt static int
standard_type(const char * name)2841*32bb5217SDaniel Fojt standard_type(const char *name)
2842*32bb5217SDaniel Fojt {
2843*32bb5217SDaniel Fojt int result = -1;
2844*32bb5217SDaniel Fojt const struct name_table_entry *np;
2845*32bb5217SDaniel Fojt
2846*32bb5217SDaniel Fojt if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0) {
2847*32bb5217SDaniel Fojt result = np->nte_type;
2848*32bb5217SDaniel Fojt }
2849*32bb5217SDaniel Fojt return result;
2850*32bb5217SDaniel Fojt }
2851*32bb5217SDaniel Fojt
2852*32bb5217SDaniel Fojt static const char *
name_of_type(int type)2853*32bb5217SDaniel Fojt name_of_type(int type)
2854*32bb5217SDaniel Fojt {
2855*32bb5217SDaniel Fojt const char *result = "unknown";
2856*32bb5217SDaniel Fojt switch (type) {
2857*32bb5217SDaniel Fojt case BOOLEAN:
2858*32bb5217SDaniel Fojt result = "boolean";
2859*32bb5217SDaniel Fojt break;
2860*32bb5217SDaniel Fojt case NUMBER:
2861*32bb5217SDaniel Fojt result = "number";
2862*32bb5217SDaniel Fojt break;
2863*32bb5217SDaniel Fojt case STRING:
2864*32bb5217SDaniel Fojt result = "string";
2865*32bb5217SDaniel Fojt break;
2866*32bb5217SDaniel Fojt }
2867*32bb5217SDaniel Fojt return result;
2868*32bb5217SDaniel Fojt }
2869*32bb5217SDaniel Fojt
2870*32bb5217SDaniel Fojt static void
check_user_capability_type(const char * name,int actual)2871*32bb5217SDaniel Fojt check_user_capability_type(const char *name, int actual)
2872*32bb5217SDaniel Fojt {
2873*32bb5217SDaniel Fojt if (lookup_user_capability(name) == 0) {
2874*32bb5217SDaniel Fojt int expected = standard_type(name);
2875*32bb5217SDaniel Fojt if (expected >= 0) {
2876*32bb5217SDaniel Fojt _nc_warning("expected %s to be %s, but actually %s",
2877*32bb5217SDaniel Fojt name,
2878*32bb5217SDaniel Fojt name_of_type(actual),
2879*32bb5217SDaniel Fojt name_of_type(expected)
2880*32bb5217SDaniel Fojt );
2881*32bb5217SDaniel Fojt } else if (*name != 'k') {
2882*32bb5217SDaniel Fojt _nc_warning("undocumented %s capability %s",
2883*32bb5217SDaniel Fojt name_of_type(actual),
2884*32bb5217SDaniel Fojt name);
2885*32bb5217SDaniel Fojt }
2886*32bb5217SDaniel Fojt }
2887*32bb5217SDaniel Fojt }
2888*32bb5217SDaniel Fojt #endif
2889*32bb5217SDaniel Fojt
28903468e90cSJohn Marino /* other sanity-checks (things that we don't want in the normal
28913468e90cSJohn Marino * logic that reads a terminfo entry)
28923468e90cSJohn Marino */
28933468e90cSJohn Marino static void
check_termtype(TERMTYPE2 * tp,bool literal)2894*32bb5217SDaniel Fojt check_termtype(TERMTYPE2 *tp, bool literal)
28953468e90cSJohn Marino {
28963468e90cSJohn Marino unsigned j;
28973468e90cSJohn Marino
28983468e90cSJohn Marino check_conflict(tp);
28993468e90cSJohn Marino
29003468e90cSJohn Marino for_each_string(j, tp) {
29015f4613f2SJohn Marino char *a = tp->Strings[j];
29023468e90cSJohn Marino if (VALID_STRING(a)) {
2903*32bb5217SDaniel Fojt const char *name = ExtStrname(tp, (int) j, strnames);
2904*32bb5217SDaniel Fojt /*
2905*32bb5217SDaniel Fojt * If we expect parameters, or if there might be parameters,
2906*32bb5217SDaniel Fojt * check for consistent number of parameters.
2907*32bb5217SDaniel Fojt */
2908*32bb5217SDaniel Fojt if (j >= SIZEOF(parametrized) ||
2909*32bb5217SDaniel Fojt is_user_capability(name) >= 0 ||
2910*32bb5217SDaniel Fojt parametrized[j] > 0) {
2911*32bb5217SDaniel Fojt check_params(tp, name, a, (j >= STRCOUNT));
2912*32bb5217SDaniel Fojt }
2913*32bb5217SDaniel Fojt check_delays(tp, ExtStrname(tp, (int) j, strnames), a);
29143468e90cSJohn Marino if (capdump) {
29153468e90cSJohn Marino check_infotocap(tp, (int) j, a);
29163468e90cSJohn Marino }
29173468e90cSJohn Marino }
29185f4613f2SJohn Marino }
2919*32bb5217SDaniel Fojt #if NCURSES_XNAMES
2920*32bb5217SDaniel Fojt /* in extended mode, verify that each extension is expected type */
2921*32bb5217SDaniel Fojt for_each_ext_boolean(j, tp) {
2922*32bb5217SDaniel Fojt check_user_capability_type(ExtBoolname(tp, (int) j, strnames), BOOLEAN);
2923*32bb5217SDaniel Fojt }
2924*32bb5217SDaniel Fojt for_each_ext_number(j, tp) {
2925*32bb5217SDaniel Fojt check_user_capability_type(ExtNumname(tp, (int) j, strnames), NUMBER);
2926*32bb5217SDaniel Fojt }
2927*32bb5217SDaniel Fojt for_each_ext_string(j, tp) {
2928*32bb5217SDaniel Fojt check_user_capability_type(ExtStrname(tp, (int) j, strnames), STRING);
2929*32bb5217SDaniel Fojt }
2930*32bb5217SDaniel Fojt #endif /* NCURSES_XNAMES */
29315f4613f2SJohn Marino
29325f4613f2SJohn Marino check_acs(tp);
29335f4613f2SJohn Marino check_colors(tp);
29345f4613f2SJohn Marino check_cursor(tp);
29355f4613f2SJohn Marino check_keypad(tp);
29365f4613f2SJohn Marino check_printer(tp);
29373468e90cSJohn Marino check_screen(tp);
29385f4613f2SJohn Marino
29395f4613f2SJohn Marino /*
2940*32bb5217SDaniel Fojt * These are probably both or none.
2941*32bb5217SDaniel Fojt */
2942*32bb5217SDaniel Fojt PAIRED(parm_index, parm_rindex);
2943*32bb5217SDaniel Fojt PAIRED(parm_ich, parm_dch);
2944*32bb5217SDaniel Fojt
2945*32bb5217SDaniel Fojt /*
29465f4613f2SJohn Marino * These may be mismatched because the terminal description relies on
29475f4613f2SJohn Marino * restoring the cursor visibility by resetting it.
29485f4613f2SJohn Marino */
29495f4613f2SJohn Marino ANDMISSING(cursor_invisible, cursor_normal);
29505f4613f2SJohn Marino ANDMISSING(cursor_visible, cursor_normal);
29515f4613f2SJohn Marino
29525f4613f2SJohn Marino if (PRESENT(cursor_visible) && PRESENT(cursor_normal)
29535f4613f2SJohn Marino && !_nc_capcmp(cursor_visible, cursor_normal))
29545f4613f2SJohn Marino _nc_warning("cursor_visible is same as cursor_normal");
29555f4613f2SJohn Marino
29565f4613f2SJohn Marino /*
29575f4613f2SJohn Marino * From XSI & O'Reilly, we gather that sc/rc are required if csr is
29585f4613f2SJohn Marino * given, because the cursor position after the scrolling operation is
29595f4613f2SJohn Marino * performed is undefined.
29605f4613f2SJohn Marino */
29615f4613f2SJohn Marino ANDMISSING(change_scroll_region, save_cursor);
29625f4613f2SJohn Marino ANDMISSING(change_scroll_region, restore_cursor);
29635f4613f2SJohn Marino
29645f4613f2SJohn Marino /*
29655f4613f2SJohn Marino * If we can clear tabs, we should be able to initialize them.
29665f4613f2SJohn Marino */
29675f4613f2SJohn Marino ANDMISSING(clear_all_tabs, set_tab);
29685f4613f2SJohn Marino
29695f4613f2SJohn Marino if (PRESENT(set_attributes)) {
29705f4613f2SJohn Marino char *zero = 0;
29715f4613f2SJohn Marino
29725f4613f2SJohn Marino _nc_tparm_err = 0;
29735f4613f2SJohn Marino if (PRESENT(exit_attribute_mode)) {
29745f4613f2SJohn Marino zero = strdup(CHECK_SGR(0, exit_attribute_mode));
29755f4613f2SJohn Marino } else {
29765f4613f2SJohn Marino zero = strdup(TPARM_9(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0));
29775f4613f2SJohn Marino }
29785f4613f2SJohn Marino if (_nc_tparm_err)
29795f4613f2SJohn Marino _nc_warning("stack error in sgr(0) string");
29805f4613f2SJohn Marino
29815f4613f2SJohn Marino if (zero != 0) {
29825f4613f2SJohn Marino CHECK_SGR(1, enter_standout_mode);
29835f4613f2SJohn Marino CHECK_SGR(2, enter_underline_mode);
29845f4613f2SJohn Marino CHECK_SGR(3, enter_reverse_mode);
29855f4613f2SJohn Marino CHECK_SGR(4, enter_blink_mode);
29865f4613f2SJohn Marino CHECK_SGR(5, enter_dim_mode);
29875f4613f2SJohn Marino CHECK_SGR(6, enter_bold_mode);
29885f4613f2SJohn Marino CHECK_SGR(7, enter_secure_mode);
29895f4613f2SJohn Marino CHECK_SGR(8, enter_protected_mode);
29905f4613f2SJohn Marino CHECK_SGR(9, enter_alt_charset_mode);
29915f4613f2SJohn Marino free(zero);
29925f4613f2SJohn Marino } else {
29935f4613f2SJohn Marino _nc_warning("sgr(0) did not return a value");
29945f4613f2SJohn Marino }
29955f4613f2SJohn Marino } else if (PRESENT(exit_attribute_mode) &&
29965f4613f2SJohn Marino set_attributes != CANCELLED_STRING) {
29975f4613f2SJohn Marino if (_nc_syntax == SYN_TERMINFO)
29985f4613f2SJohn Marino _nc_warning("missing sgr string");
29995f4613f2SJohn Marino }
30003468e90cSJohn Marino #define CHECK_SGR0(name) check_exit_attribute(#name, name, check_sgr0, exit_attribute_mode)
30015f4613f2SJohn Marino if (PRESENT(exit_attribute_mode)) {
30025f4613f2SJohn Marino char *check_sgr0 = _nc_trim_sgr0(tp);
30035f4613f2SJohn Marino
30045f4613f2SJohn Marino if (check_sgr0 == 0 || *check_sgr0 == '\0') {
30055f4613f2SJohn Marino _nc_warning("trimmed sgr0 is empty");
30065f4613f2SJohn Marino } else {
30075f4613f2SJohn Marino show_where(2);
30085f4613f2SJohn Marino if (check_sgr0 != exit_attribute_mode) {
30095f4613f2SJohn Marino DEBUG(2,
30105f4613f2SJohn Marino ("will trim sgr0\n\toriginal sgr0=%s\n\ttrimmed sgr0=%s",
30115f4613f2SJohn Marino _nc_visbuf2(1, exit_attribute_mode),
30125f4613f2SJohn Marino _nc_visbuf2(2, check_sgr0)));
30135f4613f2SJohn Marino } else {
30145f4613f2SJohn Marino DEBUG(2,
30155f4613f2SJohn Marino ("will not trim sgr0\n\toriginal sgr0=%s",
30165f4613f2SJohn Marino _nc_visbuf(exit_attribute_mode)));
30175f4613f2SJohn Marino }
30185f4613f2SJohn Marino }
3019*32bb5217SDaniel Fojt #if defined(exit_italics_mode)
30203468e90cSJohn Marino CHECK_SGR0(exit_italics_mode);
3021*32bb5217SDaniel Fojt #endif
30223468e90cSJohn Marino CHECK_SGR0(exit_standout_mode);
30233468e90cSJohn Marino CHECK_SGR0(exit_underline_mode);
30243468e90cSJohn Marino if (check_sgr0 != exit_attribute_mode) {
30253468e90cSJohn Marino free(check_sgr0);
30263468e90cSJohn Marino }
30273468e90cSJohn Marino }
30283468e90cSJohn Marino #define CHECK_SGR_PARAM(code, name) check_sgr_param(tp, (int)code, #name, name)
30293468e90cSJohn Marino for (j = 0; *sgr_names[j] != '\0'; ++j) {
30303468e90cSJohn Marino CHECK_SGR_PARAM(j, set_a_foreground);
30313468e90cSJohn Marino CHECK_SGR_PARAM(j, set_a_background);
30323468e90cSJohn Marino CHECK_SGR_PARAM(j, set_foreground);
30333468e90cSJohn Marino CHECK_SGR_PARAM(j, set_background);
30345f4613f2SJohn Marino }
30355f4613f2SJohn Marino #ifdef TRACE
30365f4613f2SJohn Marino show_where(2);
30375f4613f2SJohn Marino if (!auto_right_margin) {
30385f4613f2SJohn Marino DEBUG(2,
30395f4613f2SJohn Marino ("can write to lower-right directly"));
30405f4613f2SJohn Marino } else if (PRESENT(enter_am_mode) && PRESENT(exit_am_mode)) {
30415f4613f2SJohn Marino DEBUG(2,
30425f4613f2SJohn Marino ("can write to lower-right by suppressing automargin"));
30435f4613f2SJohn Marino } else if ((PRESENT(enter_insert_mode) && PRESENT(exit_insert_mode))
30445f4613f2SJohn Marino || PRESENT(insert_character) || PRESENT(parm_ich)) {
30455f4613f2SJohn Marino DEBUG(2,
30465f4613f2SJohn Marino ("can write to lower-right by using inserts"));
30475f4613f2SJohn Marino } else {
30485f4613f2SJohn Marino DEBUG(2,
30495f4613f2SJohn Marino ("cannot write to lower-right"));
30505f4613f2SJohn Marino }
30515f4613f2SJohn Marino #endif
30525f4613f2SJohn Marino
30535f4613f2SJohn Marino /*
30545f4613f2SJohn Marino * Some standard applications (e.g., vi) and some non-curses
30555f4613f2SJohn Marino * applications (e.g., jove) get confused if we have both ich1 and
30565f4613f2SJohn Marino * smir/rmir. Let's be nice and warn about that, too, even though
30575f4613f2SJohn Marino * ncurses handles it.
30585f4613f2SJohn Marino */
30595f4613f2SJohn Marino if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))
3060*32bb5217SDaniel Fojt && PRESENT(insert_character)) {
30615f4613f2SJohn Marino _nc_warning("non-curses applications may be confused by ich1 with smir/rmir");
30625f4613f2SJohn Marino }
30635f4613f2SJohn Marino
30645f4613f2SJohn Marino /*
30655f4613f2SJohn Marino * Finally, do the non-verbose checks
30665f4613f2SJohn Marino */
30675f4613f2SJohn Marino if (save_check_termtype != 0)
30685f4613f2SJohn Marino save_check_termtype(tp, literal);
30695f4613f2SJohn Marino }
3070