[BACK]Return to tic.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tic

Diff for /src/usr.bin/tic/tic.c between version 1.29 and 1.30

version 1.29, 2006/10/10 21:38:16 version 1.30, 2010/01/12 23:22:14
Line 1 
Line 1 
 /*      $OpenBSD$       */  /*      $OpenBSD$       */
   
 /****************************************************************************  /****************************************************************************
  * Copyright (c) 1998,1999,2000,2001 Free Software Foundation, Inc.         *   * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.              *
  *                                                                          *   *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *   * Permission is hereby granted, free of charge, to any person obtaining a  *
  * copy of this software and associated documentation files (the            *   * copy of this software and associated documentation files (the            *
Line 31 
Line 31 
 /****************************************************************************  /****************************************************************************
  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *   *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *   *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
    *     and: Thomas E. Dickey                        1996 on                 *
  ****************************************************************************/   ****************************************************************************/
   
 /*  /*
Line 43 
Line 44 
 #include <sys/stat.h>  #include <sys/stat.h>
   
 #include <dump_entry.h>  #include <dump_entry.h>
 #include <term_entry.h>  
 #include <transform.h>  #include <transform.h>
   
 MODULE_ID("$From: tic.c,v 1.85 2001/02/03 23:31:45 tom Exp $")  MODULE_ID("$Id$")
   
 const char *_nc_progname = "tic";  const char *_nc_progname = "tic";
   
 static FILE *log_fp;  static FILE *log_fp;
 static FILE *tmp_fp;  static FILE *tmp_fp;
   static bool capdump = FALSE;    /* running as infotocap? */
   static bool infodump = FALSE;   /* running as captoinfo? */
 static bool showsummary = FALSE;  static bool showsummary = FALSE;
 static const char *to_remove;  static const char *to_remove;
   
 static void (*save_check_termtype) (TERMTYPE *);  static void (*save_check_termtype) (TERMTYPE *, bool);
 static void check_termtype(TERMTYPE * tt);  static void check_termtype(TERMTYPE *tt, bool);
   
 static const char usage_string[] = "[-V] [-v[n]] [-e names] [-CILNRTcfrswx1] source-file\n";  static const char usage_string[] = "\
   [-e names] \
   [-o dir] \
   [-R name] \
   [-v[n]] \
   [-V] \
   [-w[n]] \
   [-\
   1\
   a\
   C\
   c\
   f\
   G\
   g\
   I\
   L\
   N\
   r\
   s\
   T\
   t\
   U\
   x\
   ] \
   source-file\n";
   
   #if NO_LEAKS
 static void  static void
 cleanup(void)  free_namelist(char **src)
 {  {
       if (src != 0) {
           int n;
           for (n = 0; src[n] != 0; ++n)
               free(src[n]);
           free(src);
       }
   }
   #endif
   
   static void
   cleanup(char **namelst GCC_UNUSED)
   {
   #if NO_LEAKS
       free_namelist(namelst);
   #endif
     if (tmp_fp != 0)      if (tmp_fp != 0)
         fclose(tmp_fp);          fclose(tmp_fp);
     if (to_remove != 0) {      if (to_remove != 0) {
Line 78 
Line 121 
 failed(const char *msg)  failed(const char *msg)
 {  {
     perror(msg);      perror(msg);
     cleanup();      cleanup((char **) 0);
     exit(EXIT_FAILURE);      ExitProgram(EXIT_FAILURE);
 }  }
   
 static void  static void
Line 89 
Line 132 
     {      {
         "Options:",          "Options:",
         "  -1         format translation output one capability per line",          "  -1         format translation output one capability per line",
         "  -C         translate entries to termcap source form",  
         "  -I         translate entries to terminfo source form",  
         "  -L         translate entries to full terminfo source form",  
         "  -N         disable smart defaults for source translation",  
         "  -R         restrict translation to given terminfo/termcap version",  
         "  -T         remove size-restrictions on compiled description",  
         "  -V         print version",  
 #if NCURSES_XNAMES  #if NCURSES_XNAMES
         "  -a         retain commented-out capabilities (sets -x also)",          "  -a         retain commented-out capabilities (sets -x also)",
 #endif  #endif
           "  -C         translate entries to termcap source form",
         "  -c         check only, validate input without compiling or translating",          "  -c         check only, validate input without compiling or translating",
           "  -e<names>  translate/compile only entries named by comma-separated list",
         "  -f         format complex strings for readability",          "  -f         format complex strings for readability",
         "  -G         format %{number} to %'char'",          "  -G         format %{number} to %'char'",
         "  -g         format %'char' to %{number}",          "  -g         format %'char' to %{number}",
         "  -e<names>  translate/compile only entries named by comma-separated list",          "  -I         translate entries to terminfo source form",
           "  -L         translate entries to full terminfo source form",
           "  -N         disable smart defaults for source translation",
         "  -o<dir>    set output directory for compiled entry writes",          "  -o<dir>    set output directory for compiled entry writes",
           "  -R<name>   restrict translation to given terminfo/termcap version",
         "  -r         force resolution of all use entries in source translation",          "  -r         force resolution of all use entries in source translation",
         "  -s         print summary statistics",          "  -s         print summary statistics",
           "  -T         remove size-restrictions on compiled description",
   #if NCURSES_XNAMES
           "  -t         suppress commented-out capabilities",
   #endif
           "  -U         suppress post-processing of entries",
           "  -V         print version",
         "  -v[n]      set verbosity level",          "  -v[n]      set verbosity level",
         "  -w[n]      set format width for translation output",          "  -w[n]      set format width for translation output",
 #if NCURSES_XNAMES  #if NCURSES_XNAMES
Line 123 
Line 170 
         fputs(tbl[j], stderr);          fputs(tbl[j], stderr);
         putc('\n', stderr);          putc('\n', stderr);
     }      }
     exit(EXIT_FAILURE);      ExitProgram(EXIT_FAILURE);
 }  }
   
 #define L_BRACE '{'  #define L_BRACE '{'
Line 149 
Line 196 
             d = result;              d = result;
             t = s;              t = s;
             while ((ch = *t++) != 0) {              while ((ch = *t++) != 0) {
                 *d++ = ch;                  *d++ = (char) ch;
                 if (ch == '\\') {                  if (ch == '\\') {
                     *d++ = *t++;                      *d++ = *t++;
                 } else if ((ch == '%')                  } else if ((ch == '%')
Line 163 
Line 210 
                         && value < 127                          && value < 127
                         && isprint((int) value)) {                          && isprint((int) value)) {
                         *d++ = S_QUOTE;                          *d++ = S_QUOTE;
                         *d++ = (int) value;                          *d++ = (char) value;
                         *d++ = S_QUOTE;                          *d++ = S_QUOTE;
                         t = (v + 1);                          t = (v + 1);
                     }                      }
                 }                  }
             }              }
             *d = 0;              *d = 0;
             if (strlen(result) < strlen(s)) {              if (strlen(result) < strlen(s)) {
                 /* new string is same length as what is there, or shorter */                      /* new string is same length as what is there, or shorter */
                 strlcpy(s, result, strlen(s));                      strlcpy(s, result, strlen(s));
             }              }
         }          }
     }      }
   
Line 253 
Line 300 
             putchar(c);              putchar(c);
             in_name = FALSE;              in_name = FALSE;
         } else if (c != '>') {          } else if (c != '>') {
             namebuf[used++] = c;              namebuf[used++] = (char) c;
         } else {                /* ah! candidate name! */          } else {                /* ah! candidate name! */
             char *up;              char *up;
             NCURSES_CONST char *tp;              NCURSES_CONST char *tp;
Line 265 
Line 312 
             if ((up = strchr(namebuf, '#')) != 0              if ((up = strchr(namebuf, '#')) != 0
                 || (up = strchr(namebuf, '=')) != 0                  || (up = strchr(namebuf, '=')) != 0
                 || ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {                  || ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {
                 (void) strlcpy(suffix, up, have);                      (void) strlcpy(suffix, up, have);
                 *up = '\0';                  *up = '\0';
             }              }
   
Line 296 
Line 343 
 static char *  static char *
 stripped(char *src)  stripped(char *src)
 {  {
     while (isspace(CharOf(*src)))      while (isspace(UChar(*src)))
         src++;          src++;
     if (*src != '\0') {      if (*src != '\0') {
         char *dst;          char *dst;
         size_t len;          size_t len;
   
         if ((dst = strdup(src)) == NULL)          if ((dst = strdup(src)) == NULL)
                 failed("strdup");              failed("strdup");
         len = strlen(dst);          len = strlen(dst);
         while (--len != 0 && isspace(CharOf(dst[len])))          while (--len != 0 && isspace(UChar(dst[len])))
             dst[len] = '\0';              dst[len] = '\0';
         return dst;          return dst;
     }      }
Line 320 
Line 367 
   
     if (fp == 0) {      if (fp == 0) {
         fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename);          fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename);
         exit(EXIT_FAILURE);          ExitProgram(EXIT_FAILURE);
     }      }
     if (fstat(fileno(fp), &sb) < 0      if (fstat(fileno(fp), &sb) < 0
         || (sb.st_mode & S_IFMT) != S_IFREG) {          || (sb.st_mode & S_IFMT) != S_IFREG) {
         fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);          fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);
         exit(EXIT_FAILURE);          ExitProgram(EXIT_FAILURE);
     }      }
     return fp;      return fp;
 }  }
   
 /* Parse the "-e" option-value into a list of names */  /* Parse the "-e" option-value into a list of names */
 static const char **  static char **
 make_namelist(char *src)  make_namelist(char *src)
 {  {
     const char **dst = 0;      char **dst = 0;
   
     char *s, *base;      char *s, *base;
     unsigned pass, n, nn;      unsigned pass, n, nn;
Line 351 
Line 398 
                 if ((s = stripped(buffer)) != 0) {                  if ((s = stripped(buffer)) != 0) {
                     if (dst != 0)                      if (dst != 0)
                         dst[nn] = s;                          dst[nn] = s;
                       else
                           free(s);
                     nn++;                      nn++;
                 }                  }
             }              }
             if (pass == 1) {              if (pass == 1) {
                 dst = typeCalloc(const char *, nn + 1);                  dst = typeCalloc(char *, nn + 1);
                 rewind(fp);                  rewind(fp);
             }              }
         }          }
Line 378 
Line 427 
                     break;                      break;
             }              }
             if (pass == 1)              if (pass == 1)
                 dst = typeCalloc(const char *, nn + 1);                  dst = typeCalloc(char *, nn + 1);
         }          }
     }      }
     if (showsummary) {      if (showsummary && (dst != 0)) {
         fprintf(log_fp, "Entries that will be compiled:\n");          fprintf(log_fp, "Entries that will be compiled:\n");
         for (n = 0; dst[n] != 0; n++)          for (n = 0; dst[n] != 0; n++)
             fprintf(log_fp, "%d:%s\n", n + 1, dst[n]);              fprintf(log_fp, "%u:%s\n", n + 1, dst[n]);
     }      }
     return dst;      return dst;
 }  }
   
 static bool  static bool
 matches(const char **needle, const char *haystack)  matches(char **needle, const char *haystack)
 /* does entry in needle list match |-separated field in haystack? */  /* does entry in needle list match |-separated field in haystack? */
 {  {
     bool code = FALSE;      bool code = FALSE;
Line 439 
Line 488 
   
     int width = 60;      int width = 60;
     bool formatted = FALSE;     /* reformat complex strings? */      bool formatted = FALSE;     /* reformat complex strings? */
       bool literal = FALSE;       /* suppress post-processing? */
     int numbers = 0;            /* format "%'char'" to/from "%{number}" */      int numbers = 0;            /* format "%'char'" to/from "%{number}" */
     bool infodump = FALSE;      /* running as captoinfo? */  
     bool capdump = FALSE;       /* running as infotocap? */  
     bool forceresolve = FALSE;  /* force resolution */      bool forceresolve = FALSE;  /* force resolution */
     bool limited = TRUE;      bool limited = TRUE;
     char *tversion = (char *) NULL;      char *tversion = (char *) NULL;
     const char *source_file = "terminfo";      const char *source_file = "terminfo";
     const char **namelst = 0;      char **namelst = 0;
     char *outdir = (char *) NULL;      char *outdir = (char *) NULL;
     bool check_only = FALSE;      bool check_only = FALSE;
       bool suppress_untranslatable = FALSE;
   
     log_fp = stderr;      log_fp = stderr;
   
     _nc_progname = _nc_basename(argv[0]);      _nc_progname = _nc_rootname(argv[0]);
   
     if ((infodump = (strcmp(_nc_progname, PROG_CAPTOINFO) == 0)) != FALSE) {      if ((infodump = (strcmp(_nc_progname, PROG_CAPTOINFO) == 0)) != FALSE) {
         outform = F_TERMINFO;          outform = F_TERMINFO;
Line 472 
Line 521 
      * be optional.       * be optional.
      */       */
     while ((this_opt = getopt(argc, argv,      while ((this_opt = getopt(argc, argv,
                               "0123456789CILNR:TVace:fGgo:rsvwx")) != -1) {                                "0123456789CILNR:TUVace:fGgo:rstvwx")) != -1) {
         if (isdigit(this_opt)) {          if (isdigit(this_opt)) {
             switch (last_opt) {              switch (last_opt) {
             case 'v':              case 'v':
Line 507 
Line 556 
             break;              break;
         case 'N':          case 'N':
             smart_defaults = FALSE;              smart_defaults = FALSE;
               literal = TRUE;
             break;              break;
         case 'R':          case 'R':
             tversion = optarg;              tversion = optarg;
Line 514 
Line 564 
         case 'T':          case 'T':
             limited = FALSE;              limited = FALSE;
             break;              break;
           case 'U':
               literal = TRUE;
               break;
         case 'V':          case 'V':
             puts(curses_version());              puts(curses_version());
             return EXIT_SUCCESS;              cleanup(namelst);
               ExitProgram(EXIT_SUCCESS);
         case 'c':          case 'c':
             check_only = TRUE;              check_only = TRUE;
             break;              break;
Line 548 
Line 602 
             width = 0;              width = 0;
             break;              break;
 #if NCURSES_XNAMES  #if NCURSES_XNAMES
           case 't':
               _nc_disable_period = FALSE;
               suppress_untranslatable = TRUE;
               break;
         case 'a':          case 'a':
             _nc_disable_period = TRUE;              _nc_disable_period = TRUE;
             /* FALLTHRU */              /* FALLTHRU */
Line 565 
Line 623 
     set_trace_level(debug_level);      set_trace_level(debug_level);
   
     if (_nc_tracing) {      if (_nc_tracing) {
         save_check_termtype = _nc_check_termtype;          save_check_termtype = _nc_check_termtype2;
         _nc_check_termtype = check_termtype;          _nc_check_termtype2 = check_termtype;
     }      }
 #if !HAVE_BIG_CORE  #if !HAVE_BIG_CORE
     /*      /*
Line 582 
Line 640 
     if (namelst && (!infodump && !capdump)) {      if (namelst && (!infodump && !capdump)) {
         (void) fprintf(stderr,          (void) fprintf(stderr,
                        "Sorry, -e can't be used without -I or -C\n");                         "Sorry, -e can't be used without -I or -C\n");
         cleanup();          cleanup(namelst);
         return EXIT_FAILURE;          ExitProgram(EXIT_FAILURE);
     }      }
 #endif /* HAVE_BIG_CORE */  #endif /* HAVE_BIG_CORE */
   
Line 595 
Line 653 
                     _nc_progname,                      _nc_progname,
                     _nc_progname,                      _nc_progname,
                     usage_string);                      usage_string);
             return EXIT_FAILURE;              ExitProgram(EXIT_FAILURE);
         }          }
     } else {      } else {
         if (infodump == TRUE) {          if (infodump == TRUE) {
             /* captoinfo's no-argument case */              /* captoinfo's no-argument case */
             source_file = "/usr/share/misc/termcap";              source_file = "/etc/termcap";
             if ((termcap = getenv("TERMCAP")) != 0              if ((termcap = getenv("TERMCAP")) != 0
                 && (namelst = make_namelist(getenv("TERM"))) != 0) {                  && (namelst = make_namelist(getenv("TERM"))) != 0) {
                 strlcpy(my_tmpname, "/tmp/XXXXXXXXXX", sizeof my_tmpname);                  strlcpy(my_tmpname, "/tmp/XXXXXXXXXX", sizeof my_tmpname);
Line 614 
Line 672 
                     tmp_fp = open_input(source_file);                      tmp_fp = open_input(source_file);
                     to_remove = source_file;                      to_remove = source_file;
                 } else {                  } else {
                     failed("mkstemp");                      failed("tmpnam");
                 }                  }
             }              }
         } else {          } else {
Line 624 
Line 682 
                     _nc_progname,                      _nc_progname,
                     _nc_progname,                      _nc_progname,
                     usage_string);                      usage_string);
             cleanup();              cleanup(namelst);
             return EXIT_FAILURE;              ExitProgram(EXIT_FAILURE);
         }          }
     }      }
   
Line 650 
Line 708 
         _nc_set_writedir(outdir);          _nc_set_writedir(outdir);
 #endif /* HAVE_BIG_CORE */  #endif /* HAVE_BIG_CORE */
     _nc_read_entry_source(tmp_fp, (char *) NULL,      _nc_read_entry_source(tmp_fp, (char *) NULL,
                           !smart_defaults, FALSE,                            !smart_defaults || literal, FALSE,
                           (check_only || infodump || capdump) ? NULLHOOK : immedhook);                            ((check_only || infodump || capdump)
                              ? NULLHOOK
                              : immedhook));
   
     /* do use resolution */      /* do use resolution */
     if (check_only || (!infodump && !capdump) || forceresolve) {      if (check_only || (!infodump && !capdump) || forceresolve) {
         if (!_nc_resolve_uses(TRUE) && !check_only) {          if (!_nc_resolve_uses2(TRUE, literal) && !check_only) {
             cleanup();              cleanup(namelst);
             return EXIT_FAILURE;              ExitProgram(EXIT_FAILURE);
         }          }
     }      }
   
Line 665 
Line 725 
     if (check_only && (capdump || infodump)) {      if (check_only && (capdump || infodump)) {
         for_entry_list(qp) {          for_entry_list(qp) {
             if (matches(namelst, qp->tterm.term_names)) {              if (matches(namelst, qp->tterm.term_names)) {
                 int len = fmt_entry(&qp->tterm, NULL, TRUE, infodump, numbers);                  int len = fmt_entry(&qp->tterm, NULL, FALSE, TRUE, infodump, numbers);
   
                 if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))                  if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))
                     (void) fprintf(stderr,                      (void) fprintf(stderr,
Line 697 
Line 757 
                     _nc_set_type(_nc_first_name(qp->tterm.term_names));                      _nc_set_type(_nc_first_name(qp->tterm.term_names));
   
                     (void) fseek(tmp_fp, qp->cstart, SEEK_SET);                      (void) fseek(tmp_fp, qp->cstart, SEEK_SET);
                     while (j--) {                      while (j-- > 0) {
                         if (infodump)                          if (infodump)
                             (void) putchar(fgetc(tmp_fp));                              (void) putchar(fgetc(tmp_fp));
                         else                          else
                             put_translate(fgetc(tmp_fp));                              put_translate(fgetc(tmp_fp));
                     }                      }
   
                     len = dump_entry(&qp->tterm, limited, numbers, NULL);                      dump_entry(&qp->tterm, suppress_untranslatable,
                     for (j = 0; j < qp->nuses; j++)                                 limited, numbers, NULL);
                         len += dump_uses(qp->uses[j].name, !capdump);                      for (j = 0; j < (int) qp->nuses; j++)
                     (void) putchar('\n');                          dump_uses(qp->uses[j].name, !capdump);
                       len = show_entry();
                     if (debug_level != 0 && !limited)                      if (debug_level != 0 && !limited)
                         printf("# length=%d\n", len);                          printf("# length=%d\n", len);
                 }                  }
Line 749 
Line 810 
         else          else
             fprintf(log_fp, "No entries written\n");              fprintf(log_fp, "No entries written\n");
     }      }
     cleanup();      cleanup(namelst);
     return (EXIT_SUCCESS);      ExitProgram(EXIT_SUCCESS);
 }  }
   
 /*  /*
Line 758 
Line 819 
  * references to locations in the arrays Booleans, Numbers, and Strings ---   * references to locations in the arrays Booleans, Numbers, and Strings ---
  * precisely what's needed (see comp_parse.c).   * precisely what's needed (see comp_parse.c).
  */   */
   
 TERMINAL *cur_term;             /* tweak to avoid linking lib_cur_term.c */  
   
 #undef CUR  #undef CUR
 #define CUR tp->  #define CUR tp->
   
 /*  /*
    * Check if the alternate character-set capabilities are consistent.
    */
   static void
   check_acs(TERMTYPE *tp)
   {
       if (VALID_STRING(acs_chars)) {
           const char *boxes = "lmkjtuvwqxn";
           char mapped[256];
           char missing[256];
           const char *p;
           char *q;
   
           memset(mapped, 0, sizeof(mapped));
           for (p = acs_chars; *p != '\0'; p += 2) {
               if (p[1] == '\0') {
                   _nc_warning("acsc has odd number of characters");
                   break;
               }
               mapped[UChar(p[0])] = p[1];
           }
   
           if (mapped[UChar('I')] && !mapped[UChar('i')]) {
               _nc_warning("acsc refers to 'I', which is probably an error");
           }
   
           for (p = boxes, q = missing; *p != '\0'; ++p) {
               if (!mapped[UChar(p[0])]) {
                   *q++ = p[0];
               }
           }
           *q = '\0';
   
           assert(strlen(missing) <= strlen(boxes));
           if (*missing != '\0' && strcmp(missing, boxes)) {
               _nc_warning("acsc is missing some line-drawing mapping: %s", missing);
           }
       }
   }
   
   /*
    * Check if the color capabilities are consistent
    */
   static void
   check_colors(TERMTYPE *tp)
   {
       if ((max_colors > 0) != (max_pairs > 0)
           || ((max_colors > max_pairs) && (initialize_pair == 0)))
           _nc_warning("inconsistent values for max_colors (%d) and max_pairs (%d)",
                       max_colors, max_pairs);
   
       PAIRED(set_foreground, set_background);
       PAIRED(set_a_foreground, set_a_background);
       PAIRED(set_color_pair, initialize_pair);
   
       if (VALID_STRING(set_foreground)
           && VALID_STRING(set_a_foreground)
           && !_nc_capcmp(set_foreground, set_a_foreground))
           _nc_warning("expected setf/setaf to be different");
   
       if (VALID_STRING(set_background)
           && VALID_STRING(set_a_background)
           && !_nc_capcmp(set_background, set_a_background))
           _nc_warning("expected setb/setab to be different");
   
       /* see: has_colors() */
       if (VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs)
           && (((set_foreground != NULL)
                && (set_background != NULL))
               || ((set_a_foreground != NULL)
                   && (set_a_background != NULL))
               || set_color_pair)) {
           if (!VALID_STRING(orig_pair) && !VALID_STRING(orig_colors))
               _nc_warning("expected either op/oc string for resetting colors");
       }
   }
   
   static char
   keypad_final(const char *string)
   {
       char result = '\0';
   
       if (VALID_STRING(string)
           && *string++ == '\033'
           && *string++ == 'O'
           && strlen(string) == 1) {
           result = *string;
       }
   
       return result;
   }
   
   static int
   keypad_index(const char *string)
   {
       char *test;
       const char *list = "PQRSwxymtuvlqrsPpn";    /* app-keypad except "Enter" */
       int ch;
       int result = -1;
   
       if ((ch = keypad_final(string)) != '\0') {
           test = strchr(list, ch);
           if (test != 0)
               result = (test - list);
       }
       return result;
   }
   
   #define MAX_KP 5
   /*
    * Do a quick sanity-check for vt100-style keypads to see if the 5-key keypad
    * is mapped inconsistently.
    */
   static void
   check_keypad(TERMTYPE *tp)
   {
       char show[80];
   
       if (VALID_STRING(key_a1) &&
           VALID_STRING(key_a3) &&
           VALID_STRING(key_b2) &&
           VALID_STRING(key_c1) &&
           VALID_STRING(key_c3)) {
           char final[MAX_KP + 1];
           int list[MAX_KP];
           int increase = 0;
           int j, k, kk;
           int last;
           int test;
   
           final[0] = keypad_final(key_a1);
           final[1] = keypad_final(key_a3);
           final[2] = keypad_final(key_b2);
           final[3] = keypad_final(key_c1);
           final[4] = keypad_final(key_c3);
           final[5] = '\0';
   
           /* special case: legacy coding using 1,2,3,0,. on the bottom */
           assert(strlen(final) <= MAX_KP);
           if (!strcmp(final, "qsrpn"))
               return;
   
           list[0] = keypad_index(key_a1);
           list[1] = keypad_index(key_a3);
           list[2] = keypad_index(key_b2);
           list[3] = keypad_index(key_c1);
           list[4] = keypad_index(key_c3);
   
           /* check that they're all vt100 keys */
           for (j = 0; j < MAX_KP; ++j) {
               if (list[j] < 0) {
                   return;
               }
           }
   
           /* check if they're all in increasing order */
           for (j = 1; j < MAX_KP; ++j) {
               if (list[j] > list[j - 1]) {
                   ++increase;
               }
           }
           if (increase != (MAX_KP - 1)) {
               show[0] = '\0';
   
               for (j = 0, last = -1; j < MAX_KP; ++j) {
                   for (k = 0, kk = -1, test = 100; k < 5; ++k) {
                       if (list[k] > last &&
                           list[k] < test) {
                           test = list[k];
                           kk = k;
                       }
                   }
                   last = test;
                   assert(strlen(show) < (MAX_KP * 4));
                   switch (kk) {
                   case 0:
                       strlcat(show, " ka1", sizeof(show));
                       break;
                   case 1:
                       strlcat(show, " ka3", sizeof(show));
                       break;
                   case 2:
                       strlcat(show, " kb2", sizeof(show));
                       break;
                   case 3:
                       strlcat(show, " kc1", sizeof(show));
                       break;
                   case 4:
                       strlcat(show, " kc3", sizeof(show));
                       break;
                   }
               }
   
               _nc_warning("vt100 keypad order inconsistent: %s", show);
           }
   
       } else if (VALID_STRING(key_a1) ||
                  VALID_STRING(key_a3) ||
                  VALID_STRING(key_b2) ||
                  VALID_STRING(key_c1) ||
                  VALID_STRING(key_c3)) {
           show[0] = '\0';
           if (keypad_index(key_a1) >= 0)
               strlcat(show, " ka1", sizeof(show));
           if (keypad_index(key_a3) >= 0)
               strlcat(show, " ka3", sizeof(show));
           if (keypad_index(key_b2) >= 0)
               strlcat(show, " kb2", sizeof(show));
           if (keypad_index(key_c1) >= 0)
               strlcat(show, " kc1", sizeof(show));
           if (keypad_index(key_c3) >= 0)
               strlcat(show, " kc3", sizeof(show));
           if (*show != '\0')
               _nc_warning("vt100 keypad map incomplete:%s", show);
       }
   }
   
   /*
  * Returns the expected number of parameters for the given capability.   * Returns the expected number of parameters for the given capability.
  */   */
 static int  static int
 expected_params(char *name)  expected_params(const char *name)
 {  {
     /* *INDENT-OFF* */      /* *INDENT-OFF* */
     static const struct {      static const struct {
         const char *name;          const char *name;
         int count;          int count;
     } table[] = {      } table[] = {
           { "S0",                 1 },    /* 'screen' extension */
         { "birep",              2 },          { "birep",              2 },
         { "chr",                1 },          { "chr",                1 },
         { "colornm",            1 },          { "colornm",            1 },
Line 827 
Line 1103 
         { "sgr1",               6 },          { "sgr1",               6 },
         { "slength",            1 },          { "slength",            1 },
         { "slines",             1 },          { "slines",             1 },
         { "smgbp",              2 },          { "smgbp",              1 },    /* 2 if smgtp is not given */
         { "smglp",              2 },          { "smglp",              1 },
         { "smglr",              2 },          { "smglr",              2 },
         { "smgrp",              1 },          { "smgrp",              1 },
         { "smgtb",              2 },          { "smgtb",              2 },
Line 860 
Line 1136 
  * markers.   * markers.
  */   */
 static void  static void
 check_params(TERMTYPE * tp, char *name, char *value)  check_params(TERMTYPE *tp, const char *name, char *value)
 {  {
     int expected = expected_params(name);      int expected = expected_params(name);
     int actual = 0;      int actual = 0;
Line 868 
Line 1144 
     bool params[10];      bool params[10];
     char *s = value;      char *s = value;
   
   #ifdef set_top_margin_parm
       if (!strcmp(name, "smgbp")
           && set_top_margin_parm == 0)
           expected = 2;
   #endif
   
     for (n = 0; n < 10; n++)      for (n = 0; n < 10; n++)
         params[n] = FALSE;          params[n] = FALSE;
   
Line 906 
Line 1188 
     }      }
 }  }
   
   static char *
   skip_delay(char *s)
   {
       while (*s == '/' || isdigit(UChar(*s)))
           ++s;
       return s;
   }
   
 /*  /*
    * Skip a delay altogether, e.g., when comparing a simple string to sgr,
    * the latter may have a worst-case delay on the end.
    */
   static char *
   ignore_delays(char *s)
   {
       int delaying = 0;
   
       do {
           switch (*s) {
           case '$':
               if (delaying == 0)
                   delaying = 1;
               break;
           case '<':
               if (delaying == 1)
                   delaying = 2;
               break;
           case '\0':
               delaying = 0;
               break;
           default:
               if (delaying) {
                   s = skip_delay(s);
                   if (*s == '>')
                       ++s;
                   delaying = 0;
               }
               break;
           }
           if (delaying)
               ++s;
       } while (delaying);
       return s;
   }
   
   /*
  * An sgr string may contain several settings other than the one we're   * An sgr string may contain several settings other than the one we're
  * interested in, essentially sgr0 + rmacs + whatever.  As long as the   * interested in, essentially sgr0 + rmacs + whatever.  As long as the
  * "whatever" is contained in the sgr string, that is close enough for our   * "whatever" is contained in the sgr string, that is close enough for our
  * sanity check.   * sanity check.
  */   */
 static bool  static bool
 similar_sgr(char *a, char *b)  similar_sgr(int num, char *a, char *b)
 {  {
       static const char *names[] =
       {
           "none"
           ,"standout"
           ,"underline"
           ,"reverse"
           ,"blink"
           ,"dim"
           ,"bold"
           ,"invis"
           ,"protect"
           ,"altcharset"
       };
       char *base_a = a;
       char *base_b = b;
       int delaying = 0;
   
     while (*b != 0) {      while (*b != 0) {
         while (*a != *b) {          while (*a != *b) {
             if (*a == 0)              if (*a == 0) {
                   if (b[0] == '$'
                       && b[1] == '<') {
                       _nc_warning("Did not find delay %s", _nc_visbuf(b));
                   } else {
                       _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s",
                                   names[num], _nc_visbuf2(1, base_a),
                                   _nc_visbuf2(2, base_b),
                                   _nc_visbuf2(3, b));
                   }
                 return FALSE;                  return FALSE;
             a++;              } else if (delaying) {
                   a = skip_delay(a);
                   b = skip_delay(b);
               } else {
                   a++;
               }
         }          }
           switch (*a) {
           case '$':
               if (delaying == 0)
                   delaying = 1;
               break;
           case '<':
               if (delaying == 1)
                   delaying = 2;
               break;
           default:
               delaying = 0;
               break;
           }
         a++;          a++;
         b++;          b++;
     }      }
     return TRUE;      /* ignore delays on the end of the string */
       a = ignore_delays(a);
       return ((num != 0) || (*a == 0));
 }  }
   
 static void  static char *
 check_sgr(TERMTYPE * tp, char *zero, int num, char *cap, const char *name)  check_sgr(TERMTYPE *tp, char *zero, int num, char *cap, const char *name)
 {  {
     char *test = tparm(set_attributes,      char *test;
                        num == 1,  
                        num == 2,      _nc_tparm_err = 0;
                        num == 3,      test = TPARM_9(set_attributes,
                        num == 4,                     num == 1,
                        num == 5,                     num == 2,
                        num == 6,                     num == 3,
                        num == 7,                     num == 4,
                        num == 8,                     num == 5,
                        num == 9);                     num == 6,
                      num == 7,
                      num == 8,
                      num == 9);
     if (test != 0) {      if (test != 0) {
         if (PRESENT(cap)) {          if (PRESENT(cap)) {
             if (!similar_sgr(test, cap)) {              if (!similar_sgr(num, test, cap)) {
                 _nc_warning("%s differs from sgr(%d): %s", name, num,                  _nc_warning("%s differs from sgr(%d)\n\t%s=%s\n\tsgr(%d)=%s",
                             _nc_visbuf(test));                              name, num,
                               name, _nc_visbuf2(1, cap),
                               num, _nc_visbuf2(2, test));
             }              }
         } else if (strcmp(test, zero)) {          } else if (_nc_capcmp(test, zero)) {
             _nc_warning("sgr(%d) present, but not %s", num, name);              _nc_warning("sgr(%d) present, but not %s", num, name);
         }          }
     } else if (PRESENT(cap)) {      } else if (PRESENT(cap)) {
         _nc_warning("sgr(%d) missing, but %s present", num, name);          _nc_warning("sgr(%d) missing, but %s present", num, name);
     }      }
       if (_nc_tparm_err)
           _nc_warning("stack error in sgr(%d) string", num);
       return test;
 }  }
   
 #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)  #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)
   
   #ifdef TRACE
   /*
    * If tic is compiled with TRACE, we'll be able to see the output from the
    * DEBUG() macro.  But since it doesn't use traceon(), it always goes to
    * the standard error.  Use this function to make it simpler to follow the
    * resulting debug traces.
    */
   static void
   show_where(unsigned level)
   {
       if (_nc_tracing >= DEBUG_LEVEL(level)) {
           char my_name[256];
           _nc_get_type(my_name);
           fprintf(stderr, "\"%s\", line %d, '%s' ",
                   _nc_get_source(),
                   _nc_curr_line, my_name);
       }
   }
   
   #else
   #define show_where(level)       /* nothing */
   #endif
   
 /* other sanity-checks (things that we don't want in the normal  /* other sanity-checks (things that we don't want in the normal
  * logic that reads a terminfo entry)   * logic that reads a terminfo entry)
  */   */
 static void  static void
 check_termtype(TERMTYPE * tp)  check_termtype(TERMTYPE *tp, bool literal)
 {  {
     bool conflict = FALSE;      bool conflict = FALSE;
     unsigned j, k;      unsigned j, k;
Line 971 
Line 1375 
      * a given string (e.g., KEY_END and KEY_LL).  But curses will only       * a given string (e.g., KEY_END and KEY_LL).  But curses will only
      * return one (the last one assigned).       * return one (the last one assigned).
      */       */
     memset(fkeys, 0, sizeof(fkeys));      if (!(_nc_syntax == SYN_TERMCAP && capdump)) {
     for (j = 0; _nc_tinfo_fkeys[j].code; j++) {          memset(fkeys, 0, sizeof(fkeys));
         char *a = tp->Strings[_nc_tinfo_fkeys[j].offset];          for (j = 0; _nc_tinfo_fkeys[j].code; j++) {
         bool first = TRUE;              char *a = tp->Strings[_nc_tinfo_fkeys[j].offset];
         if (!VALID_STRING(a))              bool first = TRUE;
             continue;              if (!VALID_STRING(a))
         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])  
                 continue;                  continue;
             if (!strcmp(a, b)) {              for (k = j + 1; _nc_tinfo_fkeys[k].code; k++) {
                 fkeys[j] = 1;                  char *b = tp->Strings[_nc_tinfo_fkeys[k].offset];
                 fkeys[k] = 1;                  if (!VALID_STRING(b)
                 if (first) {                      || fkeys[k])
                     if (!conflict) {                      continue;
                         _nc_warning("Conflicting key definitions (using the last)");                  if (!_nc_capcmp(a, b)) {
                         conflict = TRUE;                      fkeys[j] = 1;
                       fkeys[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));
                           first = FALSE;
                       } else {
                           fprintf(stderr, ", %s",
                                   keyname((int) _nc_tinfo_fkeys[k].code));
                     }                      }
                     fprintf(stderr, "... %s is the same as %s",  
                             keyname(_nc_tinfo_fkeys[j].code),  
                             keyname(_nc_tinfo_fkeys[k].code));  
                     first = FALSE;  
                 } else {  
                     fprintf(stderr, ", %s",  
                             keyname(_nc_tinfo_fkeys[k].code));  
                 }                  }
             }              }
               if (!first)
                   fprintf(stderr, "\n");
         }          }
         if (!first)  
             fprintf(stderr, "\n");  
     }      }
   
     for (j = 0; j < NUM_STRINGS(tp); j++) {      for (j = 0; j < NUM_STRINGS(tp); j++) {
Line 1010 
Line 1416 
             check_params(tp, ExtStrname(tp, j, strnames), a);              check_params(tp, ExtStrname(tp, j, strnames), a);
     }      }
   
     /*      check_acs(tp);
      * Quick check for color.  We could also check if the ANSI versus      check_colors(tp);
      * non-ANSI strings are misused.      check_keypad(tp);
      */  
     if ((max_colors > 0) != (max_pairs > 0)  
         || (max_colors > max_pairs))  
         _nc_warning("inconsistent values for max_colors and max_pairs");  
   
     PAIRED(set_foreground, set_background);  
     PAIRED(set_a_foreground, set_a_background);  
   
     /*      /*
      * These may be mismatched because the terminal description relies on       * These may be mismatched because the terminal description relies on
      * restoring the cursor visibility by resetting it.       * restoring the cursor visibility by resetting it.
Line 1029 
Line 1428 
     ANDMISSING(cursor_visible, cursor_normal);      ANDMISSING(cursor_visible, cursor_normal);
   
     if (PRESENT(cursor_visible) && PRESENT(cursor_normal)      if (PRESENT(cursor_visible) && PRESENT(cursor_normal)
         && !strcmp(cursor_visible, cursor_normal))          && !_nc_capcmp(cursor_visible, cursor_normal))
         _nc_warning("cursor_visible is same as cursor_normal");          _nc_warning("cursor_visible is same as cursor_normal");
   
     /*      /*
Line 1041 
Line 1440 
     ANDMISSING(change_scroll_region, restore_cursor);      ANDMISSING(change_scroll_region, restore_cursor);
   
     if (PRESENT(set_attributes)) {      if (PRESENT(set_attributes)) {
         char *zero = tparm(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0);          char *zero = 0;
   
         zero = strdup(zero);          _nc_tparm_err = 0;
         CHECK_SGR(1, enter_standout_mode);          if (PRESENT(exit_attribute_mode)) {
         CHECK_SGR(2, enter_underline_mode);              zero = strdup(CHECK_SGR(0, exit_attribute_mode));
         CHECK_SGR(3, enter_reverse_mode);          } else {
         CHECK_SGR(4, enter_blink_mode);              zero = strdup(TPARM_9(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0));
         CHECK_SGR(5, enter_dim_mode);          }
         CHECK_SGR(6, enter_bold_mode);          if (_nc_tparm_err)
         CHECK_SGR(7, enter_secure_mode);              _nc_warning("stack error in sgr(0) string");
         CHECK_SGR(8, enter_protected_mode);  
         CHECK_SGR(9, enter_alt_charset_mode);          if (zero != 0) {
         free(zero);              CHECK_SGR(1, enter_standout_mode);
               CHECK_SGR(2, enter_underline_mode);
               CHECK_SGR(3, enter_reverse_mode);
               CHECK_SGR(4, enter_blink_mode);
               CHECK_SGR(5, enter_dim_mode);
               CHECK_SGR(6, enter_bold_mode);
               CHECK_SGR(7, enter_secure_mode);
               CHECK_SGR(8, enter_protected_mode);
               CHECK_SGR(9, enter_alt_charset_mode);
               free(zero);
           } else {
               _nc_warning("sgr(0) did not return a value");
           }
       } else if (PRESENT(exit_attribute_mode) &&
                  set_attributes != CANCELLED_STRING) {
           if (_nc_syntax == SYN_TERMINFO)
               _nc_warning("missing sgr string");
     }      }
   
       if (PRESENT(exit_attribute_mode)) {
           char *check_sgr0 = _nc_trim_sgr0(tp);
   
           if (check_sgr0 == 0 || *check_sgr0 == '\0') {
               _nc_warning("trimmed sgr0 is empty");
           } else {
               show_where(2);
               if (check_sgr0 != exit_attribute_mode) {
                   DEBUG(2,
                         ("will trim sgr0\n\toriginal sgr0=%s\n\ttrimmed  sgr0=%s",
                          _nc_visbuf2(1, exit_attribute_mode),
                          _nc_visbuf2(2, check_sgr0)));
                   free(check_sgr0);
               } else {
                   DEBUG(2,
                         ("will not trim sgr0\n\toriginal sgr0=%s",
                          _nc_visbuf(exit_attribute_mode)));
               }
           }
       }
   #ifdef TRACE
       show_where(2);
       if (!auto_right_margin) {
           DEBUG(2,
                 ("can write to lower-right directly"));
       } else if (PRESENT(enter_am_mode) && PRESENT(exit_am_mode)) {
           DEBUG(2,
                 ("can write to lower-right by suppressing automargin"));
       } else if ((PRESENT(enter_insert_mode) && PRESENT(exit_insert_mode))
                  || PRESENT(insert_character) || PRESENT(parm_ich)) {
           DEBUG(2,
                 ("can write to lower-right by using inserts"));
       } else {
           DEBUG(2,
                 ("cannot write to lower-right"));
       }
   #endif
   
     /*      /*
      * Some standard applications (e.g., vi) and some non-curses       * Some standard applications (e.g., vi) and some non-curses
      * applications (e.g., jove) get confused if we have both ich/ich1 and       * applications (e.g., jove) get confused if we have both ich1 and
      * smir/rmir.  Let's be nice and warn about that, too, even though       * smir/rmir.  Let's be nice and warn about that, too, even though
      * ncurses handles it.       * ncurses handles it.
      */       */
     if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))      if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))
         && (PRESENT(insert_character) || PRESENT(parm_ich))) {          && PRESENT(parm_ich)) {
         _nc_warning("non-curses applications may be confused by ich/ich1 with smir/rmir");          _nc_warning("non-curses applications may be confused by ich1 with smir/rmir");
     }      }
   
     /*      /*
      * Finally, do the non-verbose checks       * Finally, do the non-verbose checks
      */       */
     if (save_check_termtype != 0)      if (save_check_termtype != 0)
         save_check_termtype(tp);          save_check_termtype(tp, literal);
 }  }

Legend:
Removed from v.1.29  
changed lines
  Added in v.1.30