"Fossies" - the Fresh Open Source Software Archive

Member "schily-2021-09-18/termcap/cap.c" (20 Aug 2021, 42966 Bytes) of package /linux/privat/schily-2021-09-18.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cap.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes reports: 2021-08-14_vs_2021-09-18 or 2021-07-29_vs_2021-09-18.

    1 /* @(#)cap.c    1.60 21/08/20 Copyright 2000-2021 J. Schilling */
    2 #include <schily/mconfig.h>
    3 #ifndef lint
    4 static  UConst char sccsid[] =
    5     "@(#)cap.c  1.60 21/08/20 Copyright 2000-2021 J. Schilling";
    6 #endif
    7 /*
    8  *  termcap     a TERMCAP compiler
    9  *
   10  *  The termcap database is an ASCII representation of the data
   11  *  so people may believe that there is no need for a compiler.
   12  *  Syntax checks and unification however are a property of compilers.
   13  *  We check for correct data types, output all entries in a unique
   14  *  order and recode all strings with the same escape notation.
   15  *  This is needed in to compare two entries and it makes life easier.
   16  *
   17  *  Copyright (c) 2000-2021 J. Schilling
   18  */
   19 /*
   20  * The contents of this file are subject to the terms of the
   21  * Common Development and Distribution License, Version 1.0 only
   22  * (the "License").  You may not use this file except in compliance
   23  * with the License.
   24  *
   25  * See the file CDDL.Schily.txt in this distribution for details.
   26  * A copy of the CDDL is also available via the Internet at
   27  * http://www.opensource.org/licenses/cddl1.txt
   28  *
   29  * When distributing Covered Code, include this CDDL HEADER in each
   30  * file and include the License file CDDL.Schily.txt from this distribution.
   31  */
   32 
   33 #include <schily/stdio.h>
   34 #include <schily/stdlib.h>
   35 #include <schily/unistd.h>
   36 #include <schily/standard.h>
   37 #include <schily/fcntl.h>
   38 #include <schily/string.h>
   39 #include <schily/termcap.h>
   40 #include <schily/getargs.h>
   41 #define SCHILY_PRINT
   42 #define GT_COMERR       /* #define comerr gtcomerr */
   43 #define GT_ERROR        /* #define error gterror   */
   44 #include <schily/schily.h>
   45 #include <schily/nlsdefs.h>
   46 
   47 #define TBUF    2048
   48 
   49 typedef struct {
   50     char    *tc_name;   /* Termcap name */
   51     char    *tc_iname;  /* Terminfo name */
   52     char    *tc_var;    /* Curses Variable name */
   53     char    *tc_comment;    /* Explanation */
   54     int tc_flags;
   55 } clist;
   56 
   57 /*
   58  * Definitions for tc_flags
   59  */
   60 #define C_BOOL      0x01    /* This is a boolean entry */
   61 #define C_INT       0x02    /* This is a numeric entry */
   62 #define C_STRING    0x04    /* This is a string entry */
   63 #define C_TC        0x08    /* This is a tc= string entry */
   64 #define C_PAD       0x10    /* This rentry requires padding */
   65 #define C_PADN      0x20    /* Padding based on affect count */
   66 #define C_PARM      0x40    /* Padding based on affect count */
   67 #define C_OLD       0x100   /* This is an old termcap only entry */
   68 #define C_CURIOUS   0x200   /* This is a curious termcap entry */
   69 
   70 /*
   71  * The list of capabilities for the termcap command.
   72  * This contains the Termcap Name, the Terminfo Name and a Comment.
   73  */
   74 LOCAL clist caplist[] = {
   75 #include "caplist.c"
   76 };
   77 
   78 LOCAL   int ncaps = sizeof (caplist) / sizeof (caplist[0]);
   79 
   80 LOCAL   BOOL    nodisabled = FALSE;
   81 LOCAL   BOOL    nounknown = FALSE;
   82 LOCAL   BOOL    nowarn = FALSE;
   83 LOCAL   BOOL    dooctal = FALSE;
   84 LOCAL   BOOL    docaret = FALSE;
   85 LOCAL   BOOL    gnugoto = FALSE;
   86 LOCAL   BOOL    oneline = FALSE;
   87 
   88 #ifdef  HAVE_SETVBUF
   89 LOCAL   char    obuf[4096];
   90 #else
   91 #ifdef  HAVE_SETVBUF
   92 LOCAL   char    obuf[BUFSIZ];
   93 #endif
   94 #endif
   95 
   96 LOCAL   void    init_clist  __PR((void));
   97 LOCAL   char *  tskip       __PR((char *ep));
   98 LOCAL   char *  tfind       __PR((char *ep, char *ent));
   99 LOCAL   void    dumplist    __PR((void));
  100 LOCAL   void    usage       __PR((int ex));
  101 EXPORT  int main        __PR((int ac, char **av));
  102 LOCAL   void    checkentries    __PR((char *tname, int *slenp));
  103 LOCAL   char    *type2str   __PR((int type));
  104 LOCAL   void    checkbad    __PR((char *tname, char *unknown, char *disabled));
  105 LOCAL   void    outcap      __PR((char *tname, char *unknown, char *disabled, BOOL obsolete_last));
  106 LOCAL   char *  checkgoto   __PR((char *tname, char *ent, char *cm, int col, int line));
  107 LOCAL   char *  checkquote  __PR((char *tname, char *s));
  108 LOCAL   char *  quote       __PR((char *s));
  109 LOCAL   char *  requote     __PR((char *s));
  110 LOCAL   void    compile_ent __PR((char *tname, BOOL do_tc, BOOL obsolete_last));
  111 LOCAL   void    read_names  __PR((char *fname, BOOL do_tc, BOOL obsolete_last));
  112 
  113 /*
  114  * Initialize the tc_flags struct member in "caplist".
  115  */
  116 LOCAL void
  117 init_clist()
  118 {
  119     int i;
  120     int flags = 0;
  121     int flags2;
  122 
  123     for (i = 0; i < ncaps; i++) {
  124         flags2 = 0;
  125 
  126         /*
  127          * Process meta entries.
  128          */
  129         if (caplist[i].tc_name[0] == '-' &&
  130             caplist[i].tc_name[1] == '-') {
  131         }
  132 
  133         if (streql(caplist[i].tc_var, "BOOL")) {
  134 
  135             flags &= ~(C_BOOL|C_INT|C_STRING);
  136             flags |= C_BOOL;
  137         }
  138         if (streql(caplist[i].tc_var, "INT")) {
  139 
  140             flags &= ~(C_BOOL|C_INT|C_STRING);
  141             flags |= C_INT;
  142         }
  143         if (streql(caplist[i].tc_var, "STRING")) {
  144 
  145             flags &= ~(C_BOOL|C_INT|C_STRING);
  146             flags |= C_STRING;
  147         }
  148         if (streql(caplist[i].tc_var, "TC")) {
  149 
  150             flags |= C_TC;
  151         }
  152         if (streql(caplist[i].tc_var, "COMMENT")) {
  153 
  154             flags &= ~(C_BOOL|C_INT|C_STRING);
  155             flags &= ~C_OLD;
  156         }
  157         if (streql(caplist[i].tc_var, "OBSOLETE")) {
  158             /*
  159              * OBSOLETE is used together with BOOL, INT or STRING
  160              */
  161             flags |= C_OLD;
  162         }
  163         if (streql(caplist[i].tc_var, "CURIOUS")) {
  164             /*
  165              * CURIOUS is a special tag for the tc= entry.
  166              */
  167             flags &= ~C_OLD;
  168             flags |= C_CURIOUS;
  169         }
  170         if (caplist[i].tc_comment[0] != '\0') {
  171             char    *p = caplist[i].tc_comment;
  172 
  173             p += strlen(p) - 1;
  174 
  175             if (*p == ')' && strchr("NP*", p[-1]) != NULL) {
  176                 while (strchr("NP*", *--p) != NULL) {
  177                     if (*p == 'N')
  178                         flags2 |= C_PARM;
  179                     if (*p == 'P')
  180                         flags2 |= C_PAD;
  181                     if (*p == '*')
  182                         flags2 |= C_PADN;
  183                 }
  184             }
  185         }
  186         caplist[i].tc_flags = flags | flags2;
  187     }
  188 }
  189 
  190 
  191 /*
  192  * Skip past next ':'.
  193  * If there are two consecutive ':', the returned pointer may point to ':'.
  194  *
  195  * A copy from the local function libxtermcap:tgetent.c:tskip()
  196  */
  197 LOCAL char *
  198 tskip(ep)
  199     register    char    *ep;
  200 {
  201     while (*ep) {
  202         if (*ep++ == ':')
  203             return (ep);
  204     }
  205     return (ep);
  206 }
  207 
  208 /*
  209  * A copy from the local function libxtermcap:tgetent.c:tfind()
  210  */
  211 LOCAL char *
  212 tfind(ep, ent)
  213     register    char    *ep;
  214             char    *ent;
  215 {
  216     register    char    e0 = ent[0];
  217     register    char    e1 = ent[1];
  218 
  219     for (;;) {
  220         ep = tskip(ep);
  221         if (*ep == '\0')
  222             break;
  223         if (*ep == ':')
  224             continue;
  225         if (e0 != *ep++)
  226             continue;
  227         if (*ep == '\0')
  228             break;
  229         if (e1 != *ep++)
  230             continue;
  231         return (ep);
  232     }
  233     return ((char *) NULL);
  234 }
  235 
  236 /*
  237  * Dump the all entries from "caplist".
  238  * Skip all special entries.
  239  */
  240 LOCAL void
  241 dumplist()
  242 {
  243     int i;
  244     int j;
  245     char    parms[8];
  246 
  247     for (i = 0; i < ncaps; i++) {
  248         int l;
  249         /*
  250          * Skip meta entries.
  251          */
  252         if (caplist[i].tc_name[0] == '-' &&
  253             caplist[i].tc_name[1] == '-')
  254             continue;
  255         if (caplist[i].tc_name[0] == '.' &&
  256             caplist[i].tc_name[1] == '.')
  257             continue;
  258 
  259         parms[0] = '\0';
  260         j = 0;
  261         if (caplist[i].tc_flags & C_PARM)
  262             parms[j++] = 'N';
  263         if (caplist[i].tc_flags & C_PAD)
  264             parms[j++] = 'P';
  265         if (caplist[i].tc_flags & C_PADN)
  266             parms[j++] = '*';
  267         parms[j] = '\0';
  268 
  269 
  270         l = strlen(caplist[i].tc_var);
  271         printf("{\"%s\",    \"%s\",%s\"%s\"},%s /*%c%c%-3s %s */\n",
  272             caplist[i].tc_name,
  273             caplist[i].tc_iname,
  274             strlen(caplist[i].tc_iname) >= 5 ? "\t":"\t\t",
  275             caplist[i].tc_var,
  276             l >= 20 ? "":
  277             l >= 12 ? "\t":
  278             l >= 4 ? "\t\t": "\t\t\t",
  279             (caplist[i].tc_flags & C_BOOL) ? 'B':
  280             (caplist[i].tc_flags & C_INT) ? 'I':
  281             (caplist[i].tc_flags & C_STRING) ? 'S': '?',
  282             (caplist[i].tc_flags & C_OLD) ? 'O': ' ',
  283             parms,
  284             caplist[i].tc_comment);
  285     }
  286 }
  287 
  288 LOCAL void
  289 usage(ex)
  290     int ex;
  291 {
  292     error("Usage: %s\n", get_progname());
  293     error("Options:\n");
  294     error("-e       use termcap entry from TERMCAP environment if present\n");
  295     error("-help        print this help\n");
  296     error("-version print version number\n");
  297     error("-dumplist    dump internal capability list\n");
  298     error("-inorder print caps in order, else print outdated caps last\n");
  299     error("-noinorder   switch off -inorder, print unknown and outdated caps last\n");
  300     error("-dooctal prefer '\\003' before '^C' when creating escaped strings\n");
  301     error("-docaret prefer '^M' before '\\r' when creating escaped strings\n");
  302     error("if=name      input file for termcap compiling\n");
  303     error("-gnugoto allow GNU tgoto() format extensions '%%C' and '%%m'.\n");
  304     error("-nodisabled  do not output disabled termcap entries\n");
  305     error("-nounknown   do not output unkonwn termcap entries\n");
  306     error("-nowarn      do not warn about problems that could be fixed\n");
  307     error("-oneline output termcap entries in a single line\n");
  308     error("-s       Output commands to set and export TERM and TERMCAP.\n");
  309     error("-tc      follow tc= entries and generate cumulative output\n");
  310     error("-v       increase verbosity level\n");
  311     error("With if= name, -inorder is default\n");
  312     exit(ex);
  313 }
  314 
  315 EXPORT int
  316 main(ac, av)
  317     int ac;
  318     char    *av[];
  319 {
  320     int cac;
  321     char    *const *cav;
  322     char    *tbuf;          /* Termcap buffer */
  323     char    unknown[5*TBUF];    /* Buffer fuer "unknown" Entries */
  324     char    disabled[5*TBUF];   /* Buffer fuer :..xx: Entries */
  325     char    *tname = getenv("TERM");
  326     char    *tcap = getenv("TERMCAP");
  327     int slen = 0;
  328     int fullen;
  329     int strippedlen;
  330     BOOL    help = FALSE;
  331     BOOL    prvers = FALSE;
  332     BOOL    dodump = FALSE;
  333     BOOL    inorder = FALSE;
  334     BOOL    noinorder = FALSE;
  335     BOOL    sflag = FALSE;
  336     int verbose = 0;
  337     BOOL    do_tc = FALSE;
  338     BOOL    useenv = FALSE;
  339     char    *infile = NULL;
  340 
  341     save_args(ac, av);
  342 
  343     (void) setlocale(LC_ALL, "");
  344 
  345 #ifdef  USE_NLS
  346 #if !defined(TEXT_DOMAIN)   /* Should be defined by cc -D */
  347 #define TEXT_DOMAIN "termcap"   /* Use this only if it weren't */
  348 #endif
  349     { char  *dir;
  350     dir = searchfileinpath("share/locale", F_OK,
  351                     SIP_ANY_FILE|SIP_NO_PATH, NULL);
  352     if (dir)
  353         (void) bindtextdomain(TEXT_DOMAIN, dir);
  354     else
  355 #if defined(PROTOTYPES) && defined(INS_BASE)
  356     (void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
  357 #else
  358     (void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
  359 #endif
  360     (void) textdomain(TEXT_DOMAIN);
  361     }
  362 #endif  /* USE_NLS */
  363 
  364 #ifdef  HAVE_SETVBUF
  365     setvbuf(stdout, obuf, _IOFBF, sizeof (obuf));
  366 #else
  367 #ifdef  HAVE_SETVBUF
  368     setbuf(stdout, obuf);
  369 #endif
  370 #endif
  371     init_clist();
  372 
  373     cac = ac;
  374     cav = av;
  375     cac--, cav++;
  376     if (getallargs(&cac, &cav, "help,version,e,dumplist,inorder,noinorder,oneline,v+,s,tc,if*,nodisabled,nounknown,nowarn,dooctal,docaret,gnugoto",
  377                 &help, &prvers,
  378                 &useenv,
  379                 &dodump, &inorder, &noinorder,
  380                 &oneline,
  381                 &verbose,
  382                 &sflag,
  383                 &do_tc,
  384                 &infile,
  385                 &nodisabled, &nounknown,
  386                 &nowarn, &dooctal, &docaret,
  387                 &gnugoto) < 0) {
  388         errmsgno(EX_BAD, "Bad option '%s'\n", cav[0]);
  389         usage(EX_BAD);
  390     }
  391     if (help)
  392         usage(0);
  393     if (prvers) {
  394         gtprintf("termcap %s %s (%s-%s-%s)\n\n", "1.60", "2021/08/20",
  395                 HOST_CPU, HOST_VENDOR, HOST_OS);
  396         gtprintf("Copyright (C) 2000-2021 %s\n", _("Jörg Schilling"));
  397         gtprintf("This is free software; see the source for copying conditions.  There is NO\n");
  398         gtprintf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
  399         exit(0);
  400     }
  401 
  402     if (dodump) {
  403         dumplist();
  404         exit(0);
  405     }
  406 
  407     if (infile)
  408         inorder = TRUE;
  409     if (noinorder)
  410         inorder = FALSE;
  411 
  412 
  413     if (!useenv && tcap && *tcap != '/')
  414         *tcap = '\0';
  415 
  416     if (infile) {
  417         char    env[2048];
  418 
  419         if (tcap)
  420             *tcap = '\0';
  421         if (tname)
  422             *tname = '\0';
  423         snprintf(env, sizeof (env), "TERMPATH=%s", infile);
  424         putenv(env);
  425         read_names(infile, do_tc, !inorder);
  426         exit(0);
  427     }
  428 
  429     /*
  430      * Check existence & unstripped Termcap len
  431      *
  432      * TCF_NO_TC    Don't follow tc= entries
  433      * TCF_NO_SIZE  Don't get actual ttysize (li#/co#)
  434      * TCF_NO_STRIP Don't strip down termcap buffer
  435      *
  436      * If called with the -s option, this is the only place where we
  437      * retrieve the termcap entry, so use the default settings in this case.
  438      */
  439     if (!sflag)
  440         tcsetflags((do_tc?0:TCF_NO_TC)|TCF_NO_SIZE|TCF_NO_STRIP);
  441     if (tgetent(NULL, tname) != 1)
  442         comerr("no term '%s' found\n", tname);
  443     tbuf = tcgetbuf();
  444     fullen = strlen(tbuf);
  445 
  446     if (sflag) {
  447         char    *p = getenv("SHELL");
  448         int is_csh = FALSE;
  449 
  450         if (p) {
  451             int len = strlen(p);
  452 
  453             if (len >= 3 && streql(&p[len-3], "csh"))
  454                 is_csh = TRUE;
  455         }
  456         if (is_csh) {
  457             /*
  458              * csh
  459              */
  460             printf("set noglob;\n");
  461             printf("setenv TERM %s;\n", tname);
  462             printf("setenv TERMCAP '%s';\n", tbuf);
  463             printf("unset noglob;\n");
  464         } else {
  465             /*
  466              * Bourne Shell and compatible
  467              */
  468             printf("export TERMCAP TERM;\n");
  469             printf("TERM=%s;\n", tname);
  470             printf("TERMCAP='%s';\n", tbuf);
  471         }
  472         exit(0);
  473     }
  474 
  475     /*
  476      * Get Stripped len
  477      */
  478     tcsetflags((do_tc?0:TCF_NO_TC)|TCF_NO_SIZE);
  479     tgetent(NULL, tname);
  480     tbuf = tcgetbuf();
  481     strippedlen = strlen(tbuf);
  482 
  483     if (verbose > 0)
  484         checkentries(tname, &slen);
  485 
  486     if (verbose > 1) {
  487         printf("tbuf: '%s'\n", tbuf);
  488         printf("full tbuf len: %d stripped tbuf len: %d\n", fullen, strippedlen);
  489         printf("string length: %d\n", slen);
  490     }
  491 
  492     checkbad(tname, unknown, disabled);
  493     outcap(tname, unknown, disabled, !inorder);
  494 
  495     return (0);
  496 }
  497 
  498 /*
  499  * Check entries for correct type and print them
  500  */
  501 LOCAL void
  502 checkentries(tname, slenp)
  503     char    *tname;
  504     int *slenp;
  505 {
  506     char    stbuf[10*TBUF]; /* String buffer zum zaehlen */
  507     char    *sbp;       /* String buffer Ende */
  508     int i;
  509     int b;      /* Fuer bool/int Werte */
  510     char    *p;
  511     char    *p2;
  512     char    *pe;
  513     char    *tbuf = tcgetbuf();
  514 
  515     /*
  516      * Print first part of Termcap entry
  517      */
  518     p = strchr(tbuf, ':');
  519     if (p)
  520         i = p - tbuf;
  521     else
  522         i = strlen(tbuf);
  523     printf("tbuf: '%.*s'\n", i, tbuf);
  524 
  525     b = strlen(tbuf);
  526     if (b > 2*TBUF) {
  527         error("%s: termcap entry too long (%d bytes).\n", tname, b);
  528         return;
  529     }
  530 
  531     sbp = stbuf;
  532     p2 = tbuf;
  533     for (i = 0; i < ncaps; i++) {
  534         /*
  535          * Skip meta entries.
  536          */
  537         if (caplist[i].tc_name[0] == '-' &&
  538             caplist[i].tc_name[1] == '-')
  539             continue;
  540 
  541         if (!(pe = tfind(tbuf, caplist[i].tc_name)))
  542             continue;
  543 
  544         if ((caplist[i].tc_flags & (C_BOOL|C_INT|C_STRING)) == 0)
  545             continue;
  546 
  547         if ((caplist[i].tc_flags & C_OLD) != 0) {
  548             printf("OBSOLETE ");
  549         }
  550 
  551         if (*pe == '@') {
  552             printf("'%s' -> %s", caplist[i].tc_name,
  553                 ((caplist[i].tc_flags & C_STRING) != 0)? "null @" :
  554                 (((caplist[i].tc_flags & C_INT) != 0)? "-1 @" :
  555                 (((caplist[i].tc_flags & C_BOOL) != 0)? "FALSE @" :
  556                 "unknown-@")));
  557             printf("        %s", caplist[i].tc_comment);
  558             printf("\n");
  559             continue;
  560         }
  561         if (i == ncaps -1) {
  562             p2 = tfind(p2, "tc");
  563             if (p2 == NULL)
  564                 break;
  565             if (*p2 == '=') {
  566                 char    *n = tskip(p2);
  567 
  568                 p = &p2[1];
  569                 n--;            /* Backstep from ':' */
  570                 if ((n - p) >= TBUF) {
  571                     error("NOTICE(%s). string '%.*s' too long.\n",
  572                     tname, (int)(n - p2)+2, p2-2);
  573                     break;
  574                 }
  575                 strlcpy(sbp, p, n-p+1);
  576                 p = sbp;    /* The tc= parameter */
  577             } else
  578                 break;
  579         } else {
  580             char    *e = tfind(tbuf, caplist[i].tc_name);
  581             char    *n = tskip(e);
  582 
  583             /*
  584              * e and n are always != NULL.
  585              */
  586             p = NULL;
  587             if (*e == '=' && (n - e) > 1024) {
  588                 /*
  589                  * Warn if the string is > 1024, but let up to
  590                  * 4096 bytes appear to be able to count the
  591                  * real length.
  592                  */
  593                 error("NOTICE(%s). string '%.*s' longer than %d.\n",
  594                     tname, (int)(n - e)+1, e-2, 1024);
  595             }
  596             if (*e != '=') {
  597                 /*
  598                  * Not a string type entry.
  599                  */
  600                 /* EMPTY */
  601                 ;
  602             } else if ((n - e) > 4*TBUF) {
  603                 error("NOTICE(%s). string '%.*s' too long.\n",
  604                     tname, (int)(n - e)+1, e-2);
  605             } else if ((sbp - stbuf) > 4*TBUF) {
  606                 error(
  607                 "NOTICE(%s). '%.*s' string table overflow.\n",
  608                     tname, (int)(n - e)+1, e-2);
  609             } else {
  610                 p = tgetstr(caplist[i].tc_name, &sbp);
  611             }
  612         }
  613         if (caplist[i].tc_name[0] == 'm' &&
  614             caplist[i].tc_name[1] == 'a' &&
  615             (caplist[i].tc_flags & C_STRING) == 0) {
  616             /*
  617              * The "ma" entry exists as numeric and string
  618              * capability. We are currently not looking for
  619              * the string capability, so ignore this entry.
  620              */
  621             /* EMPTY */
  622             ;
  623         } else if (p) {
  624             /*
  625              * XXX Option zum Deaktivieren des Quoten
  626              */
  627             p = quote(p);
  628             printf("'%s' -> '%s'", caplist[i].tc_name, p);
  629             printf("        %s", caplist[i].tc_comment);
  630 
  631             if ((caplist[i].tc_flags & C_STRING) == 0)
  632                 printf(" -> WARNING: TYPE mismatch");
  633             printf("\n");
  634             if (i == ncaps -1)
  635                 i--;
  636             continue;
  637         }
  638         b = tgetnum(caplist[i].tc_name);
  639 
  640         if (caplist[i].tc_name[0] == 'm' &&
  641             caplist[i].tc_name[1] == 'a' &&
  642             (caplist[i].tc_flags & C_INT) == 0) {
  643             /*
  644              * The "ma" entry exists as numeric and string
  645              * capability. We are currently not looking for
  646              * the numeric capability, so ignore this entry.
  647              */
  648             /* EMPTY */
  649             ;
  650         } else if (b >= 0) {
  651             printf("'%s' -> %d", caplist[i].tc_name, b);
  652             printf("        %s", caplist[i].tc_comment);
  653             if ((caplist[i].tc_flags & C_INT) == 0)
  654                 printf(" -> WARNING: TYPE mismatch");
  655             printf("\n");
  656             continue;
  657         }
  658 
  659         b = tgetflag(caplist[i].tc_name);
  660         printf("'%s' -> %s", caplist[i].tc_name, b?"TRUE":"FALSE");
  661         printf("        %s", caplist[i].tc_comment);
  662         if ((caplist[i].tc_flags & C_BOOL) == 0)
  663             printf(" -> WARNING: TYPE mismatch");
  664         printf("\n");
  665         continue;
  666 
  667     }
  668     if (slenp)
  669         *slenp = sbp - stbuf;
  670 }
  671 
  672 LOCAL char *
  673 type2str(type)
  674     int type;
  675 {
  676     switch (type & 0x07) {
  677 
  678     case C_INT: return ("INT");
  679     case C_STRING:  return ("STRING");
  680     case C_BOOL:    return ("BOOL");
  681     default:    return ("<unknown>");
  682     }
  683 }
  684 
  685 /*
  686  * Check for bad termcap entries
  687  */
  688 LOCAL void
  689 checkbad(tname, unknown, disabled)
  690     char    *tname;
  691     char    *unknown;
  692     char    *disabled;
  693 {
  694     char    ent[3];     /* Space to hold termcap entry */
  695     char    *up;        /* Unknown buffer Ende */
  696     char    *dp;        /* Disabled buffer Ende */
  697     int rb;     /* Fuer bool/int Werte */
  698     char    *rp;        /* Fuer string Werte */
  699     BOOL    found;      /* Correct type already found */
  700     int i;
  701     char    *p;
  702     char    *p2;
  703     char    *xp;
  704     char    *tbuf = tcgetbuf();
  705     BOOL    out_tty = isatty(STDOUT_FILENO);
  706 
  707     p = tskip(tbuf);
  708 
  709     i = strlen(tbuf);
  710     if (i > 2*TBUF) {
  711         printf("# BAD(%s). Skipping long entry (%d bytes): '%s'\n",
  712                     tname,
  713                     i,
  714                     tbuf);
  715         if (!out_tty)
  716         error("BAD(%s). Skipping long entry (%d bytes): '%.*s'\n",
  717                     tname,
  718                     i,
  719                     (int)(p - tbuf - 1), tbuf);
  720         return;
  721     }
  722 
  723     up = unknown;
  724     dp = disabled;
  725     while (*p) {
  726         while (*p == ':')
  727             p = tskip(p);
  728         if (*p == '\0')
  729             break;
  730         /*
  731          * Avoid to warn about bad termcap entries as long as we
  732          * implement support for the terminfo escape '\:'.
  733          */
  734         if (p > (tbuf+1) && p[-1] == ':' && p[-2] == '\\') {
  735             p = tskip(p);
  736             continue;
  737         }
  738         if (p[1] == '\0' ||
  739             p[1] == ':') {
  740             if (p[0] == '\t' || /* This is an indented line */
  741                 p[0] == ' ') {  /* also ignore single space */
  742                 p = tskip(p);
  743                 continue;
  744             }
  745             printf("# NOTICE(%s). Short entry (':%c%s') removed\n",
  746                 tname, p[0], p[1]?":":"");
  747             if (!out_tty)
  748             error("NOTICE(%s). Short entry (':%c%s') removed\n",
  749                 tname, p[0], p[1]?":":"");
  750             p = tskip(p);
  751             continue;
  752         }
  753         checkquote(tname, p);
  754         if (p[2] != ':' && p[2] != '@' && p[2] != '#' && p[2] != '=') {
  755             p2 = tskip(p);
  756             if (p[0] == ' ' || p[0] == '\t') {
  757                 printf("# BAD(%s). Skipping %sblank entry: '%.*s'\n",
  758                             tname,
  759                             (p[1] == ' ' || p[1] == '\t')?
  760                             "":"partially ",
  761                             (int)(p2 - p - 1), p);
  762                 if (!out_tty)
  763                 error("BAD(%s). Skipping %sblank entry: '%.*s'\n",
  764                             tname,
  765                             (p[1] == ' ' || p[1] == '\t')?
  766                             "":"partially ",
  767                             (int)(p2 - p - 1), p);
  768                 p = tskip(p);
  769                 continue;
  770             }
  771             if (p[0] == '.') {
  772                 if (strncmp(p, "..DISABLED:", 11) == 0 ||
  773                     strncmp(p, "..OBSOLETE:", 11) == 0 ||
  774                     strncmp(p, "..UNKNOWN:", 10) == 0) {
  775                     p = tskip(p);
  776                     continue;
  777                 }
  778                 printf("# NOTICE(%s). Disabled entry: '%.*s'\n",
  779                             tname, (int)(p2 - p - 1), p);
  780                 if (!out_tty)
  781                 error("NOTICE(%s). Disabled entry: '%.*s'\n",
  782                             tname, (int)(p2 - p - 1), p);
  783                 if (1) {
  784                     strncpy(dp, p, p2 - p);
  785                     dp += p2 - p;
  786                 } else {
  787                     strncpy(dp, p, p2 - p);
  788                     dp[p2 - p] = '\0';
  789                     strcpy(dp, requote(dp));
  790                     dp += strlen(dp);
  791                     *dp++ = ':';
  792                 }
  793                 p = tskip(p);
  794                 continue;
  795             }
  796             xp = p;
  797             if (xp > &tbuf[2])
  798                 xp = &p[-2];
  799             while (xp > tbuf && *xp != ':')
  800                 --xp;
  801             printf("# BAD(%s). Illegal entry (3rd char '%c' for ':%c%c%c'): '%.*s'\n",
  802                     tname, p[2], p[0], p[1], p[2], (int)(p2 - xp - 1), xp);
  803             if (!out_tty)
  804             error("BAD(%s). Illegal entry (3rd char '%c' for '%c%c%c'): '%.*s'\n",
  805                     tname, p[2], p[0], p[1], p[2], (int)(p2 - p - 1), p);
  806             p = tskip(p);
  807             continue;
  808         }
  809         if ((p[0] == ' ' || p[0] == '\t') &&
  810             (p[1] == ' ' || p[1] == '\t')) {
  811             p2 = tskip(p);
  812             printf("# BAD(%s). Skipping blank entry: '%.*s'\n",
  813                         tname, (int)(p2 - p - 1), p);
  814             if (!out_tty)
  815             error("BAD(%s). Skipping blank entry: '%.*s'\n",
  816                             tname, (int)(p2 - p - 1), p);
  817             p = tskip(p);
  818             continue;
  819         }
  820         strncpy(ent, p, 2);
  821         ent[2] = '\0';
  822 
  823         for (i = 0; i < ncaps; i++) {
  824             /*
  825              * Skip meta entries.
  826              */
  827             if (caplist[i].tc_name[0] == '-' &&
  828                 caplist[i].tc_name[1] == '-')
  829                 continue;
  830 
  831             if (caplist[i].tc_name[0] == 'm' &&
  832                 caplist[i].tc_name[1] == 'a' &&
  833                 (caplist[i].tc_flags & C_STRING) == 0) {
  834                 /*
  835                  * We found the "ma" entry in the numeric
  836                  * variant. If this was a string cap, continue
  837                  * searching for the matching caplist entry.
  838                  * The "ma=" entry is past "ma#" in our list.
  839                  */
  840                 if (p[2] == '=')
  841                     continue;
  842             }
  843 
  844             if (streql(ent, caplist[i].tc_name))
  845                 break;
  846         }
  847         if (i == ncaps) {
  848             p2 = tskip(p);
  849             printf("# NOTICE(%s). Unknown entry ('%s'): '%.*s'\n",
  850                         tname, ent, (int)(p2 - p - 1), p);
  851             if (!out_tty)
  852             error("NOTICE(%s). Unknown entry ('%s'): '%.*s'\n",
  853                         tname, ent, (int)(p2 - p - 1), p);
  854             if (1) {
  855                 strncpy(up, p, p2 - p);
  856                 up += p2 - p;
  857             } else {
  858                 strncpy(up, p, p2 - p);
  859                 up[p2 - p] = '\0';
  860                 strcpy(up, requote(up));
  861                 up += strlen(up);
  862                 *up++ = ':';
  863             }
  864         } else if ((caplist[i].tc_flags & (C_STRING|C_PARM)) == (C_STRING|C_PARM)) {
  865 
  866             if (p[2] == '=') {
  867                 char    buf[5*TBUF];
  868                 char    *bp = buf;
  869                 char    *val = tdecode(&p[3], &bp);
  870 
  871                 checkgoto(tname, ent, val, 0, 0);
  872             }
  873         }
  874 
  875         if (i == ncaps) {
  876             /*
  877              * This is an unknown entry that has already been
  878              * handled above. We cannot check the type for unknown
  879              * entries, so continue to check the other entries.
  880              */
  881             p = tskip(p);
  882             continue;
  883         }
  884         found = FALSE;
  885         rp = tgetstr(caplist[i].tc_name, NULL);
  886         if (rp)
  887             found = TRUE;
  888         if (caplist[i].tc_name[0] == 'm' &&
  889             caplist[i].tc_name[1] == 'a' &&
  890             (caplist[i].tc_flags & C_STRING) == 0) {
  891             /* EMPTY */
  892             ;
  893         } else if (rp) {
  894             if ((caplist[i].tc_flags & C_STRING) == 0) {
  895                 p2 = tskip(p);
  896                 printf("# BAD(%s). Type mismatch '%s' in '%.*s' is STRING should be %s\n",
  897                     tname, ent, (int)(p2 - p - 1), p, type2str(caplist[i].tc_flags));
  898             }
  899         }
  900         if (rp) {       /* tgetstr() return was malloc()ed */
  901             free(rp);
  902             rp = NULL;
  903         }
  904         rb = tgetnum(caplist[i].tc_name);
  905         if (rb >= 0)
  906             found = TRUE;
  907         if (caplist[i].tc_name[0] == 'm' &&
  908             caplist[i].tc_name[1] == 'a' &&
  909             (caplist[i].tc_flags & C_INT) == 0) {
  910             /* EMPTY */
  911             ;
  912         } else if (rb >= 0) {
  913             if ((caplist[i].tc_flags & C_INT) == 0) {
  914                 p2 = tskip(p);
  915                 printf("# BAD(%s). Type mismatch '%s' in '%.*s' is INT should be %s\n",
  916                     tname, ent, (int)(p2 - p - 1), p, type2str(caplist[i].tc_flags));
  917             }
  918         }
  919 
  920         if (!found && p[2] != '@') {
  921             rb = tgetflag(caplist[i].tc_name);
  922             if ((caplist[i].tc_flags & C_BOOL) == 0) {
  923                 p2 = tskip(p);
  924                 if (rb == 0 && p[2] != '@') {
  925                     printf("# NOTICE(%s). Canceled entry '%s@' followed by '%.*s' expected type %s\n",
  926                         tname, ent, (int)(p2 - p - 1), p, type2str(caplist[i].tc_flags));
  927                 } else {
  928                     printf("# BAD(%s). Type mismatch '%s' in '%.*s' is BOOL should be %s\n",
  929                         tname, ent, (int)(p2 - p - 1), p, type2str(caplist[i].tc_flags));
  930                 }
  931             }
  932         }
  933 
  934         p = tskip(p);
  935     }
  936     *up = '\0';
  937     *dp = '\0';
  938     if (unknown[0] != '\0') {
  939         error("NOTICE(%s). Unknown: '%s'\n", tname, unknown);
  940     }
  941     if (disabled[0] != '\0') {
  942         error("NOTICE(%s). Disabled: '%s'\n", tname, disabled);
  943     }
  944 }
  945 
  946 LOCAL int   itotype[6] = { 0, C_BOOL, C_INT, C_STRING, 0, C_TC|C_STRING };
  947 #ifdef  DEBUG
  948 LOCAL char  *itoname[6] = { "0", "C_BOOL", "C_INT", "C_STRING", "C_UNKNOWN", "C_TC" };
  949 #endif
  950 
  951 LOCAL void
  952 outcap(tname, unknown, disabled, obsolete_last)
  953     char    *tname;
  954     char    *unknown;
  955     char    *disabled;
  956     BOOL    obsolete_last;  /* obsolete_last == !inorder */
  957 {
  958     char    stbuf[10*TBUF]; /* String buffer zum zaehlen */
  959     char    line[10*TBUF];  /* Fuer Einzelausgabe */
  960     char    *sbp;       /* String buffer Ende */
  961     int llen;
  962     int curlen;
  963     int i;
  964     int j = 0;
  965     int b;      /* Fuer bool/int Werte */
  966     int flags;
  967     char    *p;
  968     char    *p2;
  969     char    *pe;
  970     char    *tbuf = tcgetbuf();
  971 BOOL    didobsolete = FALSE;
  972 
  973 
  974     b = strlen(tbuf);
  975     if (b > 2*TBUF) {
  976         return;
  977     }
  978 
  979     p = strchr(tbuf, ':');
  980     if (p)
  981         i = p - tbuf;
  982     else
  983         i = strlen(tbuf);
  984     printf("%.*s:", i, tbuf);   /* Print Terminal name/label */
  985     llen = i + 1;
  986 
  987     sbp = stbuf;
  988     flags = 0;
  989     p2 = tbuf;
  990 
  991     /*
  992      * If obsolete_last is FALSE, then this loop goes from j=1..5,
  993      * else, there is only one loop with j=-1 as the loop stops with j==0.
  994      */
  995     for (j = obsolete_last ? -1:1; j != 0 && j <= 5; j++)
  996     for (i = 0; i < ncaps; i++) {
  997 #ifdef  DEBUG
  998         flush();
  999         error("caplist[%d]->'%c%c' (%s)->'%.10s' j=%d\n",
 1000             i, caplist[i].tc_name[0], caplist[i].tc_name[1],
 1001             itoname[j], tfind(tbuf, caplist[i].tc_name), j);
 1002 #endif
 1003         /*
 1004          * Skip meta entries.
 1005          */
 1006         if (caplist[i].tc_name[0] == '-' &&
 1007             caplist[i].tc_name[1] == '-')
 1008             continue;
 1009 
 1010         /*
 1011          * Print unknown entries in order at the end of the respective
 1012          * block. Do not mark inline them and requote the strings.
 1013          */
 1014         if (j >= 1 && j <= 3 && i == ncaps -1) {
 1015             char    *px = unknown;
 1016             int t = itotype[j];
 1017             char    *val = NULL;    /* Keep GCC happy */
 1018 
 1019             while (*px) {
 1020                 pe = px;
 1021                 px = tskip(pe);
 1022 
 1023                 if (t == C_BOOL) {
 1024                     if (pe[2] != ':' && pe[2] != '@')
 1025                         continue;
 1026                 } else if (t == C_INT) {
 1027                     if (pe[2] != '#')
 1028                         continue;
 1029                 } else {
 1030                     if (pe[2] != '=')
 1031                         continue;
 1032                     val = requote(&pe[3]);
 1033                 }
 1034                 p = pe;
 1035                 curlen = px - pe;
 1036                 if (p[2] == '=')
 1037                     curlen = strlen(val) + 4;
 1038                 if (curlen <= 0)
 1039                     break;
 1040                 if (flags != t && !oneline) {
 1041                     printf("\\\n\t:");
 1042                     llen = 9;
 1043                     flags = t;
 1044                 }
 1045                 if ((llen > 9) && ((llen + curlen) >= 79 &&
 1046                    !oneline)) {
 1047                     printf("\\\n\t:");
 1048                     llen = 9 + curlen;
 1049                 } else {
 1050                     llen += curlen;
 1051                 }
 1052                 if (p[2] == '=')
 1053                     printf("%.2s=%.*s:", p, curlen, val);
 1054                 else
 1055                     printf("%.*s", curlen, p);
 1056             }
 1057         }
 1058         /*
 1059          * If j < 0, sort order is order from caplist array
 1060          * and thus obsolete entries appear past non obsolete entries.
 1061          *
 1062          * If j > 0, sort order is BOOL -> INT -> STRING
 1063          */
 1064         if (j > 0 && (caplist[i].tc_flags & (C_BOOL|C_INT|C_STRING|C_TC)) != itotype[j])
 1065             continue;
 1066 
 1067         if ((caplist[i].tc_flags & (C_BOOL|C_INT|C_STRING)) == 0) {
 1068             if (streql(caplist[i].tc_var, "unknown")) {
 1069                 if (j > 0)  /* Printed in order before */
 1070                     continue;
 1071                 if (unknown[0] == '\0')
 1072                     continue;
 1073                 if (nounknown)
 1074                     continue;
 1075 
 1076                 if ((llen > 9 || flags == 0) && !oneline)
 1077                     printf("\\\n\t:");
 1078                 if (!oneline) {
 1079                     printf("%s%s",
 1080                         "..UNKNOWN:\\\n\t:",
 1081                         unknown);
 1082                 }
 1083                 llen = 99;
 1084             } else {
 1085                 if (disabled[0] == '\0')
 1086                     continue;
 1087                 if (nodisabled)
 1088                     continue;
 1089 
 1090                 if ((llen > 9 || flags == 0) && !oneline)
 1091                     printf("\\\n\t:");
 1092                 if (!oneline) {
 1093                     printf("%s%s",
 1094                         "..DISABLED:\\\n\t:",
 1095                         disabled);
 1096                 }
 1097                 llen = 99;
 1098             }
 1099             continue;
 1100         }
 1101 
 1102         if (!(pe = tfind(tbuf, caplist[i].tc_name)))
 1103             continue;
 1104 
 1105         if (*pe == '@') {
 1106             curlen = sprintf(line, "%s@:", caplist[i].tc_name);
 1107             goto printit;
 1108         }
 1109         if (i == ncaps -1) {
 1110             /*
 1111              * tfind() first calls tskip() but the last printed
 1112              * entry may be just before the "tc=" enty and did
 1113              * already call p2 = tskip(pe). In this case, we must
 1114              * not call tfind().
 1115              */
 1116             if (strncmp(p2, "tc=", 3) == 0)
 1117                 p2 = &p2[2];
 1118             else
 1119                 p2 = tfind(p2, "tc");
 1120             if (p2 == NULL)
 1121                 break;              /* End of loop */
 1122             if (*p2 == '=') {
 1123                 p = &p2[1];
 1124                 strcpy(sbp, p);
 1125                 if ((p = strchr(sbp, ':')) != NULL)
 1126                     *p = '\0';
 1127                 p = sbp;
 1128             } else {
 1129                 break;              /* End of loop */
 1130             }
 1131             curlen = sprintf(line, "%s=%s:", caplist[i].tc_name, p);
 1132             i--;
 1133             goto printit;
 1134         } else {
 1135             p = tgetstr(caplist[i].tc_name, &sbp);
 1136         }
 1137 
 1138         if (p) {
 1139             if (caplist[i].tc_flags & C_INT) {  /* check type for "ma" */
 1140                 if (caplist[i].tc_name[0] == 'm' &&
 1141                     caplist[i].tc_name[1] == 'a') {
 1142                     /*
 1143                      * The "ma" entry exists as numeric and
 1144                      * string capability. We are currently
 1145                      * not looking for the string
 1146                      * capability, so try to check for int.
 1147                      */
 1148                     goto trynum;
 1149                 }
 1150             }
 1151 
 1152             if (caplist[i].tc_flags & C_STRING) {   /* check type for "ma" */
 1153                 curlen = sprintf(line, "%s=%s:", caplist[i].tc_name, quote(p));
 1154                 goto printit;
 1155             } else {
 1156                 p2 = tskip(pe);
 1157                 error("%s: Illegal entry '%s' '%.*s' (should not be a string)\n",
 1158                         tname, caplist[i].tc_name,
 1159                         (int)(p2 - pe - 1), pe);
 1160                 continue;
 1161             }
 1162         }
 1163 trynum:
 1164         b = tgetnum(caplist[i].tc_name);
 1165         if (b >= 0) {
 1166             if (caplist[i].tc_flags & C_INT) {  /* check type for "ma" */
 1167                 curlen = sprintf(line, "%s#%d:", caplist[i].tc_name, b);
 1168                 goto printit;
 1169             } else {
 1170                 p2 = tskip(pe);
 1171                 if (caplist[i].tc_name[0] == 'm' &&
 1172                     caplist[i].tc_name[1] == 'a') {
 1173                     /*
 1174                      * The "ma" entry exists as numeric and
 1175                      * string capability. We are currently
 1176                      * not looking for the string
 1177                      * capability. We will check the string
 1178                      * entry later in the caplist[i] loop.
 1179                      */
 1180                     continue;
 1181                 }
 1182                 error("%s: Illegal entry '%s' '%.*s' (should not be a number)\n",
 1183                         tname, caplist[i].tc_name,
 1184                         (int)(p2 - pe - 1), pe);
 1185                 continue;
 1186             }
 1187         }
 1188 
 1189         b = tgetflag(caplist[i].tc_name);
 1190         if (b != 0) {
 1191             if (caplist[i].tc_flags & C_BOOL) {
 1192                 curlen = sprintf(line, "%s:", caplist[i].tc_name);
 1193                 goto printit;
 1194             } else {
 1195                 p2 = tskip(pe);
 1196                 error("%s: Illegal entry '%s' '%.*s' (should not be a bool)\n",
 1197                         tname, caplist[i].tc_name,
 1198                         (int)(p2 - pe - 1), pe);
 1199                 continue;
 1200             }
 1201         }
 1202         p2 = tskip(pe);
 1203         if (caplist[i].tc_flags & C_INT) {  /* check type for "ma" */
 1204             if (caplist[i].tc_name[0] == 'm' &&
 1205                 caplist[i].tc_name[1] == 'a' &&
 1206                 *pe == '=') {
 1207                 /*
 1208                  * This entry will be checked later.
 1209                  * The "ma=" entry is past "ma#" in our list.
 1210                  */
 1211                 continue;
 1212             }
 1213         }
 1214         error("%s: Illegal entry '%s' '%.*s'\n",
 1215                         tname, caplist[i].tc_name,
 1216                         (int)(p2 - pe - 1), pe);
 1217         continue;
 1218 
 1219 printit:
 1220         if (!oneline &&
 1221             flags != (caplist[i].tc_flags & (C_BOOL|C_INT|C_STRING|C_TC))) {
 1222             printf("\\\n\t:");
 1223             llen = 9;
 1224             flags = caplist[i].tc_flags & (C_BOOL|C_INT|C_STRING|C_TC);
 1225         }
 1226 
 1227         /*
 1228          * If j > 0, sort order is BOOL -> INT -> STRING
 1229          * Do not print the OBSOLETE header in this case.
 1230          */
 1231         if (!oneline &&
 1232             j < 0 && (caplist[i].tc_flags & C_OLD) != 0) {
 1233             if (!didobsolete) {
 1234                 if (llen > 9)
 1235                     printf("\\\n\t:");
 1236                 if (!oneline) {
 1237                     printf("..OBSOLETE:\\\n\t:");
 1238                 }
 1239                 llen = 9;
 1240                 didobsolete = TRUE;
 1241             }
 1242         }
 1243 
 1244 /*error("line: '%s', llen: %d curlen: %d sum: %d\n", line, llen, curlen, llen + curlen);*/
 1245         p = line;
 1246         curlen = strlen(p);
 1247         if ((llen > 9) && ((llen + curlen) >= 79) && !oneline) {
 1248             printf("\\\n\t:");
 1249             llen = 9 + curlen;
 1250         } else {
 1251             llen += curlen;
 1252         }
 1253         printf("%s", p);
 1254     }
 1255     printf("\n");
 1256     flush();
 1257 }
 1258 
 1259 
 1260 #define OBUF_SIZE   80
 1261 
 1262 /*
 1263  * Perform string preparation/conversion for cursor addressing.
 1264  * The string cm contains a format string.
 1265  *
 1266  * A copy from the local function libxtermcap:tgoto.c:tgoto()
 1267  */
 1268 LOCAL char *
 1269 checkgoto(tname, ent, cm, col, line)
 1270     char    *tname;
 1271     char    *ent;
 1272     char    *cm;
 1273     int col;
 1274     int line;
 1275 {
 1276     static  char    outbuf[OBUF_SIZE];  /* Where the output goes to */
 1277         char    xbuf[10];       /* for %. corrections       */
 1278     register char   *op = outbuf;
 1279     register char   *p = cm;
 1280     register int    c;
 1281     register int    val = line;
 1282         int usecol = 0;
 1283         BOOL    out_tty = isatty(STDOUT_FILENO);
 1284         BOOL    hadbad = FALSE;
 1285 
 1286     if (p == 0) {
 1287 badfmt:
 1288         /*
 1289          * Be compatible to 'vi' in case of bad format.
 1290          */
 1291         return ("OOPS");
 1292     }
 1293     xbuf[0] = 0;
 1294     while ((c = *p++) != '\0') {
 1295         if ((op + 5) >= &outbuf[OBUF_SIZE])
 1296             goto overflow;
 1297 
 1298         if (c != '%') {
 1299             *op++ = c;
 1300             continue;
 1301         }
 1302         switch (c = *p++) {
 1303 
 1304         case '%':       /* %% -> %          */
 1305                     /* This is from BSD     */
 1306             *op++ = c;
 1307             continue;
 1308 
 1309         case 'd':       /* output as printf("%d"... */
 1310                     /* This is from BSD (use val)   */
 1311             if (val < 10)
 1312                 goto onedigit;
 1313             if (val < 100)
 1314                 goto twodigits;
 1315             /*FALLTHROUGH*/
 1316 
 1317         case '3':       /* output as printf("%03d"...   */
 1318                     /* This is from BSD (use val)   */
 1319             if (val >= 1000) {
 1320                 *op++ = '0' + (val / 1000);
 1321                 val %= 1000;
 1322             }
 1323             *op++ = '0' + (val / 100);
 1324             val %= 100;
 1325             /*FALLTHROUGH*/
 1326 
 1327         case '2':       /* output as printf("%02d"...   */
 1328                     /* This is from BSD (use val)   */
 1329         twodigits:
 1330             *op++ = '0' + val / 10;
 1331         onedigit:
 1332             *op++ = '0' + val % 10;
 1333         nextparam:
 1334             usecol ^= 1;
 1335         setval:
 1336             val = usecol ? col : line;
 1337             continue;
 1338 
 1339         case 'C':       /* For c-100: print quotient of */
 1340                     /* value by 96, if nonzero, */
 1341                     /* then do like %+.     */
 1342                     /* This is from GNU (use val)   */
 1343             if (!gnugoto)
 1344                 goto badchar;
 1345             if (val >= 96) {
 1346                 *op++ = val / 96;
 1347                 val %= 96;
 1348             }
 1349             /*FALLTHROUGH*/
 1350 
 1351         case '+':       /* %+x like %c but add x before */
 1352                     /* This is from BSD (use val)   */
 1353             val += *p++;
 1354             /*FALLTHROUGH*/
 1355 
 1356         case '.':       /* output as printf("%c" but... */
 1357                     /* This is from BSD (use val)   */
 1358             if (usecol || UP)  {
 1359                 /*
 1360                  * We assume that backspace works and we don't
 1361                  * need to test for BC too.
 1362                  *
 1363                  * If you did not call stty tabs while termcap
 1364                  * is used you will get other problems, so we
 1365                  * exclude tab from the execptions.
 1366                  */
 1367                 while (val == 0 || val == '\004' ||
 1368                     /* val == '\t' || */ val == '\n') {
 1369 
 1370                     strcat(xbuf,
 1371                         usecol ? (BC?BC:"\b") : UP);
 1372                     val++;
 1373                 }
 1374             }
 1375             *op++ = val;
 1376             goto nextparam;
 1377 
 1378         case '>':       /* %>xy if val > x add y    */
 1379                     /* This is from BSD (chng state)*/
 1380 
 1381             if (val > *p++)
 1382                 val += *p++;
 1383             else
 1384                 p++;
 1385             continue;
 1386 
 1387         case 'B':       /* convert to BCD char coding   */
 1388                     /* This is from BSD (chng state)*/
 1389 
 1390             val += 6 * (val / 10);
 1391             continue;
 1392 
 1393         case 'D':       /* weird Delta Data conversion  */
 1394                     /* This is from BSD (chng state)*/
 1395 
 1396             val -= 2 * (val % 16);
 1397             continue;
 1398 
 1399         case 'i':       /* increment row/col by one */
 1400                     /* This is from BSD (chng state)*/
 1401             col++;
 1402             line++;
 1403             val++;
 1404             continue;
 1405 
 1406         case 'm':       /* xor both parameters by 0177  */
 1407                     /* This is from GNU (chng state)*/
 1408             if (!gnugoto)
 1409                 goto badchar;
 1410             col ^= 0177;
 1411             line ^= 0177;
 1412             goto setval;
 1413 
 1414         case 'n':       /* xor both parameters by 0140  */
 1415                     /* This is from BSD (chng state)*/
 1416             col ^= 0140;
 1417             line ^= 0140;
 1418             goto setval;
 1419 
 1420         case 'r':       /* reverse row/col      */
 1421                     /* This is from BSD (chng state)*/
 1422             usecol = 1;
 1423             goto setval;
 1424 
 1425         default:
 1426         badchar:
 1427             printf("# BAD(%s). Bad format '%%%c' in '%s=%s'\n", tname, c, ent, quote(cm));
 1428             if (!out_tty)
 1429             error("BAD(%s). Bad format '%%%c' in '%s=%s'\n", tname, c, ent, quote(cm));
 1430             hadbad = TRUE;
 1431 /*          goto badfmt;*/
 1432         }
 1433     }
 1434     /*
 1435      * append to output if there is space...
 1436      */
 1437     if ((op + strlen(xbuf)) >= &outbuf[OBUF_SIZE]) {
 1438 overflow:
 1439         printf("# BAD(%s). Buffer overflow in '%s=%s'\n", tname, ent, quote(cm));
 1440         if (!out_tty)
 1441         error("BAD(%s). Buffer overflow in '%s=%s'\n", tname, ent, quote(cm));
 1442         return ("OVERFLOW");
 1443     }
 1444     if (hadbad)
 1445         goto badfmt;
 1446 
 1447     for (p = xbuf; *p; )
 1448         *op++ = *p++;
 1449     *op = '\0';
 1450     return (outbuf);
 1451 }
 1452 
 1453 LOCAL   char    _quotetab[] = "E^^\\\\n\nr\rt\tb\bf\f";
 1454 
 1455 #define isoctal(c)  ((c) >= '0' && (c) <= '7')
 1456 
 1457 LOCAL char *
 1458 checkquote(tname, s)
 1459     char    *tname;
 1460     char    *s;
 1461 {
 1462 static          char    out[5*TBUF];
 1463             char    nm[16];
 1464             int i;
 1465     register    Uchar   c;
 1466     register    Uchar   *ep = (Uchar *)s;
 1467     register    Uchar   *bp;
 1468     register    Uchar   *tp;
 1469             char    *p;
 1470             BOOL    out_tty = isatty(STDOUT_FILENO);
 1471 
 1472     out[0] = '\0';
 1473     if (s[0] == ' ' || s[0] == '\t')
 1474         return (out);
 1475 
 1476     ep = (Uchar *)strchr(s, '=');
 1477     if (ep == NULL)
 1478         return (out);
 1479     i = ep - (Uchar *)s;
 1480     ep++;
 1481     p = tskip(s);
 1482     if (ep > (Uchar *)p)
 1483         return (out);
 1484 
 1485     strlcpy(nm, s, sizeof (nm));
 1486     if (i < sizeof (nm))
 1487         nm[i] = '\0';
 1488 
 1489     bp = (Uchar *)out;
 1490 
 1491     for (; (c = *ep++) && c != ':'; *bp++ = c) {
 1492         if (c == '^') {
 1493             c = *ep++;
 1494             if (c == '\0') {
 1495                 printf(
 1496                 "# NOTICE(%s). ^ quoting followed by no character in '%s'\n",
 1497                             tname, s);
 1498                 if (!out_tty)
 1499                 error("NOTICE(%s). ^ quoting followed by no character in '%s'\n",
 1500                             tname, s);
 1501                 break;
 1502             }
 1503             c &= 0x1F;
 1504         } else if (c == '\\') {
 1505             c = *ep++;
 1506             if (c == '\0') {
 1507                 printf(
 1508                 "# NOTICE(%s). \\ quoting followed by no character in '%s'\n",
 1509                             tname, s);
 1510                 if (!out_tty)
 1511                 error("NOTICE(%s). \\ quoting followed by no character in '%s'\n",
 1512                             tname, s);
 1513                 break;
 1514             }
 1515             if (isoctal(c)) {
 1516                 for (c -= '0', i = 3; --i > 0 && isoctal(*ep); ) {
 1517                     c <<= 3;
 1518                     c |= *ep++ - '0';
 1519                 }
 1520                 if (c == 0) {
 1521                     char    *p2 = tskip(s);
 1522                     int len;
 1523                     int pos = (char *)ep - s;
 1524 
 1525                     len = p2 - s - (*p2?1:0);
 1526                     pos -= 4-i;
 1527                     if (!nowarn && nm[0] != '.') {
 1528                     printf("# NOTICE(%s). NULL char (fixed) in entry ('%s') at abs position %d in '%.*s'\n",
 1529                             tname, nm, pos, len, s);
 1530                     if (!out_tty)
 1531                     error("NOTICE(%s). NULL char (fixed) in entry ('%s') at abs position %d in '%.*s'\n",
 1532                             tname, nm, pos, len, s);
 1533                     }
 1534                 }
 1535 #ifdef  __checkoctal__
 1536                 if (i > 0) {
 1537                     char    *p2 = tskip(s);
 1538                     int len;
 1539                     int pos = (char *)ep - s;
 1540 
 1541                     len = p2 - s - (*p2?1:0);
 1542                     printf(
 1543                     "# NOTICE(%s). Nonoctal char '%c' in entry ('%s') at position %d (abs %d) in '%.*s'\n",
 1544                             tname, *ep, nm, 4-i, pos, len, s);
 1545                     if (!out_tty)
 1546                     error("NOTICE(%s). Nonoctal char '%c' in entry ('%s') at position %d (abs %d) in '%.*s'\n",
 1547                             tname, *ep, nm, 4-i, pos, len, s);
 1548                 }
 1549 #endif
 1550             } else {
 1551                 for (tp = (Uchar *)_quotetab; *tp; tp++) {
 1552                     if (*tp++ == c) {
 1553                         c = *tp;
 1554                         break;
 1555                     }
 1556                 }
 1557                 /*
 1558                  * Terminfo quotes not in termcap:
 1559                  * \a   ->  '^G'
 1560                  * \e   ->  '^['
 1561                  * \:   ->  ':'
 1562                  * \,   ->  ','
 1563                  * \s   ->  ' '
 1564                  * \l   ->  '\n'
 1565                  */
 1566                 if (*tp == '\0') {
 1567                     char    *p2 = tskip(s);
 1568                     int len;
 1569                     int pos = (char *)&ep[-1] - s;
 1570 
 1571                     len = p2 - s - (*p2?1:0);
 1572                     if (!nowarn) {
 1573                     printf("# NOTICE(%s). Badly quoted char '\\%c' %sin ('%s') at abs position %d in '%.*s'\n",
 1574                             tname, c, strchr("ae:,sl", c)?"(fixed) ":"", nm, pos, len, s);
 1575                     if (!out_tty)
 1576                     error("NOTICE(%s). Badly quoted char '\\%c' %sin ('%s') at abs position %d in '%.*s'\n",
 1577                             tname, c, strchr("ae:,sl", c)?"(fixed) ":"", nm, pos, len, s);
 1578                     }
 1579                 }
 1580             }
 1581         }
 1582     }
 1583     *bp++ = '\0';
 1584     return (out);
 1585 }
 1586 
 1587 LOCAL char *
 1588 quote(s)
 1589     char    *s;
 1590 {
 1591 static  char    out[10*TBUF];
 1592     char    *p1;
 1593     char    *p2;
 1594     unsigned char   c;
 1595 
 1596     for (p1 = s, p2 = out; *p1; ) {
 1597         c = *p1++;
 1598         if (c == 033) {     /* ESC -> \E */
 1599             *p2++ = '\\';
 1600             *p2++ = 'E';
 1601         } else if (c == '\\') { /* \ -> \\ */
 1602             *p2++ = '\\';
 1603             *p2++ = '\\';
 1604         } else if (c == '^') {  /* ^ -> \^ */
 1605             *p2++ = '\\';
 1606             *p2++ = '^';
 1607         } else if (!docaret && c == '\r') { /* CR -> \r */
 1608             *p2++ = '\\';
 1609             *p2++ = 'r';
 1610         } else if (!docaret && c == '\n') { /* NL -> \n */
 1611             *p2++ = '\\';
 1612             *p2++ = 'n';
 1613         } else if (!docaret && c == '\t') { /* TAB -> \t */
 1614             *p2++ = '\\';
 1615             *p2++ = 't';
 1616         } else if (!docaret && c == '\b') { /* BS -> \b */
 1617             *p2++ = '\\';
 1618             *p2++ = 'b';
 1619         } else if (!docaret && c == '\f') { /* FF -> \f */
 1620             *p2++ = '\\';
 1621             *p2++ = 'f';
 1622         } else if (!dooctal &&
 1623                 c <= 0x1F) {    /* Control C -> ^C */
 1624             *p2++ = '^';
 1625             *p2++ = '@' + c;
 1626         } else if (c == ':' || c <= 0x1F || c >= 0x7F) {
 1627             *p2++ = '\\';
 1628             *p2++ = '0' + (c / 64) % 8;
 1629             *p2++ = '0' + (c / 8) % 8;
 1630             *p2++ = '0' + c % 8;
 1631         } else {
 1632             *p2++ = c;
 1633         }
 1634     }
 1635     *p2 = '\0';
 1636     return (out);
 1637 }
 1638 
 1639 /*
 1640  *   A number of escape sequences are  provided  in  the  string-
 1641  *   valued capabilities for easy encoding of characters there:
 1642  *
 1643  *        \E   maps to ESC
 1644  *        ^X   maps to CTRL-X for any appropriate character X
 1645  *        \n   maps to LINEFEED
 1646  *        \r   maps to RETURN
 1647  *        \t   maps to TAB
 1648  *        \b   maps to BACKSPACE
 1649  *        \f   maps to FORMFEED
 1650  *
 1651  *   Finally, characters may be given as three octal digits after
 1652  *   a  backslash  (for  example,  \123),  and  the  characters ^
 1653  *   (caret) and \ (backslash) may be given as \^ and \\  respec-
 1654  *   tively.
 1655  *
 1656  *   If it is necessary to place a : in a capability it  must  be
 1657  *   escaped in octal as \072.
 1658  *
 1659  *   If it is necessary to place a  NUL  character  in  a  string
 1660  *   capability  it  must be encoded as \200.  (The routines that
 1661  *   deal with termcap use C strings and strip the high  bits  of
 1662  *   the  output  very  late,  so that a \200 comes out as a \000
 1663  *   would.)
 1664  */
 1665 
 1666 LOCAL char *
 1667 requote(s)
 1668     char    *s;
 1669 {
 1670     char    buf[5*TBUF];
 1671     char    *bp = buf;
 1672 
 1673     tdecode(s, &bp);
 1674     return (quote(buf));
 1675 }
 1676 
 1677 LOCAL void
 1678 compile_ent(tname, do_tc, obsolete_last)
 1679     char    *tname;
 1680     BOOL    do_tc;
 1681     BOOL    obsolete_last;
 1682 {
 1683     char    unknown[5*TBUF];    /* Buffer fuer "unknown" Entries */
 1684     char    disabled[5*TBUF];   /* Buffer fuer :..xx: Entries */
 1685 
 1686     tcsetflags((do_tc?0:TCF_NO_TC)|TCF_NO_SIZE|TCF_NO_STRIP);
 1687     if (tgetent(NULL, tname) != 1)
 1688         return;
 1689 /*  tbuf = tcgetbuf();*/
 1690 /*  strippedlen = strlen(tbuf);*/
 1691 
 1692 /*  checkentries(tname, &slen);*/
 1693 
 1694 /*  printf("tbuf: '%s'\n", tbuf);*/
 1695 /*printf("full tbuf len: %d stripped tbuf len: %d\n", fullen, strippedlen);*/
 1696 /*printf("string length: %d\n", slen);*/
 1697 
 1698     checkbad(tname, unknown, disabled);
 1699     outcap(tname, unknown, disabled, obsolete_last);
 1700 }
 1701 
 1702 
 1703 #define TRDBUF  8192
 1704 #define TMAX    1024
 1705 #define TINC    1
 1706 
 1707 LOCAL void
 1708 read_names(fname, do_tc, obsolete_last)
 1709     char    *fname;
 1710     BOOL    do_tc;
 1711     BOOL    obsolete_last;
 1712 {
 1713             char    nbuf[TMAX];
 1714             char    rdbuf[TRDBUF];
 1715             char    *tbuf;
 1716             char    *name = nbuf;
 1717     register    char    *bp;
 1718     register    char    *ep;
 1719     register    char    *rbuf = rdbuf;
 1720     register    char    c;
 1721     register    int count   = 0;
 1722     register    int tfd;
 1723             int nents = 0;
 1724             int tbufsize = TINC;
 1725 
 1726     tcsetflags(TCF_NO_TC|TCF_NO_SIZE);
 1727 
 1728     tbuf = bp = malloc(tbufsize);
 1729     if (bp == NULL)
 1730         comerr("Cannot malloc termcap parsing buffer.\n");
 1731 
 1732 
 1733     if (fname == NULL)
 1734         fname = "/etc/termcap";
 1735     tfd = open(fname, O_RDONLY);
 1736     if (tfd < 0)
 1737         comerr("Cannot open '%s'\n", fname);
 1738 
 1739     /*
 1740      * Search TERM entry in one file.
 1741      */
 1742     ep = bp;
 1743     for (;;) {
 1744         if (--count <= 0) {
 1745             if ((count = read(tfd, rdbuf, sizeof (rdbuf))) <= 0) {
 1746                 close(tfd);
 1747                 error("Found %d terminal entries.\n", nents);
 1748                 error("TBuf size %d.\n", tbufsize);
 1749                 free(tbuf);
 1750                 return;
 1751             }
 1752             rbuf = rdbuf;
 1753         }
 1754         c = *rbuf++;
 1755         if (c == '\n') {
 1756             if (ep > bp && ep[-1] == '\\') {
 1757                 ep--;
 1758                 continue;
 1759             }
 1760         } else if (ep >= bp + (tbufsize-1)) {
 1761             tbufsize += TINC;
 1762             if ((bp = realloc(bp, tbufsize)) != NULL) {
 1763                 ep = bp + (ep - tbuf);
 1764                 tbuf = bp;
 1765                 *ep++ = c;
 1766                 continue;
 1767             } else {
 1768                 comerr("Cannot grow termcap parsing buffer.\n");
 1769             }
 1770         } else {
 1771             *ep++ = c;
 1772             continue;
 1773         }
 1774         *ep = '\0';
 1775 
 1776         if (tbuf[0] != '\0' && tbuf[0] != '#') {
 1777             char    *p;
 1778 
 1779 /*          printf("NAME: '%.20s'\n", tbuf);*/
 1780             p = strchr(tbuf, '|');
 1781             if (p == &tbuf[2]) {
 1782                 ++p;
 1783                 p = strchr(p, '|');
 1784             }
 1785             if (p == 0)
 1786                 p = strchr(tbuf, ':');
 1787             if (p) {
 1788                 int amt = p - tbuf;
 1789 
 1790                 nents++;
 1791                 if (amt > (sizeof (nbuf)-1))
 1792                     amt = sizeof (nbuf)-1;
 1793                 strncpy(name, tbuf, amt);
 1794                 nbuf[amt] = '\0';
 1795 /*              printf("name: %s'\n", name);*/
 1796                 compile_ent(name, do_tc, obsolete_last);
 1797                 tcsetflags(TCF_NO_TC|TCF_NO_SIZE);
 1798             } else {
 1799                 /*
 1800                  * This line is not a termcap entry
 1801                  */
 1802                 printf("%s\n", tbuf);
 1803             }
 1804         } else {
 1805             /*
 1806              * This line is comment
 1807              */
 1808             printf("%s\n", tbuf);
 1809         }
 1810         ep = bp;
 1811     }
 1812 }