From cea297eb34d2361e79529034397465068ae34ecd Mon Sep 17 00:00:00 2001 From: Xin LI Date: Sat, 1 Mar 2014 00:40:26 +0000 Subject: Vendor import of ncurses 5.9 20140222 snapshot. --- progs/Makefile.in | 33 +-- progs/capconvert | 24 ++- progs/clear.c | 12 +- progs/dump_entry.c | 247 +++++++++++++++------ progs/dump_entry.h | 18 +- progs/infocmp.c | 492 +++++++++++++++++++++++++++++++----------- progs/progs.priv.h | 22 +- progs/tabs.c | 146 ++++++++----- progs/tic.c | 619 +++++++++++++++++++++++++++++++++++++++++++---------- progs/toe.c | 456 ++++++++++++++++++++++++++++----------- progs/tput.c | 13 +- progs/transform.c | 16 +- progs/tset.c | 121 ++++++----- 13 files changed, 1635 insertions(+), 584 deletions(-) (limited to 'progs') diff --git a/progs/Makefile.in b/progs/Makefile.in index bdb8a0f04898..a9161b16cbca 100644 --- a/progs/Makefile.in +++ b/progs/Makefile.in @@ -1,6 +1,6 @@ -# $Id: Makefile.in,v 1.85 2010/11/27 21:45:27 tom Exp $ +# $Id: Makefile.in,v 1.90 2013/08/04 20:23:20 tom Exp $ ############################################################################## -# Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. # +# Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. # # # # Permission is hereby granted, free of charge, to any person obtaining a # # copy of this software and associated documentation files (the "Software"), # @@ -61,7 +61,11 @@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ includedir = @includedir@ +datarootdir = @datarootdir@ datadir = @datadir@ +includesubdir = @includesubdir@ + +INCLUDEDIR = $(DESTDIR)$(includedir)$(includesubdir) LIBTOOL = @LIBTOOL@ LIBTOOL_CLEAN = @LIB_CLEAN@ @@ -104,20 +108,21 @@ LOCAL_LIBDIR = @top_builddir@/lib LD = @LD@ LINK = @LINK_PROGS@ $(LIBTOOL_LINK) LDFLAGS = @EXTRA_LDFLAGS@ @LDFLAGS@ +RPATH_LIST = @RPATH_LIST@ LDFLAGS_LIBTOOL = $(LDFLAGS) $(CFLAGS_LIBTOOL) LDFLAGS_NORMAL = $(LDFLAGS) $(CFLAGS_NORMAL) LDFLAGS_DEBUG = $(LDFLAGS) $(CFLAGS_DEBUG) -LDFLAGS_PROFILE = $(LDFLAGS) $(CFLAGS_PROFILE) +LDFLAGS_PROFILE = $(LDFLAGS) $(CFLAGS_PROFILE) LDFLAGS_SHARED = $(LDFLAGS) $(CFLAGS_SHARED) @LD_SHARED_OPTS@ LDFLAGS_DEFAULT = $(LDFLAGS_@DFT_UPR_MODEL@) -LIBS_TIC = @LDFLAGS_STATIC@ @TICS_ARGS@ @TINFO_ARGS@ @LDFLAGS_SHARED@ @LD_MODEL@ @LIBS@ -LDFLAGS_TIC = $(LDFLAGS_@DFT_UPR_MODEL@) $(LIBS_TIC) +LIBS_TIC = @TINFO_LDFLAGS@ @LDFLAGS_STATIC@ @TICS_LIBS@ @TINFO_LIBS@ @LDFLAGS_SHARED@ @LD_MODEL@ @LIBS@ +LDFLAGS_TIC = @TICS_LDFLAGS@ $(LDFLAGS_@DFT_UPR_MODEL@) $(LIBS_TIC) -LIBS_TINFO = @LDFLAGS_STATIC@ @TINFO_ARGS@ @LDFLAGS_SHARED@ @LD_MODEL@ @LIBS@ -LDFLAGS_TINFO = $(LDFLAGS_@DFT_UPR_MODEL@) $(LIBS_TINFO) +LIBS_TINFO = @LDFLAGS_STATIC@ @TINFO_LIBS@ @LDFLAGS_SHARED@ @LD_MODEL@ @LIBS@ +LDFLAGS_TINFO = @TINFO_LDFLAGS@ $(LDFLAGS_@DFT_UPR_MODEL@) $(LIBS_TINFO) LINT = @LINT@ LINT_OPTS = @LINT_OPTS@ @@ -230,46 +235,46 @@ DEPS_TIC = \ $(MODEL)/transform$o tic$x: $(DEPS_TIC) $(DEPS_CURSES) transform.h - @ECHO_LINK@ $(LINK) $(DEPS_TIC) $(LDFLAGS_TIC) -o $@ + @ECHO_LD@ $(LINK) $(DEPS_TIC) $(LDFLAGS_TIC) -o $@ DEPS_TOE = \ $(MODEL)/toe$o toe$x: $(DEPS_TOE) $(DEPS_CURSES) - @ECHO_LINK@ $(LINK) $(DEPS_TOE) $(LDFLAGS_TIC) -o $@ + @ECHO_LD@ $(LINK) $(DEPS_TOE) $(LDFLAGS_TIC) -o $@ DEPS_CLEAR = \ $(MODEL)/clear$o clear$x: $(DEPS_CLEAR) $(DEPS_CURSES) - @ECHO_LINK@ $(LINK) $(DEPS_CLEAR) $(LDFLAGS_TINFO) -o $@ + @ECHO_LD@ $(LINK) $(DEPS_CLEAR) $(LDFLAGS_TINFO) -o $@ DEPS_TABS = \ $(MODEL)/tabs$o tabs$x: $(DEPS_TABS) $(DEPS_TABS) - @ECHO_LINK@ $(LINK) $(DEPS_TABS) $(LDFLAGS_TINFO) -o $@ + @ECHO_LD@ $(LINK) $(DEPS_TABS) $(LDFLAGS_TINFO) -o $@ DEPS_TPUT = \ $(MODEL)/tput$o \ $(MODEL)/transform$o tput$x: $(DEPS_TPUT) $(DEPS_CURSES) transform.h - @ECHO_LINK@ $(LINK) $(DEPS_TPUT) $(LDFLAGS_TINFO) -o $@ + @ECHO_LD@ $(LINK) $(DEPS_TPUT) $(LDFLAGS_TINFO) -o $@ DEPS_INFOCMP = \ $(MODEL)/infocmp$o \ $(MODEL)/dump_entry$o infocmp$x: $(DEPS_INFOCMP) $(DEPS_CURSES) - @ECHO_LINK@ $(LINK) $(DEPS_INFOCMP) $(LDFLAGS_TIC) -o $@ + @ECHO_LD@ $(LINK) $(DEPS_INFOCMP) $(LDFLAGS_TIC) -o $@ DEPS_TSET = \ $(MODEL)/tset$o \ $(MODEL)/transform$o tset$x: $(DEPS_TSET) $(DEPS_CURSES) transform.h - @ECHO_LINK@ $(LINK) $(DEPS_TSET) $(LDFLAGS_TINFO) -o $@ + @ECHO_LD@ $(LINK) $(DEPS_TSET) $(LDFLAGS_TINFO) -o $@ termsort.c: $(srcdir)/MKtermsort.sh sh $(srcdir)/MKtermsort.sh $(AWK) $(srcdir)/../include/@TERMINFO_CAPS@ >$@ diff --git a/progs/capconvert b/progs/capconvert index 8199bbf09b7e..eb382e0bc86c 100755 --- a/progs/capconvert +++ b/progs/capconvert @@ -1,6 +1,6 @@ #!/bin/sh ############################################################################## -# Copyright (c) 1998,2006 Free Software Foundation, Inc. # +# Copyright (c) 1998-2006,2011 Free Software Foundation, Inc. # # # # Permission is hereby granted, free of charge, to any person obtaining a # # copy of this software and associated documentation files (the "Software"), # @@ -26,7 +26,7 @@ # use or other dealings in this Software without prior written # # authorization. # ############################################################################## -# $Id: capconvert,v 1.4 2006/04/22 21:46:17 tom Exp $ +# $Id: capconvert,v 1.5 2011/11/12 23:28:07 Robert.Millan Exp $ # # capconvert -- automated conversion from termcap to terminfo # @@ -77,16 +77,18 @@ then # Assumes the terminfo master covers all canned terminal types exit; fi - if test "$TERM" = "xterm" - then + case $TERM in + xterm | xterm-*) echo "You are running xterm, which usually sets TERMCAP itself." echo "We can ignore this, because terminfo knows about xterm." echo "So you will just use the system-wide terminfo tree." - exit; - else + exit + ;; + *) echo "We will have to make a local one for you anyway, to capture the effect" echo "of your TERMCAP variable." - fi + ;; + esac else echo "No system-wide terminfo tree. We will make you a local one." fi @@ -109,7 +111,7 @@ IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" for x in $PATH . do if test $OPT $x/tic - then + then TIC=$x/tic break fi @@ -141,7 +143,7 @@ if test -d $HOME/.terminfo then echo "It appears you already have a private terminfo directory" echo "at $HOME/.terminfo; this seems odd, because TERMINFO" - echo "is not defined. I am not going to second-guess this -- if you" + echo "is not defined. I am not going to second-guess this -- if you" echo "really want me to try auto-configuring for you, remove or" echo "rename $HOME/terminfo and run me again." exit; @@ -214,7 +216,7 @@ trap 0 1 2 5 15 # echo "You now have a private tree under $HOME/.terminfo;" echo "the ncurses library will automatically read from it," -echo "and ncurses tic will automatically compile entries to it." +echo "and ncurses tic will automatically compile entries to it." # We're done unless user has a .termcap file or equivalent named by TERMCAP if test -z "$TERMCAP" @@ -235,7 +237,7 @@ then echo "Done." echo "Note that editing $HOME/.termcap will no longer change the data curses sees." elif test -f "$TERMCAP" -then +then echo "Your TERMCAP names the file $TERMCAP. I will compile that." eval $TIC $TERMCAP echo "Done." diff --git a/progs/clear.c b/progs/clear.c index 9f5a543848a1..4ac503ed3641 100644 --- a/progs/clear.c +++ b/progs/clear.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2006,2007 Free Software Foundation, Inc. * + * Copyright (c) 1998-2007,2013 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -39,7 +39,7 @@ #define USE_LIBTINFO #include -MODULE_ID("$Id: clear.c,v 1.11 2007/10/13 22:16:02 tom Exp $") +MODULE_ID("$Id: clear.c,v 1.13 2013/06/22 22:20:54 tom Exp $") static int putch(int c) @@ -52,7 +52,15 @@ main( int argc GCC_UNUSED, char *argv[]GCC_UNUSED) { + char *E3; + setupterm((char *) 0, STDOUT_FILENO, (int *) 0); + + /* Clear the scrollback buffer if possible. */ + E3 = tigetstr("E3"); + if (E3) + (void) tputs(E3, lines > 0 ? lines : 1, putch); + ExitProgram((tputs(clear_screen, lines > 0 ? lines : 1, putch) == ERR) ? EXIT_FAILURE : EXIT_SUCCESS); diff --git a/progs/dump_entry.c b/progs/dump_entry.c index 485bbbd91d64..65de9f9bc1f1 100644 --- a/progs/dump_entry.c +++ b/progs/dump_entry.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2008,2010 Free Software Foundation, Inc. * + * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -39,7 +39,7 @@ #include "termsort.c" /* this C file is generated */ #include /* so is this */ -MODULE_ID("$Id: dump_entry.c,v 1.89 2010/05/01 22:04:08 tom Exp $") +MODULE_ID("$Id: dump_entry.c,v 1.111 2013/12/15 01:05:20 tom Exp $") #define INDENT 8 #define DISCARD(string) string = ABSENT_STRING @@ -57,6 +57,7 @@ static int tversion; /* terminfo version */ static int outform; /* output format to use */ static int sortmode; /* sort mode to use */ static int width = 60; /* max line width for listings */ +static int height = 65535; /* max number of lines for listings */ static int column; /* current column, limited by 'width' */ static int oldcol; /* last value of column before wrap */ static bool pretty; /* true if we format if-then-else strings */ @@ -72,7 +73,7 @@ static NCURSES_CONST char *const *bool_names; static NCURSES_CONST char *const *num_names; static NCURSES_CONST char *const *str_names; -static const char *separator, *trailer; +static const char *separator = "", *trailer = ""; /* cover various ports and variants of terminfo */ #define V_ALLCAPS 0 /* all capabilities (SVr4, XSI, ncurses) */ @@ -99,6 +100,15 @@ static const char *separator, *trailer; #define StrIndirect(j) ((sortmode == S_NOSORT) ? (j) : str_indirect[j]) #endif +static void failed(const char *) GCC_NORETURN; + +static void +failed(const char *s) +{ + perror(s); + ExitProgram(EXIT_FAILURE); +} + static void strncpy_DYN(DYNBUF * dst, const char *src, size_t need) { @@ -106,6 +116,8 @@ strncpy_DYN(DYNBUF * dst, const char *src, size_t need) if (want > dst->size) { dst->size += (want + 1024); /* be generous */ dst->text = typeRealloc(char, dst->size, dst->text); + if (dst->text == 0) + failed("strncpy_DYN"); } (void) strncpy(dst->text + dst->used, src, need); dst->used += need; @@ -172,11 +184,17 @@ nametrans(const char *name) } void -dump_init(const char *version, int mode, int sort, int twidth, int traceval, +dump_init(const char *version, + int mode, + int sort, + int twidth, + int theight, + unsigned traceval, bool formatted) /* set up for entry display */ { width = twidth; + height = theight; pretty = formatted; /* versions */ @@ -201,7 +219,7 @@ dump_init(const char *version, int mode, int sort, int twidth, int traceval, bool_names = boolnames; num_names = numnames; str_names = strnames; - separator = twidth ? ", " : ","; + separator = (twidth > 0 && theight > 1) ? ", " : ","; trailer = "\n\t"; break; @@ -209,7 +227,7 @@ dump_init(const char *version, int mode, int sort, int twidth, int traceval, bool_names = boolfnames; num_names = numfnames; str_names = strfnames; - separator = twidth ? ", " : ","; + separator = (twidth > 0 && theight > 1) ? ", " : ","; trailer = "\n\t"; break; @@ -291,7 +309,11 @@ dump_predicate(PredType type, PredIdx idx) static void set_obsolete_termcaps(TERMTYPE *tp); /* is this the index of a function key string? */ -#define FNKEY(i) (((i)<= 65 && (i)>= 75) || ((i)<= 216 && (i)>= 268)) +#define FNKEY(i) \ + (((i) >= STR_IDX(key_f0) && \ + (i) <= STR_IDX(key_f9)) || \ + ((i) >= STR_IDX(key_f11) && \ + (i) <= STR_IDX(key_f63))) /* * If we configure with a different Caps file, the offsets into the arrays @@ -393,8 +415,8 @@ force_wrap(void) static void wrap_concat(const char *src) { - unsigned need = strlen(src); - unsigned want = strlen(separator) + need; + size_t need = strlen(src); + size_t want = strlen(separator) + need; if (column > INDENT && column + (int) want > width) { @@ -445,7 +467,7 @@ indent_DYN(DYNBUF * buffer, int level) int n; for (n = 0; n < level; n++) - strncpy_DYN(buffer, "\t", 1); + strncpy_DYN(buffer, "\t", (size_t) 1); } static bool @@ -458,9 +480,9 @@ has_params(const char *src) bool params = FALSE; for (n = 0; n < len - 1; ++n) { - if (!strncmp(src + n, "%p", 2)) { + if (!strncmp(src + n, "%p", (size_t) 2)) { params = TRUE; - } else if (!strncmp(src + n, "%;", 2)) { + } else if (!strncmp(src + n, "%;", (size_t) 2)) { ifthen = TRUE; result = params; break; @@ -473,7 +495,7 @@ has_params(const char *src) } static char * -fmt_complex(char *src, int level) +fmt_complex(TERMTYPE *tterm, const char *capability, char *src, int level) { bool percent = FALSE; bool params = has_params(src); @@ -482,7 +504,7 @@ fmt_complex(char *src, int level) switch (*src) { case '\\': percent = FALSE; - strncpy_DYN(&tmpbuf, src++, 1); + strncpy_DYN(&tmpbuf, src++, (size_t) 1); break; case '%': percent = TRUE; @@ -496,26 +518,28 @@ fmt_complex(char *src, int level) /* treat a "%e" as else-if, on the same level */ if (*src == 'e') { indent_DYN(&tmpbuf, level); - strncpy_DYN(&tmpbuf, "%", 1); - strncpy_DYN(&tmpbuf, src, 1); + strncpy_DYN(&tmpbuf, "%", (size_t) 1); + strncpy_DYN(&tmpbuf, src, (size_t) 1); src++; params = has_params(src); if (!params && *src != '\0' && *src != '%') { - strncpy_DYN(&tmpbuf, "\n", 1); + strncpy_DYN(&tmpbuf, "\n", (size_t) 1); indent_DYN(&tmpbuf, level + 1); } } else { indent_DYN(&tmpbuf, level + 1); - strncpy_DYN(&tmpbuf, "%", 1); - strncpy_DYN(&tmpbuf, src, 1); + strncpy_DYN(&tmpbuf, "%", (size_t) 1); + strncpy_DYN(&tmpbuf, src, (size_t) 1); if (*src++ == '?') { - src = fmt_complex(src, level + 1); + src = fmt_complex(tterm, capability, src, level + 1); if (*src != '\0' && *src != '%') { - strncpy_DYN(&tmpbuf, "\n", 1); + strncpy_DYN(&tmpbuf, "\n", (size_t) 1); indent_DYN(&tmpbuf, level + 1); } } else if (level == 1) { - _nc_warning("%%%c without %%?", *src); + _nc_warning("%s: %%%c without %%? in %s", + _nc_first_name(tterm->term_names), + *src, capability); } } continue; @@ -527,31 +551,39 @@ fmt_complex(char *src, int level) if (level > 1) { tmpbuf.text[tmpbuf.used - 1] = '\n'; indent_DYN(&tmpbuf, level); - strncpy_DYN(&tmpbuf, "%", 1); - strncpy_DYN(&tmpbuf, src++, 1); + strncpy_DYN(&tmpbuf, "%", (size_t) 1); + strncpy_DYN(&tmpbuf, src++, (size_t) 1); + if (src[0] == '%' + && src[1] != '\0' + && (strchr("?e;", src[1])) == 0) { + tmpbuf.text[tmpbuf.used++] = '\n'; + indent_DYN(&tmpbuf, level); + } return src; } - _nc_warning("%%; without %%?"); + _nc_warning("%s: %%; without %%? in %s", + _nc_first_name(tterm->term_names), + capability); } break; case 'p': if (percent && params) { tmpbuf.text[tmpbuf.used - 1] = '\n'; indent_DYN(&tmpbuf, level + 1); - strncpy_DYN(&tmpbuf, "%", 1); + strncpy_DYN(&tmpbuf, "%", (size_t) 1); } params = FALSE; percent = FALSE; break; case ' ': - strncpy_DYN(&tmpbuf, "\\s", 2); + strncpy_DYN(&tmpbuf, "\\s", (size_t) 2); ++src; continue; default: percent = FALSE; break; } - strncpy_DYN(&tmpbuf, src++, 1); + strncpy_DYN(&tmpbuf, src++, (size_t) 1); } return src; } @@ -562,9 +594,9 @@ fmt_complex(char *src, int level) int fmt_entry(TERMTYPE *tterm, PredFunc pred, - bool content_only, - bool suppress_untranslatable, - bool infodump, + int content_only, + int suppress_untranslatable, + int infodump, int numbers) { PredIdx i, j; @@ -593,14 +625,28 @@ fmt_entry(TERMTYPE *tterm, column = INDENT; /* FIXME: workaround to prevent empty lines */ } else { strcpy_DYN(&outbuf, tterm->term_names); + + /* + * Colon is legal in terminfo descriptions, but not in termcap. + */ + if (!infodump) { + char *p = outbuf.text; + while (*p) { + if (*p == ':') { + *p = '='; + } + ++p; + } + } strcpy_DYN(&outbuf, separator); column = (int) outbuf.used; - force_wrap(); + if (height > 1) + force_wrap(); } for_each_boolean(j, tterm) { i = BoolIndirect(j); - name = ExtBoolname(tterm, i, bool_names); + name = ExtBoolname(tterm, (int) i, bool_names); assert(strlen(name) < sizeof(buffer) - EXTRA_CAP); if (!version_filter(BOOLEAN, i)) @@ -610,21 +656,21 @@ fmt_entry(TERMTYPE *tterm, predval = pred(BOOLEAN, i); if (predval != FAIL) { - (void) strcpy(buffer, name); + _nc_STRCPY(buffer, name, sizeof(buffer)); if (predval <= 0) - (void) strcat(buffer, "@"); + _nc_STRCAT(buffer, "@", sizeof(buffer)); else if (i + 1 > num_bools) num_bools = i + 1; WRAP_CONCAT; } } - if (column != INDENT) + if (column != INDENT && height > 1) force_wrap(); for_each_number(j, tterm) { i = NumIndirect(j); - name = ExtNumname(tterm, i, num_names); + name = ExtNumname(tterm, (int) i, num_names); assert(strlen(name) < sizeof(buffer) - EXTRA_CAP); if (!version_filter(NUMBER, i)) @@ -635,9 +681,11 @@ fmt_entry(TERMTYPE *tterm, predval = pred(NUMBER, i); if (predval != FAIL) { if (tterm->Numbers[i] < 0) { - sprintf(buffer, "%s@", name); + _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) + "%s@", name); } else { - sprintf(buffer, "%s#%d", name, tterm->Numbers[i]); + _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) + "%s#%d", name, tterm->Numbers[i]); if (i + 1 > num_values) num_values = i + 1; } @@ -645,7 +693,7 @@ fmt_entry(TERMTYPE *tterm, } } - if (column != INDENT) + if (column != INDENT && height > 1) force_wrap(); len += (int) (num_bools @@ -670,7 +718,7 @@ fmt_entry(TERMTYPE *tterm, for_each_string(j, tterm) { i = StrIndirect(j); - name = ExtStrname(tterm, i, str_names); + name = ExtStrname(tterm, (int) i, str_names); assert(strlen(name) < sizeof(buffer) - EXTRA_CAP); capability = tterm->Strings[i]; @@ -698,14 +746,14 @@ fmt_entry(TERMTYPE *tterm, if (PRESENT(insert_character) || PRESENT(parm_ich)) { if (SAME_CAP(i, enter_insert_mode) && enter_insert_mode == ABSENT_STRING) { - (void) strcpy(buffer, "im="); + _nc_STRCPY(buffer, "im=", sizeof(buffer)); WRAP_CONCAT; continue; } if (SAME_CAP(i, exit_insert_mode) && exit_insert_mode == ABSENT_STRING) { - (void) strcpy(buffer, "ei="); + _nc_STRCPY(buffer, "ei=", sizeof(buffer)); WRAP_CONCAT; continue; } @@ -739,7 +787,8 @@ fmt_entry(TERMTYPE *tterm, num_strings = i + 1; if (!VALID_STRING(capability)) { - sprintf(buffer, "%s@", name); + _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) + "%s@", name); WRAP_CONCAT; } else if (outform == F_TERMCAP || outform == F_TCONVERR) { int params = ((i < (int) SIZEOF(parametrized)) @@ -750,13 +799,14 @@ fmt_entry(TERMTYPE *tterm, if (cv == 0) { if (outform == F_TCONVERR) { - sprintf(buffer, "%s=!!! %s WILL NOT CONVERT !!!", - name, srccap); + _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) + "%s=!!! %s WILL NOT CONVERT !!!", + name, srccap); } else if (suppress_untranslatable) { continue; } else { char *s = srccap, *d = buffer; - sprintf(d, "..%s=", name); + _nc_SPRINTF(d, _nc_SLIMIT(sizeof(buffer)) "..%s=", name); d += strlen(d); while ((*d = *s++) != 0) { if (*d == ':') { @@ -769,7 +819,8 @@ fmt_entry(TERMTYPE *tterm, } } } else { - sprintf(buffer, "%s=%s", name, cv); + _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) + "%s=%s", name, cv); } len += (int) strlen(capability) + 1; WRAP_CONCAT; @@ -783,7 +834,7 @@ fmt_entry(TERMTYPE *tterm, if (pretty && (outform == F_TERMINFO || outform == F_VARIABLE)) { - fmt_complex(src, 1); + fmt_complex(tterm, name, src, 1); } else { strcpy_DYN(&tmpbuf, src); } @@ -793,7 +844,9 @@ fmt_entry(TERMTYPE *tterm, } } /* e.g., trimmed_sgr0 */ - if (capability != tterm->Strings[i]) + if (capability != ABSENT_STRING && + capability != CANCELLED_STRING && + capability != tterm->Strings[i]) free(capability); } len += (int) (num_strings * 2); @@ -805,11 +858,13 @@ fmt_entry(TERMTYPE *tterm, */ if (tversion == V_HPUX) { if (VALID_STRING(memory_lock)) { - (void) sprintf(buffer, "meml=%s", memory_lock); + _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) + "meml=%s", memory_lock); WRAP_CONCAT; } if (VALID_STRING(memory_unlock)) { - (void) sprintf(buffer, "memu=%s", memory_unlock); + _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) + "memu=%s", memory_unlock); WRAP_CONCAT; } } else if (tversion == V_AIX) { @@ -821,7 +876,7 @@ fmt_entry(TERMTYPE *tterm, tp = boxchars; for (cp = acstrans; *cp; cp++) { - sp = strchr(acs_chars, *cp); + sp = (strchr) (acs_chars, *cp); if (sp) *tp++ = sp[1]; else { @@ -832,9 +887,41 @@ fmt_entry(TERMTYPE *tterm, tp[0] = '\0'; if (box_ok) { - (void) strcpy(buffer, "box1="); - (void) strcat(buffer, _nc_tic_expand(boxchars, - outform == F_TERMINFO, numbers)); + char *tmp = _nc_tic_expand(boxchars, + (outform == F_TERMINFO), + numbers); + _nc_STRCPY(buffer, "box1=", sizeof(buffer)); + while (*tmp != '\0') { + size_t have = strlen(buffer); + size_t next = strlen(tmp); + size_t want = have + next + 1; + size_t last = next; + char save = '\0'; + + /* + * If the expanded string is too long for the buffer, + * chop it off and save the location where we chopped it. + */ + if (want >= sizeof(buffer)) { + save = tmp[last]; + tmp[last] = '\0'; + } + _nc_STRCAT(buffer, tmp, sizeof(buffer)); + + /* + * If we chopped the buffer, replace the missing piece and + * shift everything to append the remainder. + */ + if (save != '\0') { + next = 0; + tmp[last] = save; + while ((tmp[next] = tmp[last + next]) != '\0') { + ++next; + } + } else { + break; + } + } WRAP_CONCAT; } } @@ -846,7 +933,7 @@ fmt_entry(TERMTYPE *tterm, */ if (outcount) { bool trimmed = FALSE; - j = outbuf.used; + j = (PredIdx) outbuf.used; if (j >= 2 && outbuf.text[j - 1] == '\t' && outbuf.text[j - 2] == '\n') { @@ -926,7 +1013,7 @@ kill_labels(TERMTYPE *tterm, int target) char name[10]; for (n = 0; n <= 10; ++n) { - sprintf(name, "lf%d", n); + _nc_SPRINTF(name, _nc_SLIMIT(sizeof(name)) "lf%d", n); if ((cap = find_string(tterm, name)) != ABSENT_STRING && kill_string(tterm, cap)) { target -= (int) (strlen(cap) + 5); @@ -951,7 +1038,7 @@ kill_fkeys(TERMTYPE *tterm, int target) char name[10]; for (n = 60; n >= 0; --n) { - sprintf(name, "kf%d", n); + _nc_SPRINTF(name, _nc_SLIMIT(sizeof(name)) "kf%d", n); if ((cap = find_string(tterm, name)) != ABSENT_STRING && kill_string(tterm, cap)) { target -= (int) (strlen(cap) + 5); @@ -1017,8 +1104,8 @@ purged_acs(TERMTYPE *tterm) */ void dump_entry(TERMTYPE *tterm, - bool suppress_untranslatable, - bool limited, + int suppress_untranslatable, + int limited, int numbers, PredFunc pred) { @@ -1064,7 +1151,7 @@ dump_entry(TERMTYPE *tterm, */ unsigned n; for (n = STRCOUNT; n < NUM_STRINGS(tterm); n++) { - const char *name = ExtStrname(tterm, n, strnames); + const char *name = ExtStrname(tterm, (int) n, strnames); if (VALID_STRING(tterm->Strings[n])) { set_attributes = ABSENT_STRING; @@ -1144,21 +1231,45 @@ dump_uses(const char *name, bool infodump) if (outform == F_TERMCAP || outform == F_TCONVERR) trim_trailing(); - (void) sprintf(buffer, "%s%s", infodump ? "use=" : "tc=", name); + _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) + "%s%s", infodump ? "use=" : "tc=", name); wrap_concat(buffer); } int show_entry(void) { - trim_trailing(); + /* + * Trim any remaining whitespace. + */ + if (outbuf.used != 0) { + bool infodump = (outform != F_TERMCAP && outform != F_TCONVERR); + char delim = (char) (infodump ? ',' : ':'); + int j; + + for (j = (int) outbuf.used - 1; j > 0; --j) { + char ch = outbuf.text[j]; + if (ch == '\n') { + ; + } else if (isspace(UChar(ch))) { + outbuf.used = (size_t) j; + } else if (!infodump && ch == '\\') { + outbuf.used = (size_t) j; + } else if (ch == delim && (j == 0 || outbuf.text[j - 1] != '\\')) { + outbuf.used = (size_t) (j + 1); + } else { + break; + } + } + outbuf.text[outbuf.used] = '\0'; + } (void) fputs(outbuf.text, stdout); putchar('\n'); return (int) outbuf.used; } void -compare_entry(void (*hook) (PredType t, PredIdx i, const char *name), +compare_entry(PredHook hook, TERMTYPE *tp GCC_UNUSED, bool quiet) /* compare two entries */ @@ -1170,7 +1281,7 @@ compare_entry(void (*hook) (PredType t, PredIdx i, const char *name), fputs(" comparing booleans.\n", stdout); for_each_boolean(j, tp) { i = BoolIndirect(j); - name = ExtBoolname(tp, i, bool_names); + name = ExtBoolname(tp, (int) i, bool_names); if (isObsolete(outform, name)) continue; @@ -1182,7 +1293,7 @@ compare_entry(void (*hook) (PredType t, PredIdx i, const char *name), fputs(" comparing numbers.\n", stdout); for_each_number(j, tp) { i = NumIndirect(j); - name = ExtNumname(tp, i, num_names); + name = ExtNumname(tp, (int) i, num_names); if (isObsolete(outform, name)) continue; @@ -1194,7 +1305,7 @@ compare_entry(void (*hook) (PredType t, PredIdx i, const char *name), fputs(" comparing strings.\n", stdout); for_each_string(j, tp) { i = StrIndirect(j); - name = ExtStrname(tp, i, str_names); + name = ExtStrname(tp, (int) i, str_names); if (isObsolete(outform, name)) continue; diff --git a/progs/dump_entry.h b/progs/dump_entry.h index b99a37a74f25..cb2a44fe7d4f 100644 --- a/progs/dump_entry.h +++ b/progs/dump_entry.h @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2006,2008 Free Software Foundation, Inc. * + * Copyright (c) 1998-2011,2013 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -32,9 +32,8 @@ * and: Thomas E. Dickey 1996-on * ****************************************************************************/ - /* - * $Id: dump_entry.h,v 1.30 2008/07/12 20:23:03 tom Exp $ + * $Id: dump_entry.h,v 1.33 2013/12/15 01:08:03 tom Exp $ * * Dump control definitions and variables */ @@ -64,16 +63,17 @@ typedef unsigned PredType; typedef unsigned PredIdx; -typedef int (*PredFunc)(PredType, PredIdx); +typedef int (*PredFunc) (PredType, PredIdx); +typedef void (*PredHook) (PredType, PredIdx, const char *); extern NCURSES_CONST char *nametrans(const char *); -extern int fmt_entry(TERMTYPE *, PredFunc, bool, bool, bool, int); +extern int fmt_entry(TERMTYPE *, PredFunc, int, int, int, int); extern int show_entry(void); -extern void compare_entry(void (*)(PredType, PredIdx, const char *), TERMTYPE *, bool); -extern void dump_entry(TERMTYPE *, bool, bool, int, PredFunc); -extern void dump_init(const char *, int, int, int, int, bool); +extern void compare_entry(PredHook, TERMTYPE *, bool); +extern void dump_entry(TERMTYPE *, int, int, int, PredFunc); +extern void dump_init(const char *, int, int, int, int, unsigned, bool); extern void dump_uses(const char *, bool); -extern void repair_acsc(TERMTYPE * tp); +extern void repair_acsc(TERMTYPE *tp); #define FAIL -1 diff --git a/progs/infocmp.c b/progs/infocmp.c index 2af9cb50b1d7..587cbc3449be 100644 --- a/progs/infocmp.c +++ b/progs/infocmp.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. * + * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -42,7 +42,7 @@ #include -MODULE_ID("$Id: infocmp.c,v 1.105 2010/05/01 22:04:08 tom Exp $") +MODULE_ID("$Id: infocmp.c,v 1.129 2014/02/01 22:11:03 tom Exp $") #define L_CURL "{" #define R_CURL "}" @@ -70,8 +70,9 @@ static const char *bool_sep = ":"; static const char *s_absent = "NULL"; static const char *s_cancel = "NULL"; static const char *tversion; /* terminfo version selected */ -static int itrace; /* trace flag for debugging */ +static unsigned itrace; /* trace flag for debugging */ static int mwidth = 60; +static int mheight = 65535; static int numbers = 0; /* format "%'char'" to/from "%{number}" */ static int outform = F_TERMINFO; /* output format */ static int sortmode; /* sort_mode */ @@ -86,27 +87,52 @@ static int compare; static bool ignorepads; /* ignore pad prefixes when diffing */ #if NO_LEAKS + +typedef struct { + ENTRY *head; + ENTRY *tail; +} ENTERED; + +static ENTERED *entered; + #undef ExitProgram static void ExitProgram(int code) GCC_NORETURN; /* prototype is to get gcc to accept the noreturn attribute */ static void ExitProgram(int code) { - while (termcount-- > 0) - _nc_free_termtype(&entries[termcount].tterm); + int n; + + for (n = 0; n < termcount; ++n) { + ENTRY *new_head = _nc_head; + ENTRY *new_tail = _nc_tail; + _nc_head = entered[n].head; + _nc_tail = entered[n].tail; + _nc_free_entries(entered[n].head); + _nc_head = new_head; + _nc_tail = new_tail; + } _nc_leaks_dump_entry(); free(entries); + free(entered); _nc_free_tic(code); } #endif +static void +failed(const char *s) +{ + perror(s); + ExitProgram(EXIT_FAILURE); +} + static char * canonical_name(char *ptr, char *buf) /* extract the terminal type's primary name */ { char *bp; - (void) strcpy(buf, ptr); + _nc_STRCPY(buf, ptr, NAMESIZE); if ((bp = strchr(buf, '|')) != 0) *bp = '\0'; @@ -307,13 +333,13 @@ dump_numeric(int val, char *buf) { switch (val) { case ABSENT_NUMERIC: - strcpy(buf, s_absent); + _nc_STRCPY(buf, s_absent, MAX_STRING); break; case CANCELLED_NUMERIC: - strcpy(buf, s_cancel); + _nc_STRCPY(buf, s_cancel, MAX_STRING); break; default: - sprintf(buf, "%d", val); + _nc_SPRINTF(buf, _nc_SLIMIT(MAX_STRING) "%d", val); break; } } @@ -323,31 +349,94 @@ dump_string(char *val, char *buf) /* display the value of a string capability */ { if (val == ABSENT_STRING) - strcpy(buf, s_absent); + _nc_STRCPY(buf, s_absent, MAX_STRING); else if (val == CANCELLED_STRING) - strcpy(buf, s_cancel); + _nc_STRCPY(buf, s_cancel, MAX_STRING); else { - sprintf(buf, "'%.*s'", MAX_STRING - 3, TIC_EXPAND(val)); + _nc_SPRINTF(buf, _nc_SLIMIT(MAX_STRING) + "'%.*s'", MAX_STRING - 3, TIC_EXPAND(val)); } } +/* + * Show "comparing..." message for the given terminal names. + */ +static void +show_comparing(char **names) +{ + if (itrace) { + switch (compare) { + case C_DIFFERENCE: + (void) fprintf(stderr, "%s: dumping differences\n", _nc_progname); + break; + + case C_COMMON: + (void) fprintf(stderr, "%s: dumping common capabilities\n", _nc_progname); + break; + + case C_NAND: + (void) fprintf(stderr, "%s: dumping differences\n", _nc_progname); + break; + } + } + if (*names) { + printf("comparing %s", *names++); + if (*names) { + printf(" to %s", *names++); + while (*names) { + printf(", %s", *names++); + } + } + printf(".\n"); + } +} + +/* + * ncurses stores two types of non-standard capabilities: + * a) capabilities listed past the "STOP-HERE" comment in the Caps file. + * These are used in the terminfo source file to provide data for termcaps, + * e.g., when there is no equivalent capability in terminfo, as well as for + * widely-used non-standard capabilities. + * b) user-definable capabilities, via "tic -x". + * + * However, if "-x" is omitted from the tic command, both types of + * non-standard capability are not loaded into the terminfo database. This + * macro is used for limit-checks against the symbols that tic uses to omit + * the two types of non-standard entry. + */ +#if NCURSES_XNAMES +#define check_user_definable(n,limit) if (!_nc_user_definable && (n) > (limit)) break +#else +#define check_user_definable(n,limit) if ((n) > (limit)) break +#endif + +/* + * Use these macros to simplify loops on C_COMMON and C_NAND: + */ +#define for_each_entry() while (entries[extra].tterm.term_names) +#define next_entry (&(entries[extra++].tterm)) + static void compare_predicate(PredType type, PredIdx idx, const char *name) /* predicate function to use for entry difference reports */ { - register ENTRY *e1 = &entries[0]; - register ENTRY *e2 = &entries[1]; - char buf1[MAX_STRING], buf2[MAX_STRING]; + ENTRY *e1 = &entries[0]; + ENTRY *e2 = &entries[1]; + char buf1[MAX_STRING]; + char buf2[MAX_STRING]; int b1, b2; int n1, n2; char *s1, *s2; + bool found; + int extra = 1; switch (type) { case CMP_BOOLEAN: + check_user_definable(idx, BOOLWRITE); b1 = e1->tterm.Booleans[idx]; - b2 = e2->tterm.Booleans[idx]; switch (compare) { case C_DIFFERENCE: + b2 = next_entry->Booleans[idx]; if (!(b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) && b1 != b2) (void) printf("\t%s: %s%s%s.\n", name, @@ -357,45 +446,93 @@ compare_predicate(PredType type, PredIdx idx, const char *name) break; case C_COMMON: - if (b1 == b2 && b1 != ABSENT_BOOLEAN) - (void) printf("\t%s= %s.\n", name, dump_boolean(b1)); + if (b1 != ABSENT_BOOLEAN) { + found = TRUE; + for_each_entry() { + b2 = next_entry->Booleans[idx]; + if (b1 != b2) { + found = FALSE; + break; + } + } + if (found) { + (void) printf("\t%s= %s.\n", name, dump_boolean(b1)); + } + } break; case C_NAND: - if (b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) - (void) printf("\t!%s.\n", name); + if (b1 == ABSENT_BOOLEAN) { + found = TRUE; + for_each_entry() { + b2 = next_entry->Booleans[idx]; + if (b1 != b2) { + found = FALSE; + break; + } + } + if (found) { + (void) printf("\t!%s.\n", name); + } + } break; } break; case CMP_NUMBER: + check_user_definable(idx, NUMWRITE); n1 = e1->tterm.Numbers[idx]; - n2 = e2->tterm.Numbers[idx]; - dump_numeric(n1, buf1); - dump_numeric(n2, buf2); switch (compare) { case C_DIFFERENCE: - if (!((n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)) && n1 != n2) + n2 = next_entry->Numbers[idx]; + if (!((n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)) && n1 != n2) { + dump_numeric(n1, buf1); + dump_numeric(n2, buf2); (void) printf("\t%s: %s, %s.\n", name, buf1, buf2); + } break; case C_COMMON: - if (n1 != ABSENT_NUMERIC && n2 != ABSENT_NUMERIC && n1 == n2) - (void) printf("\t%s= %s.\n", name, buf1); + if (n1 != ABSENT_NUMERIC) { + found = TRUE; + for_each_entry() { + n2 = next_entry->Numbers[idx]; + if (n1 != n2) { + found = FALSE; + break; + } + } + if (found) { + dump_numeric(n1, buf1); + (void) printf("\t%s= %s.\n", name, buf1); + } + } break; case C_NAND: - if (n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC) - (void) printf("\t!%s.\n", name); + if (n1 == ABSENT_NUMERIC) { + found = TRUE; + for_each_entry() { + n2 = next_entry->Numbers[idx]; + if (n1 != n2) { + found = FALSE; + break; + } + } + if (found) { + (void) printf("\t!%s.\n", name); + } + } break; } break; case CMP_STRING: + check_user_definable(idx, STRWRITE); s1 = e1->tterm.Strings[idx]; - s2 = e2->tterm.Strings[idx]; switch (compare) { case C_DIFFERENCE: + s2 = next_entry->Strings[idx]; if (capcmp(idx, s1, s2)) { dump_string(s1, buf1); dump_string(s2, buf2); @@ -405,13 +542,35 @@ compare_predicate(PredType type, PredIdx idx, const char *name) break; case C_COMMON: - if (s1 && s2 && !capcmp(idx, s1, s2)) - (void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1)); + if (s1 != ABSENT_STRING) { + found = TRUE; + for_each_entry() { + s2 = next_entry->Strings[idx]; + if (capcmp(idx, s1, s2) != 0) { + found = FALSE; + break; + } + } + if (found) { + (void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1)); + } + } break; case C_NAND: - if (!s1 && !s2) - (void) printf("\t!%s.\n", name); + if (s1 == ABSENT_STRING) { + found = TRUE; + for_each_entry() { + s2 = next_entry->Strings[idx]; + if (s2 != s1) { + found = FALSE; + break; + } + } + if (found) { + (void) printf("\t!%s.\n", name); + } + } break; } break; @@ -430,16 +589,37 @@ compare_predicate(PredType type, PredIdx idx, const char *name) break; case C_COMMON: - if (e1->nuses && e2->nuses && useeq(e1, e2)) { - (void) fputs("\tuse: ", stdout); - print_uses(e1, stdout); - fputs(".\n", stdout); + if (e1->nuses) { + found = TRUE; + for_each_entry() { + e2 = &entries[extra++]; + if (e2->nuses != e1->nuses || !useeq(e1, e2)) { + found = FALSE; + break; + } + } + if (found) { + (void) fputs("\tuse: ", stdout); + print_uses(e1, stdout); + fputs(".\n", stdout); + } } break; case C_NAND: - if (!e1->nuses && !e2->nuses) - (void) printf("\t!use.\n"); + if (!e1->nuses) { + found = TRUE; + for_each_entry() { + e2 = &entries[extra++]; + if (e2->nuses != e1->nuses) { + found = FALSE; + break; + } + } + if (found) { + (void) printf("\t!use.\n"); + } + } break; } } @@ -556,7 +736,7 @@ skip_csi(const char *cap) } static bool -same_param(const char *table, const char *param, unsigned length) +same_param(const char *table, const char *param, size_t length) { bool result = FALSE; if (strncmp(table, param, length) == 0) { @@ -581,15 +761,15 @@ lookup_params(const assoc * table, char *dst, char *src) size_t tlen = strlen(ap->from); if (same_param(ap->from, ep, tlen)) { - (void) strcat(dst, ap->to); + _nc_STRCAT(dst, ap->to, MAX_TERMINFO_LENGTH); found = TRUE; break; } } if (!found) - (void) strcat(dst, ep); - (void) strcat(dst, ";"); + _nc_STRCAT(dst, ep, MAX_TERMINFO_LENGTH); + _nc_STRCAT(dst, ";", MAX_TERMINFO_LENGTH); } while ((ep = strtok((char *) 0, ";"))); @@ -608,7 +788,7 @@ analyze_string(const char *name, const char *cap, TERMTYPE *tp) const assoc *ap; int tp_lines = tp->Numbers[2]; - if (cap == ABSENT_STRING || cap == CANCELLED_STRING) + if (!VALID_STRING(cap)) return; (void) printf("%s: ", name); @@ -624,12 +804,13 @@ analyze_string(const char *name, const char *cap, TERMTYPE *tp) for (i = 0; i < STRCOUNT; i++) { char *cp = tp->Strings[i]; - /* don't use soft-key capabilities */ - if (strnames[i][0] == 'k' && strnames[i][0] == 'f') + /* don't use function-key capabilities */ + if (strnames[i][0] == 'k' && strnames[i][1] == 'f') continue; - if (cp != ABSENT_STRING && cp != CANCELLED_STRING && cp[0] && cp - != cap) { + if (VALID_STRING(cp) && + cp[0] != '\0' && + cp != cap) { len = strlen(cp); (void) strncpy(buf2, sp, len); buf2[len] = '\0'; @@ -637,7 +818,7 @@ analyze_string(const char *name, const char *cap, TERMTYPE *tp) if (_nc_capcmp(cp, buf2)) continue; -#define ISRS(s) (!strncmp((s), "is", 2) || !strncmp((s), "rs", 2)) +#define ISRS(s) (!strncmp((s), "is", (size_t) 2) || !strncmp((s), "rs", (size_t) 2)) /* * Theoretically we just passed the test for translation * (equality once the padding is stripped). However, there @@ -677,12 +858,16 @@ analyze_string(const char *name, const char *cap, TERMTYPE *tp) /* now check for standard-mode sequences */ if (!expansion && (csi = skip_csi(sp)) != 0 - && (len = strspn(sp + csi, "0123456789;")) + && (len = (strspn) (sp + csi, "0123456789;")) && (len < sizeof(buf3)) && (next = (size_t) csi + len) && ((sp[next] == 'h') || (sp[next] == 'l'))) { - (void) strcpy(buf2, (sp[next] == 'h') ? "ECMA+" : "ECMA-"); + _nc_STRCPY(buf2, + ((sp[next] == 'h') + ? "ECMA+" + : "ECMA-"), + sizeof(buf2)); (void) strncpy(buf3, sp + csi, len); buf3[len] = '\0'; len += (size_t) csi + 1; @@ -694,12 +879,16 @@ analyze_string(const char *name, const char *cap, TERMTYPE *tp) if (!expansion && (csi = skip_csi(sp)) != 0 && sp[csi] == '?' - && (len = strspn(sp + csi + 1, "0123456789;")) + && (len = (strspn) (sp + csi + 1, "0123456789;")) && (len < sizeof(buf3)) && (next = (size_t) csi + 1 + len) && ((sp[next] == 'h') || (sp[next] == 'l'))) { - (void) strcpy(buf2, (sp[next] == 'h') ? "DEC+" : "DEC-"); + _nc_STRCPY(buf2, + ((sp[next] == 'h') + ? "DEC+" + : "DEC-"), + sizeof(buf2)); (void) strncpy(buf3, sp + csi + 1, len); buf3[len] = '\0'; len += (size_t) csi + 2; @@ -710,12 +899,12 @@ analyze_string(const char *name, const char *cap, TERMTYPE *tp) /* now check for ECMA highlight sequences */ if (!expansion && (csi = skip_csi(sp)) != 0 - && (len = strspn(sp + csi, "0123456789;")) != 0 + && (len = (strspn) (sp + csi, "0123456789;")) != 0 && (len < sizeof(buf3)) && (next = (size_t) csi + len) && sp[next] == 'm') { - (void) strcpy(buf2, "SGR:"); + _nc_STRCPY(buf2, "SGR:", sizeof(buf2)); (void) strncpy(buf3, sp + csi, len); buf3[len] = '\0'; len += (size_t) csi + 1; @@ -727,8 +916,8 @@ analyze_string(const char *name, const char *cap, TERMTYPE *tp) && (csi = skip_csi(sp)) != 0 && sp[csi] == 'm') { len = (size_t) csi + 1; - (void) strcpy(buf2, "SGR:"); - strcat(buf2, ecma_highlights[0].to); + _nc_STRCPY(buf2, "SGR:", sizeof(buf2)); + _nc_STRCAT(buf2, ecma_highlights[0].to, sizeof(buf2)); expansion = buf2; } @@ -739,7 +928,7 @@ analyze_string(const char *name, const char *cap, TERMTYPE *tp) expansion = "RSR"; len = 1; } else { - (void) sprintf(buf2, "1;%dr", tp_lines); + _nc_SPRINTF(buf2, _nc_SLIMIT(sizeof(buf2)) "1;%dr", tp_lines); len = strlen(buf2); if (strncmp(buf2, sp + csi, len) == 0) expansion = "RSR"; @@ -750,12 +939,12 @@ analyze_string(const char *name, const char *cap, TERMTYPE *tp) /* now check for home-down */ if (!expansion && (csi = skip_csi(sp)) != 0) { - (void) sprintf(buf2, "%d;1H", tp_lines); + _nc_SPRINTF(buf2, _nc_SLIMIT(sizeof(buf2)) "%d;1H", tp_lines); len = strlen(buf2); if (strncmp(buf2, sp + csi, len) == 0) { expansion = "LL"; } else { - (void) sprintf(buf2, "%dH", tp_lines); + _nc_SPRINTF(buf2, _nc_SLIMIT(sizeof(buf2)) "%dH", tp_lines); len = strlen(buf2); if (strncmp(buf2, sp + csi, len) == 0) { expansion = "LL"; @@ -795,12 +984,16 @@ file_comparison(int argc, char *argv[]) int i, n; memset(heads, 0, sizeof(heads)); - dump_init((char *) 0, F_LITERAL, S_TERMINFO, 0, itrace, FALSE); + dump_init((char *) 0, F_LITERAL, S_TERMINFO, 0, 65535, itrace, FALSE); for (n = 0; n < argc && n < MAXCOMPARE; n++) { if (freopen(argv[n], "r", stdin) == 0) _nc_err_abort("Can't open %s", argv[n]); +#if NO_LEAKS + entered[n].head = _nc_head; + entered[n].tail = _nc_tail; +#endif _nc_head = _nc_tail = 0; /* parse entries out of the source file */ @@ -925,6 +1118,11 @@ file_comparison(int argc, char *argv[]) #endif if (!(entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp))) { char name1[NAMESIZE], name2[NAMESIZE]; + char *names[3]; + + names[0] = name1; + names[1] = name2; + names[2] = 0; entries[0] = *qp; entries[1] = *rp; @@ -934,29 +1132,17 @@ file_comparison(int argc, char *argv[]) switch (compare) { case C_DIFFERENCE: - if (itrace) - (void) fprintf(stderr, - "%s: dumping differences\n", - _nc_progname); - (void) printf("comparing %s to %s.\n", name1, name2); + show_comparing(names); compare_entry(compare_predicate, &entries->tterm, quiet); break; case C_COMMON: - if (itrace) - (void) fprintf(stderr, - "%s: dumping common capabilities\n", - _nc_progname); - (void) printf("comparing %s to %s.\n", name1, name2); + show_comparing(names); compare_entry(compare_predicate, &entries->tterm, quiet); break; case C_NAND: - if (itrace) - (void) fprintf(stderr, - "%s: dumping differences\n", - _nc_progname); - (void) printf("comparing %s to %s.\n", name1, name2); + show_comparing(names); compare_entry(compare_predicate, &entries->tterm, quiet); break; @@ -974,7 +1160,9 @@ usage(void) "Usage: infocmp [options] [-A directory] [-B directory] [termname...]" ,"" ,"Options:" + ," -0 print single-row" ," -1 print single-column" + ," -K use termcap-names and BSD syntax" ," -C use termcap-names" ," -F compare terminfo-files" ," -I use terminfo-names" @@ -982,6 +1170,7 @@ usage(void) ," -R subset (see manpage)" ," -T eliminate size limits (test)" ," -U eliminate post-processing of entries" + ," -D print database locations" ," -V print version" #if NCURSES_XNAMES ," -a with -F, list commented-out caps" @@ -1030,19 +1219,25 @@ static char * any_initializer(const char *fmt, const char *type) { static char *initializer; + static size_t need; char *s; - if (initializer == 0) - initializer = (char *) malloc(strlen(entries->tterm.term_names) + - strlen(type) + strlen(fmt)); + if (initializer == 0) { + need = (strlen(entries->tterm.term_names) + + strlen(type) + + strlen(fmt)); + initializer = (char *) malloc(need + 1); + if (initializer == 0) + failed("any_initializer"); + } - (void) strcpy(initializer, entries->tterm.term_names); + _nc_STRCPY(initializer, entries->tterm.term_names, need); for (s = initializer; *s != 0 && *s != '|'; s++) { if (!isalnum(UChar(*s))) *s = '_'; } *s = 0; - (void) sprintf(s, fmt, type); + _nc_SPRINTF(s, _nc_SLIMIT(need) fmt, type); return initializer; } @@ -1073,9 +1268,10 @@ dump_initializers(TERMTYPE *term) if (VALID_STRING(term->Strings[n])) { tp = buf; +#define TP_LIMIT ((MAX_STRING - 5) - (size_t)(tp - buf)) *tp++ = '"'; for (sp = term->Strings[n]; - *sp != 0 && (tp - buf) < MAX_STRING - 6; + *sp != 0 && TP_LIMIT > 2; sp++) { if (isascii(UChar(*sp)) && isprint(UChar(*sp)) @@ -1083,14 +1279,15 @@ dump_initializers(TERMTYPE *term) && *sp != '"') *tp++ = *sp; else { - (void) sprintf(tp, "\\%03o", UChar(*sp)); + _nc_SPRINTF(tp, _nc_SLIMIT(TP_LIMIT) "\\%03o", UChar(*sp)); tp += 4; } } *tp++ = '"'; *tp = '\0'; (void) printf("static char %-20s[] = %s;\n", - string_variable(ExtStrname(term, n, strnames)), buf); + string_variable(ExtStrname(term, (int) n, strnames)), + buf); } } printf("\n"); @@ -1116,7 +1313,7 @@ dump_initializers(TERMTYPE *term) break; } (void) printf("\t/* %3u: %-8s */\t%s,\n", - n, ExtBoolname(term, n, boolnames), str); + n, ExtBoolname(term, (int) n, boolnames), str); } (void) printf("%s;\n", R_CURL); @@ -1132,12 +1329,12 @@ dump_initializers(TERMTYPE *term) str = "CANCELLED_NUMERIC"; break; default: - sprintf(buf, "%d", term->Numbers[n]); + _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) "%d", term->Numbers[n]); str = buf; break; } (void) printf("\t/* %3u: %-8s */\t%s,\n", n, - ExtNumname(term, n, numnames), str); + ExtNumname(term, (int) n, numnames), str); } (void) printf("%s;\n", R_CURL); @@ -1150,10 +1347,10 @@ dump_initializers(TERMTYPE *term) else if (term->Strings[n] == CANCELLED_STRING) str = "CANCELLED_STRING"; else { - str = string_variable(ExtStrname(term, n, strnames)); + str = string_variable(ExtStrname(term, (int) n, strnames)); } (void) printf("\t/* %3u: %-8s */\t%s,\n", n, - ExtStrname(term, n, strnames), str); + ExtStrname(term, (int) n, strnames), str); } (void) printf("%s;\n", R_CURL); @@ -1165,15 +1362,15 @@ dump_initializers(TERMTYPE *term) name_initializer("string_ext"), L_CURL); for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) { (void) printf("\t/* %3u: bool */\t\"%s\",\n", - n, ExtBoolname(term, n, boolnames)); + n, ExtBoolname(term, (int) n, boolnames)); } for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) { (void) printf("\t/* %3u: num */\t\"%s\",\n", - n, ExtNumname(term, n, numnames)); + n, ExtNumname(term, (int) n, numnames)); } for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) { (void) printf("\t/* %3u: str */\t\"%s\",\n", - n, ExtStrname(term, n, strnames)); + n, ExtStrname(term, (int) n, strnames)); } (void) printf("%s;\n", R_CURL); } @@ -1247,6 +1444,23 @@ terminal_env(void) return terminal; } +/* + * Show the databases that infocmp knows about. The location to which it writes is + */ +static void +show_databases(void) +{ + DBDIRS state; + int offset; + const char *path2; + + _nc_first_db(&state, &offset); + while ((path2 = _nc_next_db(&state, &offset)) != 0) { + printf("%s\n", path2); + } + _nc_last_db(); +} + /*************************************************************************** * * Main sequence @@ -1269,7 +1483,7 @@ main(int argc, char *argv[]) /* Also avoid overflowing smaller stacks on systems like AmigaOS */ path *tfile = 0; char **tname = 0; - int maxterms; + size_t maxterms; char **myargv; @@ -1287,18 +1501,27 @@ main(int argc, char *argv[]) #if NCURSES_XNAMES use_extended_names(FALSE); #endif + _nc_strict_bsd = 0; _nc_progname = _nc_rootname(argv[0]); /* make sure we have enough space to add two terminal entries */ myargv = typeCalloc(char *, (size_t) (argc + 3)); + if (myargv == 0) + failed("myargv"); + memcpy(myargv, argv, (sizeof(char *) * (size_t) argc)); argv = myargv; while ((c = getopt(argc, argv, - "1A:aB:CcdEeFfGgIiLlnpqR:rs:TtUuVv:w:x")) != -1) { + "01A:aB:CcDdEeFfGgIiKLlnpqR:rs:TtUuVv:w:x")) != -1) { switch (c) { + case '0': + mwidth = 65535; + mheight = 1; + break; + case '1': mwidth = 0; break; @@ -1317,6 +1540,9 @@ main(int argc, char *argv[]) restdir = optarg; break; + case 'K': + _nc_strict_bsd = 1; + /* FALLTHRU */ case 'C': outform = F_TERMCAP; tversion = "BSD"; @@ -1324,6 +1550,11 @@ main(int argc, char *argv[]) sortmode = S_TERMCAP; break; + case 'D': + show_databases(); + ExitProgram(EXIT_SUCCESS); + break; + case 'c': compare = C_COMMON; break; @@ -1441,7 +1672,7 @@ main(int argc, char *argv[]) ExitProgram(EXIT_SUCCESS); case 'v': - itrace = optarg_to_number(); + itrace = (unsigned) optarg_to_number(); set_trace_level(itrace); break; @@ -1460,10 +1691,17 @@ main(int argc, char *argv[]) } } - maxterms = (argc + 2 - optind); - tfile = typeMalloc(path, maxterms); - tname = typeCalloc(char *, maxterms); - entries = typeCalloc(ENTRY, maxterms); + maxterms = (size_t) (argc + 2 - optind); + if ((tfile = typeMalloc(path, maxterms)) == 0) + failed("tfile"); + if ((tname = typeCalloc(char *, maxterms)) == 0) + failed("tname"); + if ((entries = typeCalloc(ENTRY, maxterms)) == 0) + failed("entries"); +#if NO_LEAKS + if ((entered = typeCalloc(ENTERED, maxterms)) == 0) + failed("entered"); +#endif if (tfile == 0 || tname == 0 @@ -1476,9 +1714,6 @@ main(int argc, char *argv[]) if (sortmode == S_DEFAULT) sortmode = S_TERMINFO; - /* set up for display */ - dump_init(tversion, outform, sortmode, mwidth, itrace, formatted); - /* make sure we have at least one terminal name to work with */ if (optind >= argc) argv[argc++] = terminal_env(); @@ -1487,9 +1722,23 @@ main(int argc, char *argv[]) if (compare != C_DEFAULT && optind >= argc - 1) argv[argc++] = terminal_env(); + /* exactly one terminal name with no options means display it */ /* exactly two terminal names with no options means do -d */ - if (argc - optind == 2 && compare == C_DEFAULT) - compare = C_DIFFERENCE; + if (compare == C_DEFAULT) { + switch (argc - optind) { + default: + fprintf(stderr, "%s: too many names to compare\n", _nc_progname); + ExitProgram(EXIT_FAILURE); + case 1: + break; + case 2: + compare = C_DIFFERENCE; + break; + } + } + + /* set up for display */ + dump_init(tversion, outform, sortmode, mwidth, mheight, itrace, formatted); if (!filecompare) { /* grab the entries */ @@ -1501,15 +1750,17 @@ main(int argc, char *argv[]) tname[termcount] = argv[optind]; if (directory) { -#if USE_DATABASE +#if NCURSES_USE_DATABASE #if MIXEDCASE_FILENAMES #define LEAF_FMT "%c" #else #define LEAF_FMT "%02x" #endif - (void) sprintf(tfile[termcount], "%s/" LEAF_FMT "/%s", - directory, - UChar(*argv[optind]), argv[optind]); + _nc_SPRINTF(tfile[termcount], + _nc_SLIMIT(sizeof(path)) + "%s/" LEAF_FMT "/%s", + directory, + UChar(*argv[optind]), argv[optind]); if (itrace) (void) fprintf(stderr, "%s: reading entry %s from file %s\n", @@ -1599,27 +1850,17 @@ main(int argc, char *argv[]) break; case C_DIFFERENCE: - if (itrace) - (void) fprintf(stderr, "%s: dumping differences\n", _nc_progname); - (void) printf("comparing %s to %s.\n", tname[0], tname[1]); + show_comparing(tname); compare_entry(compare_predicate, &entries->tterm, quiet); break; case C_COMMON: - if (itrace) - (void) fprintf(stderr, - "%s: dumping common capabilities\n", - _nc_progname); - (void) printf("comparing %s to %s.\n", tname[0], tname[1]); + show_comparing(tname); compare_entry(compare_predicate, &entries->tterm, quiet); break; case C_NAND: - if (itrace) - (void) fprintf(stderr, - "%s: dumping differences\n", - _nc_progname); - (void) printf("comparing %s to %s.\n", tname[0], tname[1]); + show_comparing(tname); compare_entry(compare_predicate, &entries->tterm, quiet); break; @@ -1640,15 +1881,16 @@ main(int argc, char *argv[]) break; } } - } else if (compare == C_USEALL) + } else if (compare == C_USEALL) { (void) fprintf(stderr, "Sorry, -u doesn't work with -F\n"); - else if (compare == C_DEFAULT) + } else if (compare == C_DEFAULT) { (void) fprintf(stderr, "Use `tic -[CI] ' for this.\n"); - else if (argc - optind != 2) + } else if (argc - optind != 2) { (void) fprintf(stderr, "File comparison needs exactly two file arguments.\n"); - else + } else { file_comparison(argc - optind, argv + optind); + } MAIN_LEAKS(); ExitProgram(EXIT_SUCCESS); diff --git a/progs/progs.priv.h b/progs/progs.priv.h index f0ea4608227d..3ead89f85d20 100644 --- a/progs/progs.priv.h +++ b/progs/progs.priv.h @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * + * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -30,7 +30,7 @@ * Author: Thomas E. Dickey 1997-on * ****************************************************************************/ /* - * $Id: progs.priv.h,v 1.34 2008/08/03 17:43:05 tom Exp $ + * $Id: progs.priv.h,v 1.39 2012/02/22 22:11:27 tom Exp $ * * progs.priv.h * @@ -42,7 +42,7 @@ #if USE_RCS_IDS #define MODULE_ID(id) static const char Ident[] = id; #else -#define MODULE_ID(id) /*nothing*/ +#define MODULE_ID(id) /*nothing */ #endif #include @@ -90,6 +90,14 @@ # endif #endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif + #include #include @@ -99,7 +107,7 @@ extern int errno; #if HAVE_GETOPT_H #include -#else +#elif !defined(HAVE_GETOPT_HEADER) /* 'getopt()' may be prototyped in , but declaring its * variables doesn't hurt. */ @@ -109,9 +117,11 @@ extern int optind; #include #include +#include #include #include +#include #include #if HAVE_NC_FREEALL #undef ExitProgram @@ -171,7 +181,7 @@ extern int optind; # elif defined(MAXPATHLEN) # define PATH_MAX MAXPATHLEN # else -# define PATH_MAX 255 /* the Posix minimum pathsize */ +# define PATH_MAX 255 /* the Posix minimum pathsize */ # endif #endif @@ -183,7 +193,7 @@ extern int optind; # if ('z'-'a' == 25) && ('z' < 127) && ('Z'-'A' == 25) && ('Z' < 127) && ('9' < 127) # define isascii(c) (UChar(c) <= 127) # else -# define isascii(c) 1 /* not really ascii anyway */ +# define isascii(c) 1 /* not really ascii anyway */ # endif #endif diff --git a/progs/tabs.c b/progs/tabs.c index b59c9086d8d3..7ed3007549d8 100644 --- a/progs/tabs.c +++ b/progs/tabs.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 2008-2009,2010 Free Software Foundation, Inc. * + * Copyright (c) 2008-2012,2013 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -37,12 +37,20 @@ #define USE_LIBTINFO #include -MODULE_ID("$Id: tabs.c,v 1.19 2010/10/23 22:26:01 tom Exp $") +MODULE_ID("$Id: tabs.c,v 1.34 2013/06/11 08:18:27 tom Exp $") static void usage(void) GCC_NORETURN; +static char *prg_name; static int max_cols; +static void +failed(const char *s) +{ + perror(s); + ExitProgram(EXIT_FAILURE); +} + static int putch(int c) { @@ -83,28 +91,29 @@ decode_tabs(const char *tab_list) int prior = 0; int ch; - if (result != 0) { - while ((ch = *tab_list++) != '\0') { - if (isdigit(UChar(ch))) { - value *= 10; - value += (ch - '0'); - } else if (ch == ',') { - result[n] = value + prior; - if (n > 0 && result[n] <= result[n - 1]) { - fprintf(stderr, - "tab-stops are not in increasing order: %d %d\n", - value, result[n - 1]); - free(result); - result = 0; - break; - } - ++n; - value = 0; - prior = 0; - } else if (ch == '+') { - if (n) - prior = result[n - 1]; + if (result == 0) + failed("decode_tabs"); + + while ((ch = *tab_list++) != '\0') { + if (isdigit(UChar(ch))) { + value *= 10; + value += (ch - '0'); + } else if (ch == ',') { + result[n] = value + prior; + if (n > 0 && result[n] <= result[n - 1]) { + fprintf(stderr, + "%s: tab-stops are not in increasing order: %d %d\n", + prg_name, value, result[n - 1]); + free(result); + result = 0; + break; } + ++n; + value = 0; + prior = 0; + } else if (ch == '+') { + if (n) + prior = result[n - 1]; } } @@ -114,6 +123,7 @@ decode_tabs(const char *tab_list) */ if ((n == 0) && (value > 0)) { int step = value; + value = 1; while (n < max_cols - 1) { result[n++] = value; value += step; @@ -126,6 +136,7 @@ decode_tabs(const char *tab_list) result[n++] = value + prior; result[n] = 0; } + return result; } @@ -140,10 +151,11 @@ print_ruler(int *tab_list) for (n = 0; n < max_cols; n += 10) { int ch = 1 + (n / 10); char buffer[20]; - sprintf(buffer, "----+----%c", - ((ch < 10) - ? (ch + '0') - : (ch + 'A' - 10))); + _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) + "----+----%c", + ((ch < 10) + ? (ch + '0') + : (ch + 'A' - 10))); printf("%.*s", ((max_cols - n) > 10) ? 10 : (max_cols - n), buffer); } putchar('\n'); @@ -227,7 +239,7 @@ comma_is_needed(const char *source) bool result = FALSE; if (source != 0) { - unsigned len = strlen(source); + size_t len = strlen(source); if (len != 0) result = (source[len - 1] != ','); } else { @@ -251,7 +263,7 @@ add_to_tab_list(char **append, const char *value) if (copied != 0 && *copied != '\0') { const char *comma = ","; - unsigned need = 1 + strlen(copied); + size_t need = 1 + strlen(copied); if (*copied == ',') comma = ""; @@ -263,15 +275,16 @@ add_to_tab_list(char **append, const char *value) need += strlen(*append); result = malloc(need); - if (result != 0) { - *result = '\0'; - if (*append != 0) { - strcpy(result, *append); - free(*append); - } - strcat(result, comma); - strcat(result, copied); + if (result == 0) + failed("add_to_tab_list"); + + *result = '\0'; + if (*append != 0) { + _nc_STRCPY(result, *append, need); + free(*append); } + _nc_STRCAT(result, comma, need); + _nc_STRCAT(result, copied, need); *append = result; } @@ -282,7 +295,7 @@ add_to_tab_list(char **append, const char *value) * Check for illegal characters in the tab-list. */ static bool -legal_tab_list(const char *program, const char *tab_list) +legal_tab_list(const char *tab_list) { bool result = TRUE; @@ -294,22 +307,34 @@ legal_tab_list(const char *program, const char *tab_list) if (!(isdigit(ch) || ch == ',' || ch == '+')) { fprintf(stderr, "%s: unexpected character found '%c'\n", - program, ch); + prg_name, ch); result = FALSE; break; } } } else { - fprintf(stderr, "%s: trailing comma found '%s'\n", program, tab_list); + fprintf(stderr, "%s: trailing comma found '%s'\n", prg_name, tab_list); result = FALSE; } } else { - fprintf(stderr, "%s: no tab-list given\n", program); + fprintf(stderr, "%s: no tab-list given\n", prg_name); result = FALSE; } return result; } +static char * +skip_list(char *value) +{ + while (*value != '\0' && + (isdigit(UChar(*value)) || + isspace(UChar(*value)) || + strchr("+,", UChar(*value)) != 0)) { + ++value; + } + return value; +} + static void usage(void) { @@ -332,6 +357,7 @@ usage(void) ," -s SNOBOL" ," -u UNIVAC 1100 Assembler" ," -T name use terminal type 'name'" + ," -V print version" ,"" ,"A tabstop-list is an ordered list of column numbers, e.g., 1,11,21" ,"or 1,+10,+10 which is the same." @@ -353,10 +379,11 @@ main(int argc, char *argv[]) bool no_op = FALSE; int n, ch; NCURSES_CONST char *term_name = 0; - const char *mar_list = 0; /* ignored */ char *append = 0; const char *tab_list = 0; + prg_name = _nc_rootname(argv[0]); + if ((term_name = getenv("TERM")) == 0) term_name = "ansi+tabs"; @@ -368,23 +395,25 @@ main(int argc, char *argv[]) while ((ch = *++option) != '\0') { switch (ch) { case 'a': - switch (*option) { + switch (*++option) { + default: case '\0': tab_list = "1,10,16,36,72"; + option--; /* Assembler, IBM S/370, first format */ break; case '2': tab_list = "1,10,16,40,72"; /* Assembler, IBM S/370, second format */ break; - default: - usage(); } break; case 'c': - switch (*option) { + switch (*++option) { + default: case '\0': tab_list = "1,8,12,16,20,55"; + option--; /* COBOL, normal format */ break; case '2': @@ -395,8 +424,6 @@ main(int argc, char *argv[]) tab_list = "1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67"; /* COBOL compact format extended */ break; - default: - usage(); } break; case 'd': /* ncurses extension */ @@ -427,17 +454,22 @@ main(int argc, char *argv[]) term_name = option; } else { term_name = argv[n++]; + option--; } option += ((int) strlen(option)) - 1; continue; + case 'V': + puts(curses_version()); + ExitProgram(EXIT_SUCCESS); default: if (isdigit(UChar(*option))) { - tab_list = option; - ++n; + char *copy = strdup(option); + *skip_list(copy) = '\0'; + tab_list = copy; + option = skip_list(option) - 1; } else { usage(); } - option += ((int) strlen(option)) - 1; break; } } @@ -446,7 +478,11 @@ main(int argc, char *argv[]) while ((ch = *++option) != '\0') { switch (ch) { case 'm': - mar_list = option; + /* + * The "+mXXX" option is unimplemented because only the long-obsolete + * att510d implements smgl, which is needed to support + * this option. + */ break; default: /* special case of relative stops separated by spaces? */ @@ -477,12 +513,12 @@ main(int argc, char *argv[]) if (!VALID_STRING(clear_all_tabs)) { fprintf(stderr, "%s: terminal type '%s' cannot reset tabs\n", - argv[0], term_name); + prg_name, term_name); } else if (!VALID_STRING(set_tab)) { fprintf(stderr, "%s: terminal type '%s' cannot set tabs\n", - argv[0], term_name); - } else if (legal_tab_list(argv[0], tab_list)) { + prg_name, term_name); + } else if (legal_tab_list(tab_list)) { int *list = decode_tabs(tab_list); if (!no_op) diff --git a/progs/tic.c b/progs/tic.c index 8e89095fc676..fef78ee0745e 100644 --- a/progs/tic.c +++ b/progs/tic.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2010,2011 Free Software Foundation, Inc. * + * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -35,6 +35,7 @@ /* * tic.c --- Main program for terminfo compiler * by Eric S. Raymond + * and Thomas E Dickey * */ @@ -42,9 +43,12 @@ #include #include +#include #include -MODULE_ID("$Id: tic.c,v 1.147 2011/02/12 18:39:08 tom Exp $") +MODULE_ID("$Id: tic.c,v 1.189 2013/11/16 19:58:09 tom Exp $") + +#define STDIN_NAME "" const char *_nc_progname = "tic"; @@ -53,6 +57,7 @@ static FILE *tmp_fp; static bool capdump = FALSE; /* running as infotocap? */ static bool infodump = FALSE; /* running as captoinfo? */ static bool showsummary = FALSE; +static char **namelst = 0; static const char *to_remove; static void (*save_check_termtype) (TERMTYPE *, bool); @@ -69,11 +74,13 @@ static const char usage_string[] = "\ 1\ a\ C\ +D\ c\ f\ G\ g\ I\ +K\ L\ N\ r\ @@ -99,8 +106,10 @@ free_namelist(char **src) #endif static void -cleanup(char **namelst GCC_UNUSED) +cleanup(void) { + int rc; + #if NO_LEAKS free_namelist(namelst); #endif @@ -108,10 +117,12 @@ cleanup(char **namelst GCC_UNUSED) fclose(tmp_fp); if (to_remove != 0) { #if HAVE_REMOVE - remove(to_remove); + rc = remove(to_remove); #else - unlink(to_remove); + rc = unlink(to_remove); #endif + if (rc != 0) + perror(to_remove); } } @@ -119,7 +130,6 @@ static void failed(const char *msg) { perror(msg); - cleanup((char **) 0); ExitProgram(EXIT_FAILURE); } @@ -133,7 +143,9 @@ usage(void) #if NCURSES_XNAMES " -a retain commented-out capabilities (sets -x also)", #endif + " -K translate entries to termcap source form with BSD syntax", " -C translate entries to termcap source form", + " -D print list of tic's database locations (first must be writable)", " -c check only, validate input without compiling or translating", " -e translate/compile only entries named by comma-separated list", " -f format complex strings for readability", @@ -173,7 +185,7 @@ usage(void) #define L_BRACE '{' #define R_BRACE '}' -#define S_QUOTE '\''; +#define S_QUOTE '\'' static void write_it(ENTRY * ep) @@ -216,12 +228,12 @@ write_it(ENTRY * ep) } *d = 0; if (strlen(result) < strlen(s)) - strcpy(s, result); + _nc_STRCPY(s, result, strlen(s) + 1); } } _nc_set_type(_nc_first_name(ep->tterm.term_names)); - _nc_curr_line = ep->startline; + _nc_curr_line = (int) ep->startline; _nc_write_entry(&ep->tterm); } @@ -286,8 +298,10 @@ put_translate(int c) if (in_name) { if (used + 1 >= have) { have += 132; - namebuf = typeRealloc(char, have, namebuf); - suffix = typeRealloc(char, have, suffix); + if ((namebuf = typeRealloc(char, have, namebuf)) == 0) + failed("put_translate namebuf"); + if ((suffix = typeRealloc(char, have, suffix)) == 0) + failed("put_translate suffix"); } if (c == '\n' || c == '@') { namebuf[used++] = '\0'; @@ -308,7 +322,7 @@ put_translate(int c) if ((up = strchr(namebuf, '#')) != 0 || (up = strchr(namebuf, '=')) != 0 || ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) { - (void) strcpy(suffix, up); + _nc_STRCPY(suffix, up, have); *up = '\0'; } @@ -339,39 +353,122 @@ put_translate(int c) static char * stripped(char *src) { + char *dst = 0; + while (isspace(UChar(*src))) src++; + if (*src != '\0') { - char *dst; size_t len; - if ((dst = strdup(src)) == NULL) + if ((dst = strdup(src)) == NULL) { failed("strdup"); + } else { + len = strlen(dst); + while (--len != 0 && isspace(UChar(dst[len]))) + dst[len] = '\0'; + } + } + return dst; +} - assert(dst != 0); +static FILE * +open_tempfile(char *filename) +{ + FILE *result = 0; - len = strlen(dst); - while (--len != 0 && isspace(UChar(dst[len]))) - dst[len] = '\0'; - return dst; + _nc_STRCPY(filename, "/tmp/XXXXXX", PATH_MAX); +#if HAVE_MKSTEMP + { + int oldmask = (int) umask(077); + int fd = mkstemp(filename); + if (fd >= 0) + result = fdopen(fd, "w"); + umask((mode_t) oldmask); } - return 0; +#else + if (tmpnam(filename) != 0) + result = fopen(filename, "w"); +#endif + return result; } static FILE * -open_input(const char *filename) +copy_input(FILE *source, const char *filename, char *alt_file) { - FILE *fp = fopen(filename, "r"); + char my_altfile[PATH_MAX]; + FILE *result = 0; + FILE *target = 0; + int ch; + + if (alt_file == 0) + alt_file = my_altfile; + + if (source == 0) { + failed("copy_input (source)"); + } else if ((target = open_tempfile(alt_file)) == 0) { + failed("copy_input (target)"); + } else { + clearerr(source); + for (;;) { + ch = fgetc(source); + if (feof(source)) { + break; + } else if (ferror(source)) { + failed(filename); + } else if (ch == 0) { + /* don't loop in case someone wants to convert /dev/zero */ + fprintf(stderr, "%s: %s is not a text-file\n", _nc_progname, filename); + ExitProgram(EXIT_FAILURE); + } + fputc(ch, target); + } + fclose(source); + /* + * rewind() does not force the target file's data to disk (not does + * fflush()...). So open a second stream on the data and then close + * the one that we were writing on before starting to read from the + * second stream. + */ + result = fopen(alt_file, "r+"); + fclose(target); + to_remove = strdup(alt_file); + } + return result; +} + +static FILE * +open_input(const char *filename, char *alt_file) +{ + FILE *fp; struct stat sb; + int mode; - if (fp == 0) { - fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename); + if (!strcmp(filename, "-")) { + fp = copy_input(stdin, STDIN_NAME, alt_file); + } else if (stat(filename, &sb) < 0) { + fprintf(stderr, "%s: %s %s\n", _nc_progname, filename, strerror(errno)); ExitProgram(EXIT_FAILURE); - } - if (fstat(fileno(fp), &sb) < 0 - || (sb.st_mode & S_IFMT) != S_IFREG) { + } else if ((mode = (sb.st_mode & S_IFMT)) == S_IFDIR + || (mode != S_IFREG && mode != S_IFCHR)) { fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename); ExitProgram(EXIT_FAILURE); + } else { + fp = fopen(filename, "r"); + + if (fp == 0) { + fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename); + ExitProgram(EXIT_FAILURE); + } + if (mode != S_IFREG) { + if (alt_file != 0) { + FILE *fp2 = copy_input(fp, filename, alt_file); + fp = fp2; + } else { + fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename); + ExitProgram(EXIT_FAILURE); + } + } } return fp; } @@ -389,7 +486,7 @@ make_namelist(char *src) if (src == 0) { /* EMPTY */ ; } else if (strchr(src, '/') != 0) { /* a filename */ - FILE *fp = open_input(src); + FILE *fp = open_input(src, (char *) 0); for (pass = 1; pass <= 2; pass++) { nn = 0; @@ -403,7 +500,8 @@ make_namelist(char *src) } } if (pass == 1) { - dst = typeCalloc(char *, nn + 1); + if ((dst = typeCalloc(char *, nn + 1)) == 0) + failed("make_namelist"); rewind(fp); } } @@ -425,8 +523,10 @@ make_namelist(char *src) if (mark == '\0') break; } - if (pass == 1) - dst = typeCalloc(char *, nn + 1); + if (pass == 1) { + if ((dst = typeCalloc(char *, nn + 1)) == 0) + failed("make_namelist"); + } } } if (showsummary && (dst != 0)) { @@ -456,26 +556,118 @@ matches(char **needle, const char *haystack) return (code); } -static FILE * -open_tempfile(char *name) +static char * +valid_db_path(const char *nominal) { - FILE *result = 0; -#if HAVE_MKSTEMP - int fd = mkstemp(name); - if (fd >= 0) - result = fdopen(fd, "w"); + struct stat sb; +#if USE_HASHED_DB + char suffix[] = DBM_SUFFIX; + size_t need = strlen(nominal) + sizeof(suffix); + char *result = malloc(need); + + if (result == 0) + failed("valid_db_path"); + _nc_STRCPY(result, nominal, need); + if (strcmp(result + need - sizeof(suffix), suffix)) { + _nc_STRCAT(result, suffix, need); + } #else - if (tmpnam(name) != 0) - result = fopen(name, "w"); + char *result = strdup(nominal); #endif + + DEBUG(1, ("** stat(%s)", result)); + if (stat(result, &sb) >= 0) { +#if USE_HASHED_DB + if (!S_ISREG(sb.st_mode) + || access(result, R_OK | W_OK) != 0) { + DEBUG(1, ("...not a writable file")); + free(result); + result = 0; + } +#else + if (!S_ISDIR(sb.st_mode) + || access(result, R_OK | W_OK | X_OK) != 0) { + DEBUG(1, ("...not a writable directory")); + free(result); + result = 0; + } +#endif + } else { + /* check if parent is directory and is writable */ + unsigned leaf = _nc_pathlast(result); + + DEBUG(1, ("...not found")); + if (leaf) { + char save = result[leaf]; + result[leaf] = 0; + if (stat(result, &sb) >= 0 + && S_ISDIR(sb.st_mode) + && access(result, R_OK | W_OK | X_OK) == 0) { + result[leaf] = save; + } else { + DEBUG(1, ("...parent directory %s is not writable", result)); + free(result); + result = 0; + } + } else { + DEBUG(1, ("... no parent directory")); + free(result); + result = 0; + } + } return result; } +/* + * Show the databases to which tic could write. The location to which it + * writes is always the first one. If none are writable, print an error + * message. + */ +static void +show_databases(const char *outdir) +{ + bool specific = (outdir != 0) || getenv("TERMINFO") != 0; + char *result; + const char *tried = 0; + + if (outdir == 0) { + outdir = _nc_tic_dir(0); + } + if ((result = valid_db_path(outdir)) != 0) { + printf("%s\n", result); + free(result); + } else { + tried = outdir; + } + + if ((outdir = _nc_home_terminfo())) { + if ((result = valid_db_path(outdir)) != 0) { + printf("%s\n", result); + free(result); + } else if (!specific) { + tried = outdir; + } + } + + /* + * If we can write in neither location, give an error message. + */ + if (tried) { + fflush(stdout); + fprintf(stderr, "%s: %s (no permission)\n", _nc_progname, tried); + ExitProgram(EXIT_FAILURE); + } +} + +#define VtoTrace(opt) (unsigned) ((opt > 0) ? opt : (opt == 0)) + int main(int argc, char *argv[]) { char my_tmpname[PATH_MAX]; - int v_opt = -1, debug_level; + char my_altfile[PATH_MAX]; + int v_opt = -1; + unsigned debug_level; int smart_defaults = TRUE; char *termcap; ENTRY *qp; @@ -486,6 +678,7 @@ main(int argc, char *argv[]) int sortmode = S_TERMINFO; /* sort_mode */ int width = 60; + int height = 65535; bool formatted = FALSE; /* reformat complex strings? */ bool literal = FALSE; /* suppress post-processing? */ int numbers = 0; /* format "%'char'" to/from "%{number}" */ @@ -493,7 +686,6 @@ main(int argc, char *argv[]) bool limited = TRUE; char *tversion = (char *) NULL; const char *source_file = "terminfo"; - char **namelst = 0; char *outdir = (char *) NULL; bool check_only = FALSE; bool suppress_untranslatable = FALSE; @@ -501,6 +693,7 @@ main(int argc, char *argv[]) log_fp = stderr; _nc_progname = _nc_rootname(argv[0]); + atexit(cleanup); if ((infodump = same_program(_nc_progname, PROG_CAPTOINFO)) != FALSE) { outform = F_TERMINFO; @@ -513,6 +706,7 @@ main(int argc, char *argv[]) #if NCURSES_XNAMES use_extended_names(FALSE); #endif + _nc_strict_bsd = 0; /* * Processing arguments is a little complicated, since someone made a @@ -520,7 +714,7 @@ main(int argc, char *argv[]) * be optional. */ while ((this_opt = getopt(argc, argv, - "0123456789CILNR:TUVace:fGgo:rstvwx")) != -1) { + "0123456789CDIKLNR:TUVace:fGgo:rstvwx")) != -1) { if (isdigit(this_opt)) { switch (last_opt) { case 'v': @@ -530,19 +724,40 @@ main(int argc, char *argv[]) width = (width * 10) + (this_opt - '0'); break; default: - if (this_opt != '1') + switch (this_opt) { + case '0': + last_opt = this_opt; + width = 65535; + height = 1; + break; + case '1': + last_opt = this_opt; + width = 0; + break; + default: usage(); - last_opt = this_opt; - width = 0; + } } continue; } switch (this_opt) { + case 'K': + _nc_strict_bsd = 1; + /* the initial version of -K in 20110730 fell-thru here, but the + * same flag is useful when reading sources -TD + */ + break; case 'C': capdump = TRUE; outform = F_TERMCAP; sortmode = S_TERMCAP; break; + case 'D': + debug_level = VtoTrace(v_opt); + set_trace_level(debug_level); + show_databases(outdir); + ExitProgram(EXIT_SUCCESS); + break; case 'I': infodump = TRUE; outform = F_TERMINFO; @@ -568,7 +783,6 @@ main(int argc, char *argv[]) break; case 'V': puts(curses_version()); - cleanup(namelst); ExitProgram(EXIT_SUCCESS); case 'c': check_only = TRUE; @@ -618,7 +832,7 @@ main(int argc, char *argv[]) last_opt = this_opt; } - debug_level = (v_opt > 0) ? v_opt : (v_opt == 0); + debug_level = VtoTrace(v_opt); set_trace_level(debug_level); if (_nc_tracing) { @@ -638,8 +852,8 @@ main(int argc, char *argv[]) */ if (namelst && (!infodump && !capdump)) { (void) fprintf(stderr, - "Sorry, -e can't be used without -I or -C\n"); - cleanup(namelst); + "%s: Sorry, -e can't be used without -I or -C\n", + _nc_progname); ExitProgram(EXIT_FAILURE); } #endif /* HAVE_BIG_CORE */ @@ -663,16 +877,16 @@ main(int argc, char *argv[]) if (access(termcap, F_OK) == 0) { /* file exists */ source_file = termcap; - } else if ((tmp_fp = open_tempfile(strcpy(my_tmpname, - "/tmp/XXXXXX"))) - != 0) { - source_file = my_tmpname; - fprintf(tmp_fp, "%s\n", termcap); - fclose(tmp_fp); - tmp_fp = open_input(source_file); - to_remove = source_file; } else { - failed("tmpnam"); + if ((tmp_fp = open_tempfile(my_tmpname)) != 0) { + source_file = my_tmpname; + fprintf(tmp_fp, "%s\n", termcap); + fclose(tmp_fp); + tmp_fp = open_input(source_file, (char *) 0); + to_remove = source_file; + } else { + failed("tmpnam"); + } } } } else { @@ -682,24 +896,28 @@ main(int argc, char *argv[]) _nc_progname, _nc_progname, usage_string); - cleanup(namelst); ExitProgram(EXIT_FAILURE); } } - if (tmp_fp == 0) - tmp_fp = open_input(source_file); + if (tmp_fp == 0) { + tmp_fp = open_input(source_file, my_altfile); + if (!strcmp(source_file, "-")) { + source_file = STDIN_NAME; + } + } - if (infodump) + if (infodump) { dump_init(tversion, smart_defaults ? outform : F_LITERAL, - sortmode, width, debug_level, formatted); - else if (capdump) + sortmode, width, height, debug_level, formatted); + } else if (capdump) { dump_init(tversion, outform, - sortmode, width, debug_level, FALSE); + sortmode, width, height, debug_level, FALSE); + } /* parse entries out of the source file */ _nc_set_source(source_file); @@ -716,7 +934,6 @@ main(int argc, char *argv[]) /* do use resolution */ if (check_only || (!infodump && !capdump) || forceresolve) { if (!_nc_resolve_uses2(TRUE, literal) && !check_only) { - cleanup(namelst); ExitProgram(EXIT_FAILURE); } } @@ -750,7 +967,7 @@ main(int argc, char *argv[]) for_entry_list(qp) { if (matches(namelst, qp->tterm.term_names)) { - int j = qp->cend - qp->cstart; + long j = qp->cend - qp->cstart; int len = 0; /* this is in case infotocap() generates warnings */ @@ -767,7 +984,7 @@ main(int argc, char *argv[]) repair_acsc(&qp->tterm); dump_entry(&qp->tterm, suppress_untranslatable, limited, numbers, NULL); - for (j = 0; j < (int) qp->nuses; j++) + for (j = 0; j < (long) qp->nuses; j++) dump_uses(qp->uses[j].name, !capdump); len = show_entry(); if (debug_level != 0 && !limited) @@ -811,7 +1028,6 @@ main(int argc, char *argv[]) else fprintf(log_fp, "No entries written\n"); } - cleanup(namelst); ExitProgram(EXIT_SUCCESS); } @@ -915,18 +1131,18 @@ keypad_final(const char *string) return result; } -static int +static long keypad_index(const char *string) { char *test; const char *list = "PQRSwxymtuvlqrsPpn"; /* app-keypad except "Enter" */ int ch; - int result = -1; + long result = -1; if ((ch = keypad_final(string)) != '\0') { - test = strchr(list, ch); + test = (strchr) (list, ch); if (test != 0) - result = (test - list); + result = (long) (test - list); } return result; } @@ -1008,6 +1224,19 @@ check_ansi_cursor(char *list[4]) } #define EXPECTED(name) if (!PRESENT(name)) _nc_warning("expected " #name) +#define UNEXPECTED(name) if (PRESENT(name)) _nc_warning("unexpected " #name ", for %s", why) + +static void +check_noaddress(TERMTYPE *tp, const char *why) +{ + UNEXPECTED(column_address); + UNEXPECTED(cursor_address); + UNEXPECTED(cursor_home); + UNEXPECTED(cursor_mem_address); + UNEXPECTED(cursor_to_ll); + UNEXPECTED(row_address); + UNEXPECTED(row_address); +} static void check_cursor(TERMTYPE *tp) @@ -1015,13 +1244,55 @@ check_cursor(TERMTYPE *tp) int count; char *list[4]; + if (hard_copy) { + check_noaddress(tp, "hard_copy"); + } else if (generic_type) { + check_noaddress(tp, "generic_type"); + } else if (strchr(tp->term_names, '+') == 0) { + int y = 0; + int x = 0; + if (PRESENT(column_address)) + ++y; + if (PRESENT(cursor_address)) + y = x = 10; + if (PRESENT(cursor_home)) + ++y, ++x; + if (PRESENT(cursor_mem_address)) + y = x = 10; + if (PRESENT(cursor_to_ll)) + ++y, ++x; + if (PRESENT(row_address)) + ++x; + if (PRESENT(cursor_down)) + ++y; + if (PRESENT(cursor_up)) + ++y; + if (PRESENT(cursor_left)) + ++x; + if (PRESENT(cursor_right)) + ++x; + if (x < 2 && y < 2) { + _nc_warning("terminal lacks cursor addressing"); + } else { + if (x < 2) + _nc_warning("terminal lacks cursor column-addressing"); + if (y < 2) + _nc_warning("terminal lacks cursor row-addressing"); + } + } + + /* it is rare to have an insert-line feature without a matching delete */ + ANDMISSING(parm_insert_line, insert_line); + ANDMISSING(parm_delete_line, delete_line); + ANDMISSING(parm_insert_line, parm_delete_line); + /* if we have a parameterized form, then the non-parameterized is easy */ ANDMISSING(parm_down_cursor, cursor_down); ANDMISSING(parm_up_cursor, cursor_up); ANDMISSING(parm_left_cursor, cursor_left); ANDMISSING(parm_right_cursor, cursor_right); - /* Given any of a set of cursor movement, the whole set should be present. + /* Given any of a set of cursor movement, the whole set should be present. * Technically this is not true (we could use cursor_address to fill in * unsupported controls), but it is likely. */ @@ -1097,11 +1368,11 @@ check_keypad(TERMTYPE *tp) VALID_STRING(key_c1) && VALID_STRING(key_c3)) { char final[MAX_KP + 1]; - int list[MAX_KP]; + long list[MAX_KP]; int increase = 0; int j, k, kk; - int last; - int test; + long last; + long test; final[0] = keypad_final(key_a1); final[1] = keypad_final(key_a3); @@ -1149,19 +1420,19 @@ check_keypad(TERMTYPE *tp) assert(strlen(show) < (MAX_KP * 4)); switch (kk) { case 0: - strcat(show, " ka1"); + _nc_STRCAT(show, " ka1", sizeof(show)); break; case 1: - strcat(show, " ka3"); + _nc_STRCAT(show, " ka3", sizeof(show)); break; case 2: - strcat(show, " kb2"); + _nc_STRCAT(show, " kb2", sizeof(show)); break; case 3: - strcat(show, " kc1"); + _nc_STRCAT(show, " kc1", sizeof(show)); break; case 4: - strcat(show, " kc3"); + _nc_STRCAT(show, " kc3", sizeof(show)); break; } } @@ -1176,18 +1447,24 @@ check_keypad(TERMTYPE *tp) VALID_STRING(key_c3)) { show[0] = '\0'; if (keypad_index(key_a1) >= 0) - strcat(show, " ka1"); + _nc_STRCAT(show, " ka1", sizeof(show)); if (keypad_index(key_a3) >= 0) - strcat(show, " ka3"); + _nc_STRCAT(show, " ka3", sizeof(show)); if (keypad_index(key_b2) >= 0) - strcat(show, " kb2"); + _nc_STRCAT(show, " kb2", sizeof(show)); if (keypad_index(key_c1) >= 0) - strcat(show, " kc1"); + _nc_STRCAT(show, " kc1", sizeof(show)); if (keypad_index(key_c3) >= 0) - strcat(show, " kc3"); + _nc_STRCAT(show, " kc3", sizeof(show)); if (*show != '\0') _nc_warning("vt100 keypad map incomplete:%s", show); } + + /* + * These warnings are useful for consistency checks - it is possible that + * there are real terminals with mismatches in these + */ + ANDMISSING(key_ic, key_dc); } static void @@ -1216,6 +1493,74 @@ check_printer(TERMTYPE *tp) ANDMISSING(parm_up_micro, micro_up); } +static bool +uses_SGR_39_49(const char *value) +{ + return (strstr(value, "39;49") != 0 + || strstr(value, "49;39") != 0); +} + +/* + * Check consistency of termcap extensions related to "screen". + */ +static void +check_screen(TERMTYPE *tp) +{ +#if NCURSES_XNAMES + if (_nc_user_definable) { + int have_XT = tigetflag("XT"); + int have_XM = tigetflag("XM"); + int have_bce = back_color_erase; + bool have_kmouse = FALSE; + bool use_sgr_39_49 = FALSE; + char *name = _nc_first_name(tp->term_names); + + if (!VALID_BOOLEAN(have_bce)) { + have_bce = FALSE; + } + if (!VALID_BOOLEAN(have_XM)) { + have_XM = FALSE; + } + if (!VALID_BOOLEAN(have_XT)) { + have_XT = FALSE; + } + if (VALID_STRING(key_mouse)) { + have_kmouse = !strcmp("\033[M", key_mouse); + } + if (VALID_STRING(orig_colors)) { + use_sgr_39_49 = uses_SGR_39_49(orig_colors); + } else if (VALID_STRING(orig_pair)) { + use_sgr_39_49 = uses_SGR_39_49(orig_pair); + } + + if (have_XM && have_XT) { + _nc_warning("Screen's XT capability conflicts with XM"); + } else if (have_XT + && strstr(name, "screen") != 0 + && strchr(name, '.') != 0) { + _nc_warning("Screen's \"screen\" entries should not have XT set"); + } else if (have_XT) { + if (!have_kmouse && have_bce) { + if (VALID_STRING(key_mouse)) { + _nc_warning("Value of kmous inconsistent with screen's usage"); + } else { + _nc_warning("Expected kmous capability with XT"); + } + } + if (!have_bce && max_colors > 0) + _nc_warning("Expected bce capability with XT"); + if (!use_sgr_39_49 && have_bce && max_colors > 0) + _nc_warning("Expected orig_colors capability with XT to have 39/49 parameters"); + if (VALID_STRING(to_status_line)) + _nc_warning("\"tsl\" capability is redundant, given XT"); + } else { + if (have_kmouse && !have_XM) + _nc_warning("Expected XT to be set, given kmous"); + } + } +#endif +} + /* * Returns the expected number of parameters for the given capability. */ @@ -1527,7 +1872,7 @@ static void show_where(unsigned level) { if (_nc_tracing >= DEBUG_LEVEL(level)) { - char my_name[256]; + char my_name[MAX_NAME_SIZE]; _nc_get_type(my_name); _tracef("\"%s\", line %d, '%s'", _nc_get_source(), @@ -1539,6 +1884,58 @@ show_where(unsigned level) #define show_where(level) /* nothing */ #endif +typedef struct { + int keycode; + const char *name; + const char *value; +} NAME_VALUE; + +static NAME_VALUE * +get_fkey_list(TERMTYPE *tp) +{ + NAME_VALUE *result = typeMalloc(NAME_VALUE, NUM_STRINGS(tp) + 1); + const struct tinfo_fkeys *all_fkeys = _nc_tinfo_fkeys; + int used = 0; + int j; + + if (result == 0) + failed("get_fkey_list"); + + for (j = 0; all_fkeys[j].code; j++) { + char *a = tp->Strings[all_fkeys[j].offset]; + if (VALID_STRING(a)) { + result[used].keycode = (int) all_fkeys[j].code; + result[used].name = strnames[all_fkeys[j].offset]; + result[used].value = a; + ++used; + } + } +#if NCURSES_XNAMES + for (j = STRCOUNT; j < NUM_STRINGS(tp); ++j) { + const char *name = ExtStrname(tp, j, strnames); + if (*name == 'k') { + result[used].keycode = -1; + result[used].name = name; + result[used].value = tp->Strings[j]; + ++used; + } + } +#endif + result[used].keycode = 0; + return result; +} + +static void +show_fkey_name(NAME_VALUE * data) +{ + if (data->keycode > 0) { + fprintf(stderr, " %s", keyname(data->keycode)); + fprintf(stderr, " (capability \"%s\")", data->name); + } else { + fprintf(stderr, " capability \"%s\"", data->name); + } +} + /* other sanity-checks (things that we don't want in the normal * logic that reads a terminfo entry) */ @@ -1547,7 +1944,6 @@ check_termtype(TERMTYPE *tp, bool literal) { bool conflict = FALSE; unsigned j, k; - char fkeys[STRCOUNT]; /* * A terminal entry may contain more than one keycode assigned to @@ -1555,44 +1951,50 @@ check_termtype(TERMTYPE *tp, bool literal) * return one (the last one assigned). */ if (!(_nc_syntax == SYN_TERMCAP && capdump)) { - memset(fkeys, 0, sizeof(fkeys)); - for (j = 0; _nc_tinfo_fkeys[j].code; j++) { - char *a = tp->Strings[_nc_tinfo_fkeys[j].offset]; + char *check = calloc((size_t) (NUM_STRINGS(tp) + 1), sizeof(char)); + NAME_VALUE *given = get_fkey_list(tp); + + if (check == 0) + failed("check_termtype"); + + for (j = 0; given[j].keycode; ++j) { + const char *a = given[j].value; bool first = TRUE; - if (!VALID_STRING(a)) - continue; - for (k = j + 1; _nc_tinfo_fkeys[k].code; k++) { - char *b = tp->Strings[_nc_tinfo_fkeys[k].offset]; - if (!VALID_STRING(b) - || fkeys[k]) + + for (k = j + 1; given[k].keycode; k++) { + const char *b = given[k].value; + if (check[k]) continue; if (!_nc_capcmp(a, b)) { - fkeys[j] = 1; - fkeys[k] = 1; + check[j] = 1; + check[k] = 1; if (first) { if (!conflict) { _nc_warning("Conflicting key definitions (using the last)"); conflict = TRUE; } - fprintf(stderr, "... %s is the same as %s", - keyname((int) _nc_tinfo_fkeys[j].code), - keyname((int) _nc_tinfo_fkeys[k].code)); + fprintf(stderr, "..."); + show_fkey_name(given + j); + fprintf(stderr, " is the same as"); + show_fkey_name(given + k); first = FALSE; } else { - fprintf(stderr, ", %s", - keyname((int) _nc_tinfo_fkeys[k].code)); + fprintf(stderr, ", "); + show_fkey_name(given + k); } } } if (!first) fprintf(stderr, "\n"); } + free(given); + free(check); } - for (j = 0; j < NUM_STRINGS(tp); j++) { + for_each_string(j, tp) { char *a = tp->Strings[j]; if (VALID_STRING(a)) - check_params(tp, ExtStrname(tp, j, strnames), a); + check_params(tp, ExtStrname(tp, (int) j, strnames), a); } check_acs(tp); @@ -1600,6 +2002,7 @@ check_termtype(TERMTYPE *tp, bool literal) check_cursor(tp); check_keypad(tp); check_printer(tp); + check_screen(tp); /* * These may be mismatched because the terminal description relies on diff --git a/progs/toe.c b/progs/toe.c index 6f45992f7124..0d299b457dfb 100644 --- a/progs/toe.c +++ b/progs/toe.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2008,2010 Free Software Foundation, Inc. * + * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -44,12 +44,23 @@ #include #endif -MODULE_ID("$Id: toe.c,v 1.52 2010/05/01 22:04:08 tom Exp $") +MODULE_ID("$Id: toe.c,v 1.74 2013/12/15 01:08:28 tom Exp $") #define isDotname(name) (!strcmp(name, ".") || !strcmp(name, "..")) +typedef struct { + int db_index; + unsigned long checksum; + char *term_name; + char *description; +} TERMDATA; + const char *_nc_progname; +static TERMDATA *ptr_termdata; /* array of terminal data */ +static size_t use_termdata; /* actual usage in ptr_termdata[] */ +static size_t len_termdata; /* allocated size of ptr_termdata[] */ + #if NO_LEAKS #undef ExitProgram static void ExitProgram(int code) GCC_NORETURN; @@ -61,6 +72,8 @@ ExitProgram(int code) } #endif +static void failed(const char *) GCC_NORETURN; + static void failed(const char *msg) { @@ -68,6 +81,150 @@ failed(const char *msg) ExitProgram(EXIT_FAILURE); } +static char * +strmalloc(const char *value) +{ + char *result = strdup(value); + if (result == 0) { + failed("strmalloc"); + } + return result; +} + +static TERMDATA * +new_termdata(void) +{ + size_t want = use_termdata + 1; + + if (want >= len_termdata) { + len_termdata = (2 * want) + 10; + ptr_termdata = typeRealloc(TERMDATA, len_termdata, ptr_termdata); + if (ptr_termdata == 0) + failed("ptr_termdata"); + } + + return ptr_termdata + use_termdata++; +} + +static int +compare_termdata(const void *a, const void *b) +{ + const TERMDATA *p = (const TERMDATA *) a; + const TERMDATA *q = (const TERMDATA *) b; + int result = strcmp(p->term_name, q->term_name); + + if (result == 0) { + result = (p->db_index - q->db_index); + } + return result; +} + +/* + * Sort the array of TERMDATA and print it. If more than one database is being + * reported, add a column to show which database has a given entry. + */ +static void +show_termdata(int eargc, char **eargv) +{ + int j, k; + size_t n; + + if (use_termdata) { + if (eargc > 1) { + for (j = 0; j < eargc; ++j) { + for (k = 0; k <= j; ++k) { + printf("--"); + } + printf("> "); + printf("%s\n", eargv[j]); + } + } + if (use_termdata > 1) + qsort(ptr_termdata, use_termdata, sizeof(TERMDATA), compare_termdata); + for (n = 0; n < use_termdata; ++n) { + + /* + * If there is more than one database, show how they differ. + */ + if (eargc > 1) { + unsigned long check = 0; + k = 0; + for (;;) { + for (; k < ptr_termdata[n].db_index; ++k) { + printf("--"); + } + + /* + * If this is the first entry, or its checksum differs + * from the first entry's checksum, print "*". Otherwise + * it looks enough like a duplicate to print "+". + */ + printf("%c-", ((check == 0 + || (check != ptr_termdata[n].checksum)) + ? '*' + : '+')); + check = ptr_termdata[n].checksum; + + ++k; + if ((n + 1) >= use_termdata + || strcmp(ptr_termdata[n].term_name, + ptr_termdata[n + 1].term_name)) { + break; + } + ++n; + } + for (; k < eargc; ++k) { + printf("--"); + } + printf(":\t"); + } + + (void) printf("%-10s\t%s\n", + ptr_termdata[n].term_name, + ptr_termdata[n].description); + } + } +} + +static void +free_termdata(void) +{ + if (ptr_termdata != 0) { + while (use_termdata != 0) { + --use_termdata; + free(ptr_termdata[use_termdata].term_name); + free(ptr_termdata[use_termdata].description); + } + free(ptr_termdata); + ptr_termdata = 0; + } + use_termdata = 0; + len_termdata = 0; +} + +static char ** +allocArgv(size_t count) +{ + char **result = typeCalloc(char *, count + 1); + if (result == 0) + failed("realloc eargv"); + + assert(result != 0); + return result; +} + +static void +freeArgv(char **argv) +{ + if (argv) { + int count = 0; + while (argv[count]) { + free(argv[count++]); + } + free(argv); + } +} + #if USE_HASHED_DB static bool make_db_name(char *dst, const char *src, unsigned limit) @@ -75,67 +232,100 @@ make_db_name(char *dst, const char *src, unsigned limit) static const char suffix[] = DBM_SUFFIX; bool result = FALSE; - unsigned lens = sizeof(suffix) - 1; - unsigned size = strlen(src); - unsigned need = lens + size; + size_t lens = sizeof(suffix) - 1; + size_t size = strlen(src); + size_t need = lens + size; if (need <= limit) { if (size >= lens - && !strcmp(src + size - lens, suffix)) - (void) strcpy(dst, src); - else - (void) sprintf(dst, "%s%s", src, suffix); + && !strcmp(src + size - lens, suffix)) { + _nc_STRCPY(dst, src, PATH_MAX); + } else { + _nc_SPRINTF(dst, _nc_SLIMIT(PATH_MAX) "%s%s", src, suffix); + } result = TRUE; } return result; } #endif -static bool -is_database(const char *path) +typedef void (DescHook) (int /* db_index */ , + int /* db_limit */ , + const char * /* term_name */ , + TERMTYPE * /* term */ ); + +static const char * +term_description(TERMTYPE *tp) { - bool result = FALSE; -#if USE_DATABASE - if (_nc_is_dir_path(path) && access(path, R_OK | X_OK) == 0) { - result = TRUE; - } -#endif -#if USE_TERMCAP - if (_nc_is_file_path(path) && access(path, R_OK) == 0) { - result = TRUE; + const char *desc; + + if (tp->term_names == 0 + || (desc = strrchr(tp->term_names, '|')) == 0 + || (*++desc == '\0')) { + desc = "(No description)"; } -#endif -#if USE_HASHED_DB - if (!result) { - char filename[PATH_MAX]; - if (_nc_is_file_path(path) && access(path, R_OK) == 0) { - result = TRUE; - } else if (make_db_name(filename, path, sizeof(filename))) { - if (_nc_is_file_path(filename) && access(filename, R_OK) == 0) { - result = TRUE; - } + + return desc; +} + +/* display a description for the type */ +static void +deschook(int db_index, int db_limit, const char *term_name, TERMTYPE *tp) +{ + (void) db_index; + (void) db_limit; + (void) printf("%-10s\t%s\n", term_name, term_description(tp)); +} + +static unsigned long +string_sum(const char *value) +{ + unsigned long result = 0; + + if ((intptr_t) value == (intptr_t) (-1)) { + result = ~result; + } else if (value) { + while (*value) { + result += UChar(*value); + ++value; } } -#endif return result; } -static void -deschook(const char *cn, TERMTYPE *tp) -/* display a description for the type */ +static unsigned long +checksum_of(TERMTYPE *tp) { - const char *desc; + unsigned long result = string_sum(tp->term_names); + unsigned i; - if ((desc = strrchr(tp->term_names, '|')) == 0 || *++desc == '\0') - desc = "(No description)"; + for (i = 0; i < NUM_BOOLEANS(tp); i++) { + result += (unsigned long) (tp->Booleans[i]); + } + for (i = 0; i < NUM_NUMBERS(tp); i++) { + result += (unsigned long) (tp->Numbers[i]); + } + for (i = 0; i < NUM_STRINGS(tp); i++) { + result += string_sum(tp->Strings[i]); + } + return result; +} + +/* collect data, to sort before display */ +static void +sorthook(int db_index, int db_limit, const char *term_name, TERMTYPE *tp) +{ + TERMDATA *data = new_termdata(); - (void) printf("%-10s\t%s\n", cn, desc); + data->db_index = db_index; + data->checksum = ((db_limit > 1) ? checksum_of(tp) : 0); + data->term_name = strmalloc(term_name); + data->description = strmalloc(term_description(tp)); } -#if USE_TERMCAP +#if NCURSES_USE_TERMCAP static void -show_termcap(char *buffer, - void (*hook) (const char *, TERMTYPE *tp)) +show_termcap(int db_index, int db_limit, char *buffer, DescHook hook) { TERMTYPE data; char *next = strchr(buffer, ':'); @@ -149,26 +339,42 @@ show_termcap(char *buffer, if (last) ++last; - data.term_names = strdup(buffer); + memset(&data, 0, sizeof(data)); + data.term_names = strmalloc(buffer); while ((next = strtok(list, "|")) != 0) { if (next != last) - hook(next, &data); + hook(db_index, db_limit, next, &data); list = 0; } free(data.term_names); } #endif +#if NCURSES_USE_DATABASE +static char * +copy_entryname(DIRENT * src) +{ + size_t len = NAMLEN(src); + char *result = malloc(len + 1); + if (result == 0) + failed("copy entryname"); + memcpy(result, src->d_name, len); + result[len] = '\0'; + + return result; +} +#endif + static int typelist(int eargc, char *eargv[], - bool verbosity, - void (*hook) (const char *, TERMTYPE *tp)) + int verbosity, + DescHook hook) /* apply a function to each entry in given terminfo directories */ { int i; for (i = 0; i < eargc; i++) { -#if USE_DATABASE +#if NCURSES_USE_DATABASE if (_nc_is_dir_path(eargv[i])) { char *cwd_buf = 0; DIR *termdir; @@ -179,28 +385,35 @@ typelist(int eargc, char *eargv[], (void) fprintf(stderr, "%s: can't open terminfo directory %s\n", _nc_progname, eargv[i]); - return (EXIT_FAILURE); - } else if (verbosity) + continue; + } + + if (verbosity) (void) printf("#\n#%s:\n#\n", eargv[i]); while ((subdir = readdir(termdir)) != 0) { - size_t len = NAMLEN(subdir); - size_t cwd_len = len + strlen(eargv[i]) + 3; - char name_1[PATH_MAX]; + size_t cwd_len; + char *name_1; DIR *entrydir; DIRENT *entry; + name_1 = copy_entryname(subdir); + if (isDotname(name_1)) { + free(name_1); + continue; + } + + cwd_len = NAMLEN(subdir) + strlen(eargv[i]) + 3; cwd_buf = typeRealloc(char, cwd_len, cwd_buf); if (cwd_buf == 0) failed("realloc cwd_buf"); assert(cwd_buf != 0); - strncpy(name_1, subdir->d_name, len)[len] = '\0'; - if (isDotname(name_1)) - continue; + _nc_SPRINTF(cwd_buf, _nc_SLIMIT(cwd_len) + "%s/%s/", eargv[i], name_1); + free(name_1); - (void) sprintf(cwd_buf, "%s/%.*s/", eargv[i], (int) len, name_1); if (chdir(cwd_buf) != 0) continue; @@ -210,15 +423,16 @@ typelist(int eargc, char *eargv[], continue; } while ((entry = readdir(entrydir)) != 0) { - char name_2[PATH_MAX]; + char *name_2; TERMTYPE lterm; char *cn; int status; - len = NAMLEN(entry); - strncpy(name_2, entry->d_name, len)[len] = '\0'; - if (isDotname(name_2) || !_nc_is_file_path(name_2)) + name_2 = copy_entryname(entry); + if (isDotname(name_2) || !_nc_is_file_path(name_2)) { + free(name_2); continue; + } status = _nc_read_file_entry(name_2, <erm); if (status <= 0) { @@ -226,6 +440,10 @@ typelist(int eargc, char *eargv[], (void) fprintf(stderr, "%s: couldn't open terminfo file %s.\n", _nc_progname, name_2); + free(cwd_buf); + free(name_2); + closedir(entrydir); + closedir(termdir); return (EXIT_FAILURE); } @@ -233,21 +451,26 @@ typelist(int eargc, char *eargv[], cn = _nc_first_name(lterm.term_names); if (!strcmp(cn, name_2)) { /* apply the selected hook function */ - (*hook) (cn, <erm); + hook(i, eargc, cn, <erm); } _nc_free_termtype(<erm); + free(name_2); } closedir(entrydir); } closedir(termdir); if (cwd_buf != 0) free(cwd_buf); + continue; } #if USE_HASHED_DB else { DB *capdbp; char filename[PATH_MAX]; + if (verbosity) + (void) printf("#\n#%s:\n#\n", eargv[i]); + if (make_db_name(filename, eargv[i], sizeof(filename))) { if ((capdbp = _nc_db_open(filename, FALSE)) != 0) { DBT key, data; @@ -265,7 +488,7 @@ typelist(int eargc, char *eargv[], /* only visit things once, by primary name */ cn = _nc_first_name(lterm.term_names); /* apply the selected hook function */ - (*hook) (cn, <erm); + hook(i, eargc, cn, <erm); _nc_free_termtype(<erm); } } @@ -273,44 +496,51 @@ typelist(int eargc, char *eargv[], } _nc_db_close(capdbp); + continue; } } } #endif #endif -#if USE_TERMCAP +#if NCURSES_USE_TERMCAP #if HAVE_BSD_CGETENT - char *db_array[2]; - char *buffer = 0; + { + CGETENT_CONST char *db_array[2]; + char *buffer = 0; - if (verbosity) - (void) printf("#\n#%s:\n#\n", eargv[i]); + if (verbosity) + (void) printf("#\n#%s:\n#\n", eargv[i]); - db_array[0] = eargv[i]; - db_array[1] = 0; + db_array[0] = eargv[i]; + db_array[1] = 0; - if (cgetfirst(&buffer, db_array)) { - show_termcap(buffer, hook); - free(buffer); - while (cgetnext(&buffer, db_array)) { - show_termcap(buffer, hook); + if (cgetfirst(&buffer, db_array) > 0) { + show_termcap(i, eargc, buffer, hook); free(buffer); + while (cgetnext(&buffer, db_array) > 0) { + show_termcap(i, eargc, buffer, hook); + free(buffer); + } + cgetclose(); + continue; } } - cgetclose(); #else /* scan termcap text-file only */ if (_nc_is_file_path(eargv[i])) { char buffer[2048]; FILE *fp; + if (verbosity) + (void) printf("#\n#%s:\n#\n", eargv[i]); + if ((fp = fopen(eargv[i], "r")) != 0) { while (fgets(buffer, sizeof(buffer), fp) != 0) { if (*buffer == '#') continue; if (isspace(*buffer)) continue; - show_termcap(buffer, hook); + show_termcap(i, eargc, buffer, hook); } fclose(fp); } @@ -319,13 +549,18 @@ typelist(int eargc, char *eargv[], #endif } + if (hook == sorthook) { + show_termdata(eargc, eargv); + free_termdata(); + } + return (EXIT_SUCCESS); } static void usage(void) { - (void) fprintf(stderr, "usage: %s [-ahuUV] [-v n] [file...]\n", _nc_progname); + (void) fprintf(stderr, "usage: %s [-ahsuUV] [-v n] [file...]\n", _nc_progname); ExitProgram(EXIT_FAILURE); } @@ -340,23 +575,24 @@ main(int argc, char *argv[]) unsigned i; int code; int this_opt, last_opt = '?'; - int v_opt = 0; + unsigned v_opt = 0; + DescHook *hook = deschook; _nc_progname = _nc_rootname(argv[0]); - while ((this_opt = getopt(argc, argv, "0123456789ahu:vU:V")) != -1) { + while ((this_opt = getopt(argc, argv, "0123456789ahsu:vU:V")) != -1) { /* handle optional parameter */ if (isdigit(this_opt)) { switch (last_opt) { case 'v': - v_opt = (this_opt - '0'); + v_opt = (unsigned) (this_opt - '0'); break; default: if (isdigit(last_opt)) v_opt *= 10; else v_opt = 0; - v_opt += (this_opt - '0'); + v_opt += (unsigned) (this_opt - '0'); last_opt = this_opt; } continue; @@ -368,6 +604,9 @@ main(int argc, char *argv[]) case 'h': header = TRUE; break; + case 's': + hook = sorthook; + break; case 'u': direct_dependencies = TRUE; report_file = optarg; @@ -450,7 +689,7 @@ main(int argc, char *argv[]) * If we get this far, user wants a simple terminal type listing. */ if (optind < argc) { - code = typelist(argc - optind, argv + optind, header, deschook); + code = typelist(argc - optind, argv + optind, header, hook); } else if (all_dirs) { DBDIRS state; int offset; @@ -460,64 +699,41 @@ main(int argc, char *argv[]) code = EXIT_FAILURE; for (pass = 0; pass < 2; ++pass) { - unsigned count = 0; + size_t count = 0; _nc_first_db(&state, &offset); while ((path = _nc_next_db(&state, &offset)) != 0) { - if (!is_database(path)) { - ; - } else if (eargv != 0) { - unsigned n; - int found = FALSE; - - /* eliminate duplicates */ - for (n = 0; n < count; ++n) { - if (!strcmp(path, eargv[n])) { - found = TRUE; - break; - } - } - if (!found) { - eargv[count] = strdup(path); - ++count; - } - } else { - ++count; + if (pass) { + eargv[count] = strmalloc(path); } + ++count; } if (!pass) { - eargv = typeCalloc(char *, count + 1); + eargv = allocArgv(count); if (eargv == 0) - failed("realloc eargv"); - - assert(eargv != 0); + failed("eargv"); } else { - code = typelist((int) count, eargv, header, deschook); - while (count-- > 0) - free(eargv[count]); - free(eargv); + code = typelist((int) count, eargv, header, hook); + freeArgv(eargv); } } } else { DBDIRS state; int offset; const char *path; - char *eargv[3]; - int count = 0; + char **eargv = allocArgv((size_t) 2); + size_t count = 0; + if (eargv == 0) + failed("eargv"); _nc_first_db(&state, &offset); - while ((path = _nc_next_db(&state, &offset)) != 0) { - if (is_database(path)) { - eargv[count++] = strdup(path); - break; - } + if ((path = _nc_next_db(&state, &offset)) != 0) { + eargv[count++] = strmalloc(path); } - eargv[count] = 0; - code = typelist(count, eargv, header, deschook); + code = typelist((int) count, eargv, header, hook); - while (count-- > 0) - free(eargv[count]); + freeArgv(eargv); } _nc_last_db(); diff --git a/progs/tput.c b/progs/tput.c index 2e67cfecbef4..6652d3450a2d 100644 --- a/progs/tput.c +++ b/progs/tput.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. * + * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -47,7 +47,7 @@ #endif #include -MODULE_ID("$Id: tput.c,v 1.46 2010/01/09 16:53:24 tom Exp $") +MODULE_ID("$Id: tput.c,v 1.49 2013/09/28 20:57:25 tom Exp $") #define PUTS(s) fputs(s, stdout) #define PUTCHAR(c) putchar(c) @@ -94,9 +94,6 @@ check_aliases(const char *name) * Lookup the type of call we should make to tparm(). This ignores the actual * terminfo capability (bad, because it is not extensible), but makes this * code portable to platforms where sizeof(int) != sizeof(char *). - * - * FIXME: If we want extensibility, analyze the capability string as we do - * in tparm() to decide how to parse the varargs list. */ static TParams tparm_type(const char *name) @@ -306,7 +303,7 @@ tput(int argc, char *argv[]) } else if (s != ABSENT_STRING) { if (argc > 1) { int k; - int popcount; + int ignored; long numbers[1 + NUM_PARM]; char *strings[1 + NUM_PARM]; char *p_is_s[NUM_PARM]; @@ -337,8 +334,8 @@ tput(int argc, char *argv[]) break; case Numbers: default: - (void) _nc_tparm_analyze(s, p_is_s, &popcount); -#define myParam(n) (p_is_s[n - 1] != 0 ? ((long) strings[n]) : numbers[n]) + (void) _nc_tparm_analyze(s, p_is_s, &ignored); +#define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n]) s = TPARM_9(s, myParam(1), myParam(2), diff --git a/progs/transform.c b/progs/transform.c index 75f4573357c3..c0557f0b98fb 100644 --- a/progs/transform.c +++ b/progs/transform.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 2009,2010 Free Software Foundation, Inc. * + * Copyright (c) 2009-2010,2011 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -34,21 +34,21 @@ #include -MODULE_ID("$Id: transform.c,v 1.2 2010/09/04 21:16:17 tom Exp $") +MODULE_ID("$Id: transform.c,v 1.3 2011/05/14 22:41:17 tom Exp $") #ifdef SUFFIX_IGNORED static void -trim_suffix(const char *a, unsigned *len) +trim_suffix(const char *a, size_t *len) { const char ignore[] = SUFFIX_IGNORED; if (sizeof(ignore) != 0) { bool trim = FALSE; - unsigned need = (sizeof(ignore) - 1); + size_t need = (sizeof(ignore) - 1); if (*len > need) { - unsigned first = *len - need; - unsigned n; + size_t first = *len - need; + size_t n; trim = TRUE; for (n = first; n < *len; ++n) { if (tolower(UChar(a[n])) != tolower(UChar(ignore[n - first]))) { @@ -69,8 +69,8 @@ trim_suffix(const char *a, unsigned *len) bool same_program(const char *a, const char *b) { - unsigned len_a = strlen(a); - unsigned len_b = strlen(b); + size_t len_a = strlen(a); + size_t len_b = strlen(b); trim_suffix(a, &len_a); trim_suffix(b, &len_b); diff --git a/progs/tset.c b/progs/tset.c index 084e41d6db24..f01acd721091 100644 --- a/progs/tset.c +++ b/progs/tset.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. * + * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -119,7 +119,7 @@ char *ttyname(int fd); #include #include -MODULE_ID("$Id: tset.c,v 1.82 2010/05/01 21:42:46 tom Exp $") +MODULE_ID("$Id: tset.c,v 1.93 2013/12/15 01:05:56 tom Exp $") /* * SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS, @@ -148,6 +148,10 @@ extern char **environ; #undef CTRL #define CTRL(x) ((x) & 0x1f) +static void failed(const char *) GCC_NORETURN; +static void exit_error(void) GCC_NORETURN; +static void err(const char *,...) GCC_NORETURN; + const char *_nc_progname = "tset"; static TTY mode, oldmode, original; @@ -160,7 +164,10 @@ static bool isreset = FALSE; /* invoked as reset */ static int terasechar = -1; /* new erase character */ static int intrchar = -1; /* new interrupt character */ static int tkillchar = -1; /* new kill character */ + +#if HAVE_SIZECHANGE static int tlines, tcolumns; /* window size */ +#endif #define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c)) @@ -203,13 +210,13 @@ static void failed(const char *msg) { char temp[BUFSIZ]; - unsigned len = strlen(_nc_progname) + 2; + size_t len = strlen(_nc_progname) + 2; if ((int) len < (int) sizeof(temp) - 12) { - strcpy(temp, _nc_progname); - strcat(temp, ": "); + _nc_STRCPY(temp, _nc_progname, sizeof(temp)); + _nc_STRCAT(temp, ": ", sizeof(temp)); } else { - strcpy(temp, "tset: "); + _nc_STRCPY(temp, "tset: ", sizeof(temp)); } perror(strncat(temp, msg, sizeof(temp) - strlen(temp) - 2)); exit_error(); @@ -467,9 +474,6 @@ add_mapping(const char *port, char *arg) mapp->speed = tbaudrate(p); } - if (arg == (char *) 0) /* Non-optional type. */ - goto badmopt; - mapp->type = arg; /* Terminate porttype, if specified. */ @@ -527,19 +531,19 @@ mapped(const char *type) match = TRUE; break; case EQ: - match = (ospeed == mapp->speed); + match = ((int) ospeed == mapp->speed); break; case GE: - match = (ospeed >= mapp->speed); + match = ((int) ospeed >= mapp->speed); break; case GT: - match = (ospeed > mapp->speed); + match = ((int) ospeed > mapp->speed); break; case LE: - match = (ospeed <= mapp->speed); + match = ((int) ospeed <= mapp->speed); break; case LT: - match = (ospeed < mapp->speed); + match = ((int) ospeed < mapp->speed); break; default: match = FALSE; @@ -631,13 +635,14 @@ get_termcap_entry(char *userarg) * real entry from /etc/termcap. This prevents us from being fooled * by out of date stuff in the environment. */ - found:if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) { + found: + if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) { /* 'unsetenv("TERMCAP")' is not portable. * The 'environ' array is better. */ int n; for (n = 0; environ[n] != 0; n++) { - if (!strncmp("TERMCAP=", environ[n], 8)) { + if (!strncmp("TERMCAP=", environ[n], (size_t) 8)) { while ((environ[n] = environ[n + 1]) != 0) { n++; } @@ -788,14 +793,14 @@ reset_mode(void) mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE); #endif - mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR + mode.c_iflag &= ~((unsigned) (IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR #ifdef IUCLC - | IUCLC + | IUCLC #endif #ifdef IXANY - | IXANY + | IXANY #endif - | IXOFF); + | IXOFF)); mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON #ifdef IMAXBEL @@ -803,44 +808,44 @@ reset_mode(void) #endif ); - mode.c_oflag &= ~(0 + mode.c_oflag &= ~((unsigned) (0 #ifdef OLCUC - | OLCUC + | OLCUC #endif #ifdef OCRNL - | OCRNL + | OCRNL #endif #ifdef ONOCR - | ONOCR + | ONOCR #endif #ifdef ONLRET - | ONLRET + | ONLRET #endif #ifdef OFILL - | OFILL + | OFILL #endif #ifdef OFDEL - | OFDEL + | OFDEL #endif #ifdef NLDLY - | NLDLY + | NLDLY #endif #ifdef CRDLY - | CRDLY + | CRDLY #endif #ifdef TABDLY - | TABDLY + | TABDLY #endif #ifdef BSDLY - | BSDLY + | BSDLY #endif #ifdef VTDLY - | VTDLY + | VTDLY #endif #ifdef FFDLY - | FFDLY + | FFDLY #endif - ); + )); mode.c_oflag |= (OPOST #ifdef ONLCR @@ -848,19 +853,19 @@ reset_mode(void) #endif ); - mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL); + mode.c_cflag &= ~((unsigned) (CSIZE | CSTOPB | PARENB | PARODD | CLOCAL)); mode.c_cflag |= (CS8 | CREAD); - mode.c_lflag &= ~(ECHONL | NOFLSH + mode.c_lflag &= ~((unsigned) (ECHONL | NOFLSH #ifdef TOSTOP - | TOSTOP + | TOSTOP #endif #ifdef ECHOPTR - | ECHOPRT + | ECHOPRT #endif #ifdef XCASE - | XCASE + | XCASE #endif - ); + )); mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK #ifdef ECHOCTL @@ -907,14 +912,23 @@ static void set_control_chars(void) { #ifdef TERMIOS - if (DISABLED(mode.c_cc[VERASE]) || terasechar >= 0) - mode.c_cc[VERASE] = (terasechar >= 0) ? terasechar : default_erase(); + if (DISABLED(mode.c_cc[VERASE]) || terasechar >= 0) { + mode.c_cc[VERASE] = UChar((terasechar >= 0) + ? terasechar + : default_erase()); + } - if (DISABLED(mode.c_cc[VINTR]) || intrchar >= 0) - mode.c_cc[VINTR] = (intrchar >= 0) ? intrchar : CINTR; + if (DISABLED(mode.c_cc[VINTR]) || intrchar >= 0) { + mode.c_cc[VINTR] = UChar((intrchar >= 0) + ? intrchar + : CINTR); + } - if (DISABLED(mode.c_cc[VKILL]) || tkillchar >= 0) - mode.c_cc[VKILL] = (tkillchar >= 0) ? tkillchar : CKILL; + if (DISABLED(mode.c_cc[VKILL]) || tkillchar >= 0) { + mode.c_cc[VKILL] = UChar((tkillchar >= 0) + ? tkillchar + : CKILL); + } #endif } @@ -970,9 +984,9 @@ set_conversions(void) if (newline != (char *) 0 && newline[0] == '\n' && !newline[1]) { /* Newline, not linefeed. */ #ifdef ONLCR - mode.c_oflag &= ~ONLCR; + mode.c_oflag &= ~((unsigned) ONLCR); #endif - mode.c_iflag &= ~ICRNL; + mode.c_iflag &= ~((unsigned) ICRNL); } #ifdef __OBSOLETE__ if (tgetflag("HD")) /* Half duplex. */ @@ -1043,11 +1057,18 @@ set_tabs(void) { if (set_tab && clear_all_tabs) { int c; + int lim = +#if HAVE_SIZECHANGE + tcolumns +#else + columns +#endif + ; (void) putc('\r', stderr); /* Force to left margin. */ tputs(clear_all_tabs, 0, outc); - for (c = 8; c < tcolumns; c += 8) { + for (c = 8; c < lim; c += 8) { /* Get to the right column. In BSD tset, this * used to try a bunch of half-clever things * with cup and hpa, for an average saving of @@ -1273,10 +1294,10 @@ main(int argc, char **argv) (void) get_termcap_entry(*argv); if (!noset) { +#if HAVE_SIZECHANGE tcolumns = columns; tlines = lines; -#if HAVE_SIZECHANGE if (opt_w) { STRUCT_WINSIZE win; /* Set window size if not set already */ -- cgit v1.2.3