home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / gnu / crssrc16 / tgetent.c < prev    next >
C/C++ Source or Header  |  1993-07-29  |  17KB  |  655 lines

  1. /************************************************************************
  2.  *                                    *
  3.  *            Copyright (c) 1982, Fred Fish            *
  4.  *                All Rights Reserved                *
  5.  *                                    *
  6.  *    This software and/or documentation is released for public    *
  7.  *    distribution for personal, non-commercial use only.        *
  8.  *    Limited rights to use, modify, and redistribute are hereby    *
  9.  *    granted for non-commercial purposes, provided that all        *
  10.  *    copyright notices remain intact and all changes are clearly    *
  11.  *    documented.  The author makes no warranty of any kind with    *
  12.  *    respect to this product and explicitly disclaims any implied    *
  13.  *    warranties of merchantability or fitness for any particular    *
  14.  *    purpose.                            *
  15.  *                                    *
  16.  ************************************************************************
  17.  */
  18.  
  19.  
  20. /*
  21.  *  LIBRARY FUNCTION
  22.  *
  23.  *    tgetent   load buffer with entry for specified terminal
  24.  *
  25.  *  KEY WORDS
  26.  *
  27.  *    termcap functions
  28.  *    utility routines
  29.  *
  30.  *  SYNOPSIS
  31.  *
  32.  *    int tgetent(bp,name)
  33.  *    char *bp;
  34.  *    char *name;
  35.  *
  36.  *  DESCRIPTION
  37.  *
  38.  *    Extracts the entry for terminal <name> from the termcap file
  39.  *    and places it in the character buffer <bp>.   It is currently
  40.  *    assumed that bp is at least 1024 characters.  If the entry in
  41.  *    the termcap file is larger than 1023 characters the excess
  42.  *    characters will be discarded and appropriate status will
  43.  *    be returned.
  44.  *
  45.  *    Also note that since bp is used by other termcap
  46.  *    routines, the storage associated with the termcap entry
  47.  *    cannot be freed until all termcap calls are completed.
  48.  *
  49.  *    Tgetent can be directed to look in a file other than
  50.  *    the default (/etc/termcap) by defining an environment
  51.  *    variable called TERMCAP to be the pathname of the desired
  52.  *    termcap file.  This is useful for debugging new entries.
  53.  *    NOTE: the pathname MUST begin with a '/' character.
  54.  *      (Atari ST specific change: the pathname may begin with '\',
  55.  *       or with a drive letter followed by ':').
  56.  *
  57.  *    Also, if the string assigned to TERMCAP does not begin with
  58.  *    a '/' and if the environment variable TERM matches <name> then
  59.  *    the string assigned to TERMCAP is copied to buffer <bp> 
  60.  *    instead of reading a termcap file.
  61.  *      (Atari ST specific change: TERM is no longer checked (the
  62.  *       check was buggy).
  63.  *
  64.  *    Modification by ERS: if no termcap file can be found, then
  65.  *    a default termcap is used (this is for GEMDOS).
  66.  *
  67.  *      Further mods by MJ: original routines fail to proces valid
  68.  *      termcap files - replaced with new versions.
  69.  *      Atari specific: default termcap used when nothing better is
  70.  *      around reads a number of rows and colums from Line-A variables.
  71.  *    
  72.  *  RETURNS
  73.  *
  74.  *    -1  if the termcap file cannot be opened
  75.  *     0  if no entry in termcap file matches <name>
  76.  *     1  if extraction is successful with no errors
  77.  *     2  if extraction is successful but entry truncated
  78.  *
  79.  *  SEE ALSO
  80.  *
  81.  *    tgetnum   extract numeric type capability
  82.  *    tgetflag  test boolean type capability
  83.  *    tgetstr   get string value of capability
  84.  *
  85.  *  AUTHOR
  86.  *
  87.  *    Fred Fish
  88.  *
  89.  */
  90.  
  91. #include <stdio.h>
  92. #include <string.h>
  93. #include <termcap.h>
  94. #include <ctype.h>
  95.  
  96. #ifndef _COMPILER_H
  97. #  include <compiler.h>
  98. #endif
  99.  
  100. #if __STDC__
  101. #  include<stdlib.h>
  102. #endif
  103.  
  104. #define TRUE 1
  105. #define FALSE 0
  106. #define BUFSIZE 1024            /* Assumed size of external buffer */
  107.  
  108. #define NO_FILE     -1            /* Returned if can't open file */
  109. #define NO_ENTRY  0            /* Returned if can't find entry */
  110. #define SUCCESS   1            /* Returned if entry found ok */
  111. #define TRUNCATED 2            /* Returned if entry found but trunc */
  112.  
  113. # ifdef DGK
  114. # define DEFAULT_ROOT "termcap"        /* name without path component */
  115. /**
  116.   static FILE *fopenp __PROTO((char *name, char *mode, char *pathname));
  117. **/
  118. # define DEFAULT_FILE "\\etc\\termcap"
  119. # else
  120. # define DEFAULT_FILE "/etc/termcap"    /* default termcap filename */
  121. # endif
  122. /* __EXTERN char *fgetlr __PROTO((char *bp, int bpsize, FILE *fp)); */
  123. static int build_entry __PROTO((char *bp, char *stop, FILE *fp, char *name));
  124. static FILE *find_file __PROTO((char *));
  125. /**
  126. static int gotcha __PROTO((char *bp, char *name));
  127. **/
  128.  
  129. char *_tcpbuf;                /* Place to remember buffer pointer */
  130.  
  131. /*
  132.  *  PSEUDO CODE
  133.  *
  134.  *    Begin tgetent
  135.  *        Erase any previous buffer contents.
  136.  *        Remember the buffer pointer.
  137.  *        If termcap file is not found then
  138.  *        If buffer was filled anyway then
  139.  *            Return SUCCESS.
  140.  *        Else
  141.  *            Return NO_FILE.
  142.  *        End if
  143.  *        Else
  144.  *        While records left to process
  145.  *            If this is entry is what we want then
  146.  *            Close the termcap file.
  147.  *            If entry was truncated then
  148.  *                Return TRUNCATED status
  149.  *            Else
  150.  *                Return SUCCESS status.
  151.  *            End if
  152.  *            End if
  153.  *        End while
  154.  *        Return NO_ENTRY status.
  155.  *        End if
  156.  *    End tgetent
  157.  *
  158.  *    Modification by Michal Jagerman (April of 1992):
  159.  *      The "While records left to process" is too simple minded
  160.  *      since termcap entry in a buffer can be spliced from
  161.  *    multiple pieces by using "tc" capability. Therefore
  162.  *      we delegete the task of termcap buffer filling to
  163.  *      a specialized internal function 'build_entry()'. This
  164.  *      function also solves a problem of opening a termcap file
  165.  *      in a 'wrong' mode by cleaning a termcap buffer from all
  166.  *      leftovers.
  167.  *
  168.  *  
  169.  */
  170.  
  171. int tgetent(bp,name)
  172. char *bp;                /* Pointer to buffer (1024 char min) */
  173. char *name;                /* Pointer to terminal entry to find */
  174. {
  175.     FILE *fp;
  176.  
  177.     *bp = '\0';
  178.     _tcpbuf = bp;
  179.     if ((fp = find_file(bp)) == NULL) {
  180.     if (*bp != '\0') {
  181.         return(SUCCESS);
  182.     } else {
  183.         return(NO_FILE);
  184.     }
  185.     } else {
  186.     *bp++ = ':';
  187.     return (build_entry(bp, bp + BUFSIZE - 1, fp, name));
  188.     }
  189. }
  190.  
  191. /*
  192.  *  INTERNAL FUNCTION
  193.  *
  194.  *    build_entry    construct termcap entry in a given buffer
  195.  *
  196.  *  SYNOPSIS
  197.  *
  198.  *    static int build_entry(bp, stop, fp, name)
  199.  *    char *bp, *stop, *name;
  200.  *      FILE *fp;
  201.  *
  202.  *  DESCRIPTION
  203.  *
  204.  *      For a given name build in a buffer bp a termcap description
  205.  *      using a contents of file fp.  Continue this until the entry
  206.  *      is complete or we reached stop.  Concatenate entries if
  207.  *      required by tc capability.   White space characters and
  208.  *      backslashes escaping newlines are not copied into bp.
  209.  *      Returns SUCCESS if there was no problems, NO_ENTRY if an
  210.  *      entry with given name was not found and TRUNCATED if we
  211.  *      run out of a buffer space or continuation entry specified
  212.  *      with tc was not found
  213.  *
  214.  *  BUGS
  215.  *
  216.  *      Termcap specifications require for tc to be the last capability
  217.  *      for the given name.  This is not enforced but anything which
  218.  *      follows tc in the same description will be discarded.
  219.  *      It is not entirely clear what we should return when continuation
  220.  *      specified with tc failed.
  221.  *      Other stuff which goes beyond termcap specs can be accepted.
  222.  *      Terminal names starting with '#' are not accepted.
  223.  *      Continuation with names over 127 characters long will likely bomb!
  224.  *
  225.  *  AUTHOR
  226.  *
  227.  *    Michal Jaegermann
  228.  *
  229.  */
  230. static int build_entry(bp, stop, fp, name)
  231. char *bp, *stop, *name;
  232. FILE *fp;
  233. {
  234.     int c;
  235.     int so_far, skip_all = 0;
  236.     char *np;
  237.     char nbuf[128];
  238.     static int _tgetc __PROTO((FILE *fp));
  239.  
  240.     /* rewind file - we may seek for a continuation entry */
  241.     rewind(fp);
  242.  
  243.     /*
  244.      * this is FSM - sort of 
  245.      */
  246.     while (EOF != (c = getc(fp))) {
  247.      /*
  248.       * we are looking at a comment - skip it
  249.       */
  250.     if ('#' == c) {
  251.         do {
  252.         if (EOF == (c = getc(fp)))
  253.             return NO_ENTRY;
  254.         } while ('\n' != c);
  255.     }
  256.     /*
  257.      * empty line or we finished comment traversal;
  258.      * a little bit to good - but valid termcap file will be
  259.      * stil accepted
  260.      */
  261.     if (isspace(c))
  262.         continue;
  263.     /*
  264.      * try matching name
  265.      */
  266.     np = name;
  267.     while (*np == c) {
  268.         np += 1;
  269.         c = _tgetc(fp);
  270.     }
  271.     /*
  272.      * we finished traversing our name - is this really a match ?
  273.      */
  274.     if (*np == '\0') {
  275.         if (c == '|' || c == ':')
  276.         break; /* we have a match */
  277.         if  (c == EOF)
  278.         return (TRUNCATED); /* match - but we wanted more */
  279.     }
  280.     /*
  281.      * no match - skip until next name or next entry
  282.      * if we are past all possible names here 
  283.      */
  284.     skip_all = 0;
  285.     while ('\n' != c) {
  286.         if (':' == c)
  287.         skip_all = 1; /* we are past all valid names for this entry */
  288.         if ('|' == c && 0 == skip_all)
  289.         break;
  290.         c = _tgetc(fp);
  291.     }
  292.     }
  293.     if (EOF == c)
  294.     return (NO_ENTRY);
  295.     while (':' != c)    /* skip the remainig variants of terminal names */
  296.     c = _tgetc(fp); /* we do not want any mixups later             */
  297.  
  298.     /*
  299.      * at last we got it - copy terminal description into bp
  300.      */
  301.     so_far = 0;  /* rough indicator how far we are into a capability */
  302.     while ('\n' != (c = _tgetc(fp))) {
  303.     if (0 == so_far && !isalpha(c))
  304.         continue;     /* do not bother with all kind of spurious stuff */
  305.     so_far++;
  306.     if (1 == so_far && 't' == c ) {
  307.         /* a special case - maybe we have "tc=" string? */
  308.         if ((bp + 3) > stop) {
  309.         ungetc(c, fp);
  310.         continue;
  311.         /* cheating with so_far, but we want to skip this case! */
  312.         }
  313.         *bp++ = c;
  314.         c = _tgetc(fp);
  315.         if ('c' == c) {
  316.         *bp++ = c;
  317.         c = _tgetc(fp);
  318.         if ('=' == c) {
  319.             /* we will continue with a name which follows */
  320.             bp -= 2;
  321.             /* copy new name to nbuf */
  322.             np = nbuf;
  323.             while (':' != (c = _tgetc(fp))) {
  324.             if ('\n' == c || EOF == c)
  325.                 break;
  326.             *np++ = c;
  327.             }
  328.             *np = '\0';
  329.             return (SUCCESS == build_entry(bp, stop, fp, nbuf) ?
  330.                 SUCCESS : TRUNCATED);
  331.         }
  332.         }
  333.     }  /* end of 'tc=' check */
  334.     if (':' == c) /* literal colon cannot occur in capabilities strings -
  335.                * one has to use '\072' instead */
  336.         so_far =  0;
  337.     *bp++ = c;
  338.     if (bp >= stop)
  339.         return(TRUNCATED);
  340.     }
  341.     if (bp < stop)
  342.     *bp = '\0';
  343.     return(SUCCESS);
  344. }
  345.  
  346. /*
  347.  * Auxilary function to read a character from a text file
  348.  * with skipping escaped line terminators; any escaped
  349.  * '\n' will be replaced by a character which follows.
  350.  * After escape any number of ^M's will vanish,
  351.  * i.e a string of three characters '\\', 0x0d, 'a' will read
  352.  * as a string of two characters '\\', 'a' and so on...
  353.  * We do not tolerate such garbage in text files. :-)
  354.  */
  355. static int _tgetc(fp)
  356. FILE *fp;
  357. {
  358.     int c;
  359.  
  360.     if ('\\' == (c = getc(fp))) {
  361.     while ('\r' == (c = getc(fp)))
  362.         ;                /* Messy stuff - go away */
  363.     if (c != '\n') {
  364.         ungetc(c, fp);
  365.         return ('\\');
  366.     }
  367.     c = getc(fp);
  368.     }
  369.     return(c);
  370. }
  371.  
  372.  
  373.  
  374. /*
  375.  *  INTERNAL FUNCTION
  376.  *
  377.  *    find_file    find the termcap file and open it if possible
  378.  *
  379.  *  KEY WORDS
  380.  *
  381.  *    internal functions
  382.  *    find_file
  383.  *
  384.  *  SYNOPSIS
  385.  *
  386.  *    static FILE *find_file(bp)
  387.  *    char *bp;
  388.  *
  389.  *  DESCRIPTION
  390.  *
  391.  *    Attempts to locate and open the termcap file.  Also handles
  392.  *    using the environment TERMCAP string as the actual buffer
  393.  *    (that's why bp has to be an input parameter).
  394.  *
  395.  *    If TERMCAP is defined an begins with a '/' character then
  396.  *    it is taken to be the pathname of the termcap file and
  397.  *    an attempt is made to open it.  If this fails then
  398.  *    the default termcap file is used instead.
  399.  *
  400.  *    If TERMCAP is defined but does not begin with a '/' then
  401.  *    it is assumed to be the actual buffer contents provided
  402.  *    that <name> matches the environment variable TERM.
  403.  *
  404.  *  BUGS
  405.  *
  406.  *    There is currently no way to be sure which termcap
  407.  *    file was opened since the default will always be
  408.  *    tried.
  409.  *
  410.  */
  411.  
  412. /*
  413.  *  PSEUDO CODE
  414.  *
  415.  *    Begin find_file
  416.  *        If there is a TERMCAP environment string then
  417.  *        If the string is not null then
  418.  *            If the string is a pathname then
  419.  *            If that file is opened successfully then
  420.  *                Return its pointer.
  421.  *            End if
  422.  *            Else
  423.  *            If there is a TERM environment string then
  424.  *                If TERM matches <name> then
  425.  *                Copy TERMCAP string to buffer.
  426.  *                Return NULL for no file.
  427.  *                End if
  428.  *            End if
  429.  *            End if
  430.  *        End if
  431.  *        End if
  432.  *        Open default termcap file and return results.
  433.  *    End find_file
  434.  *
  435.  */
  436.  
  437. #ifdef GEMDOS
  438. /*
  439.  * we do not really need the following part once the stuff is in
  440.  * our termcap  buffer
  441.  */
  442. /* "df|default|Atari default"  */
  443. /*
  444.  * this values we will try to fill to fit a given display
  445.  */
  446. /* :co#80:li#25:\  */
  447.  
  448. static char term_default[] = "\
  449. :al=\\EL:am:bs:cd=\\EJ:ce=\\EK:cl=\\EE:cm=\\EY%+ %+ :dl=\\EM\
  450. :do=\\EB:eo:ho=\\EH:is=\\Eq\\EE\\Ee\\Ev:it#8:pt:kb=^H:ll=\\EY9!\
  451. :me=\\Eq:mr=\\Ep:le=\\ED:nd=\\EC:rc=\\Ek:sc=\\Ej:se=\\Eq:so=\\Ep:ta=^I\
  452. :up=\\EA:ve=\\Ee:vi=\\Ef:km:bl=^G:cr=^M:ti=\\Ev\\Ee:sr=\\EI:sf=^J";
  453.  
  454. #include <linea.h>
  455. #include <support.h>
  456. #endif
  457.  
  458. static FILE *find_file(bp)
  459. char *bp;
  460. {
  461.     FILE *fp;
  462.     char *cp, *ncp;
  463.     __EXTERN char *getenv __PROTO((const char *));
  464.  
  465.     if ((cp = getenv("TERMCAP")) != NULL) {
  466.     if (*cp != '\0') {
  467.         if (*cp == '/' || *cp == '\\' || (cp[1] == ':')) {
  468.         if ((fp = fopen(cp,"r")) != NULL) {
  469.             return(fp);
  470.         }
  471.         } else {
  472.         if ((ncp = getenv("TERM")) != NULL) {
  473.             strcpy(bp,cp);
  474.             return((FILE *)NULL);
  475.         }
  476.         }
  477.     }
  478.     }
  479. # ifdef DGK
  480.     /* Try current directory, then /etc/termcap, then along the path
  481.      */
  482.     if (fp = fopen(DEFAULT_ROOT, "r"))
  483.         return fp;
  484.     else if (fp = fopen(DEFAULT_FILE, "r"))
  485.         return fp;
  486.         else if (NULL !=
  487.          (cp = findfile(DEFAULT_ROOT, getenv("PATH"), (char **)0)) &&
  488.          (NULL != (fp = fopen(cp,"r"))))
  489.                return fp;
  490.             
  491. /** this replaced by the above **
  492.     else if (fp = fopenp(DEFAULT_ROOT, "r", NULL))
  493.         return fp;
  494. **/
  495.     else {
  496. #  ifdef GEMDOS
  497.         /* 
  498.          * if we do not have any better information, then
  499.                  * first try to glimpse screen size from the env
  500.                  * failing which
  501.          * we will try to glimpse screen sizes from Line-A variables
  502.          */
  503.                 char *rows, *cols = getenv("COLUMNS");
  504.  
  505.                 if(!(rows = getenv("LINES")))
  506.                     rows = getenv("ROWS");
  507.                 
  508.                 if((!rows) || (!cols))
  509.                     linea0();
  510.  
  511.         strcpy (bp, ":co#");
  512.                 if(!cols)
  513.                 {
  514.                     (void) _ultoa((unsigned long) (V_CEL_MX + 1),
  515.                                   bp + sizeof(":co#") - 1, 10);
  516.                 }
  517.                 else
  518.                     strcat(bp, cols);
  519.                 
  520.         strcat (bp, ":li#");
  521.                 if(!rows)
  522.                 {
  523.                     (void) _ultoa((unsigned long) (V_CEL_MY + 1),
  524.                                   bp + strlen(bp), 10);
  525.                 }
  526.                 else
  527.                     strcat(bp, rows);
  528.                 
  529.         strcat (bp, term_default);
  530. #  endif
  531.         return (FILE *) NULL;
  532.     }
  533. # else
  534.     return(fopen(DEFAULT_FILE,"r"));
  535. # endif
  536. }
  537. #if 0  /* this is not used anymore */
  538.  
  539. /*
  540.  *  INTERNAL FUNCTION
  541.  *
  542.  *    gotcha   test to see if entry is for specified terminal
  543.  *
  544.  *  SYNOPSIS
  545.  *
  546.  *    gotcha(bp,name)
  547.  *    char *bp;
  548.  *    char *name;
  549.  *
  550.  *  DESCRIPTION
  551.  *
  552.  *    Tests to see if the entry in buffer bp matches the terminal
  553.  *    specified by name.  Returns TRUE if match is detected, FALSE
  554.  *    otherwise.
  555.  *
  556.  */
  557.  
  558. /*
  559.  *  PSEUDO CODE
  560.  *
  561.  *    Begin gotcha
  562.  *        If buffer character is comment character then
  563.  *        Return FALSE since remainder is comment
  564.  *        Else
  565.  *        Initialize name scan pointer.
  566.  *        Compare name and buffer until end or mismatch.
  567.  *        If valid terminators for both name and buffer strings
  568.  *            Return TRUE since a match was found.
  569.  *        Else
  570.  *            Find next non-name character in buffer.
  571.  *            If not an alternate name separater character
  572.  *            Return FALSE since no more names to check.
  573.  *            Else
  574.  *            Test next name and return results.
  575.  *            End if
  576.  *        End if
  577.  *        End if
  578.  *    End gotcha
  579.  *
  580.  */
  581.  
  582. static int gotcha(bp,name)
  583. char *bp;
  584. char *name;
  585. {
  586.     char *np;
  587.  
  588.     if (*bp == '#') {
  589.     return(FALSE);
  590.     } else {
  591.     np = name;
  592.     while (*np == *bp && *np != '\0') {np++; bp++;}
  593.     if (*np == '\0' && (*bp == '\0' || *bp == '|' || *bp == ':')) {
  594.         return(TRUE);
  595.     } else {
  596.         while (*bp != '\0' && *bp != ':' && *bp != '|') {bp++;}
  597.         if (*bp != '|') {
  598.         return(FALSE);
  599.         } else {
  600.         return(gotcha(++bp,name));
  601.         }
  602.     }
  603.     }
  604. }
  605.  
  606. #ifdef DGK
  607. # ifdef MSDOS
  608. # define PATHSEP ';'
  609. # endif
  610. # ifdef GEMDOS
  611. # define PATHSEP ','
  612. # endif
  613.  
  614. /* Follow the PATH, trying to fopen the file.  Takes one additional
  615.  * argument which can be NULL.  Otherwise this argument gets filled
  616.  * in the full path to the file.  Returns as does fopen().
  617.  */
  618.  
  619. /* On Atari ST use library routine findfile() instead */
  620.  
  621. static FILE *
  622. fopenp(name, mode, pathname)
  623. char *name, *mode, *pathname;
  624. {
  625.     char buffer[BUFSIZ], *buf, *bufp, *pathp, lastch;
  626.     FILE *fp;
  627.     __EXTERN char *getenv __PROTO((const char *));
  628.  
  629.     /* If pathname is given, use it instead of buf so the calling
  630.      * process knows the path we found name under
  631.      */
  632.     if (pathname)
  633.         buf = pathname;
  634.     else
  635.         buf = buffer;
  636.  
  637.     strcpy(buf, name);
  638.     pathp = getenv("PATH");
  639.     while (pathp && *pathp) {
  640.         bufp = buf;
  641.         while (*pathp && *pathp != PATHSEP)
  642.             lastch = *bufp++ = *pathp++;
  643.         if (lastch != '\\')
  644.             *bufp++ = '\\';
  645.         strcpy(bufp, name);
  646.         if (fp = fopen(buf, mode))
  647.             return fp;
  648.         if (*pathp)
  649.             pathp++;
  650.     }
  651.     return NULL;
  652. }
  653. #endif
  654. #endif /* 0 */
  655.