"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.

    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 }