home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / e20313sr.zip / emacs / 20.3.1 / src / termcap.c < prev    next >
C/C++ Source or Header  |  1999-07-31  |  19KB  |  815 lines

  1. /* Work-alike for termcap, plus extra features.
  2.    Copyright (C) 1985, 86, 93, 94, 95 Free Software Foundation, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. GNU General Public License for more details.
  13.  
  14. You should have received a copy of the GNU General Public License
  15. along with this program; see the file COPYING.  If not, write to
  16. the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  17. Boston, MA 02111-1307, USA.  */
  18.  
  19. /* Modified for emx by Jeremy Bowen, May 1999 based on patches
  20.    to v19.33 by Eberhard Mattes */
  21.  
  22. /* Emacs config.h may rename various library functions such as malloc.  */
  23. #ifdef HAVE_CONFIG_H
  24. #include <config.h>
  25. #endif
  26.  
  27. #ifdef emacs
  28.  
  29. /* Get the O_* definitions for open et al.  */
  30. #include <sys/file.h>
  31. #ifdef USG5
  32. #include <fcntl.h>
  33. #endif
  34.  
  35. #else /* not emacs */
  36.  
  37. #ifdef STDC_HEADERS
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #else
  41. char *getenv ();
  42. char *malloc ();
  43. char *realloc ();
  44. #endif
  45.  
  46. /* Do this after the include, in case string.h prototypes bcopy.  */
  47. #if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
  48. #define bcopy(s, d, n) memcpy ((d), (s), (n))
  49. #endif
  50.  
  51. #ifdef HAVE_UNISTD_H
  52. #include <unistd.h>
  53. #endif
  54. #ifdef _POSIX_VERSION
  55. #include <fcntl.h>
  56. #endif
  57.  
  58. #endif /* not emacs */
  59.  
  60. #ifndef NULL
  61. #define NULL (char *) 0
  62. #endif
  63.  
  64. #ifndef O_RDONLY
  65. #define O_RDONLY 0
  66. #endif
  67.  
  68. /* BUFSIZE is the initial size allocated for the buffer
  69.    for reading the termcap file.
  70.    It is not a limit.
  71.    Make it large normally for speed.
  72.    Make it variable when debugging, so can exercise
  73.    increasing the space dynamically.  */
  74.  
  75. #ifndef BUFSIZE
  76. #ifdef DEBUG
  77. #define BUFSIZE bufsize
  78.  
  79. int bufsize = 128;
  80. #else
  81. #define BUFSIZE 2048
  82. #endif
  83. #endif
  84.  
  85. #ifndef TERMCAP_FILE
  86. #define TERMCAP_FILE "/etc/termcap"
  87. #endif
  88.  
  89. #ifndef emacs
  90. static void
  91. memory_out ()
  92. {
  93.   write (2, "virtual memory exhausted\n", 25);
  94.   exit (1);
  95. }
  96.  
  97. static char *
  98. xmalloc (size)
  99.      unsigned size;
  100. {
  101.   register char *tem = malloc (size);
  102.  
  103.   if (!tem)
  104.     memory_out ();
  105.   return tem;
  106. }
  107.  
  108. static char *
  109. xrealloc (ptr, size)
  110.      char *ptr;
  111.      unsigned size;
  112. {
  113.   register char *tem = realloc (ptr, size);
  114.  
  115.   if (!tem)
  116.     memory_out ();
  117.   return tem;
  118. }
  119. #endif /* not emacs */
  120.  
  121. /* Looking up capabilities in the entry already found.  */
  122.  
  123. /* The pointer to the data made by tgetent is left here
  124.    for tgetnum, tgetflag and tgetstr to find.  */
  125. static char *term_entry;
  126.  
  127. static char *tgetst1 ();
  128.  
  129. /* Search entry BP for capability CAP.
  130.    Return a pointer to the capability (in BP) if found,
  131.    0 if not found.  */
  132.  
  133. static char *
  134. find_capability (bp, cap)
  135.      register char *bp, *cap;
  136. {
  137.   for (; *bp; bp++)
  138.     if (bp[0] == ':'
  139.     && bp[1] == cap[0]
  140.     && bp[2] == cap[1])
  141.       return &bp[4];
  142.   return NULL;
  143. }
  144.  
  145. int
  146. tgetnum (cap)
  147.      char *cap;
  148. {
  149.   register char *ptr = find_capability (term_entry, cap);
  150.   if (!ptr || ptr[-1] != '#')
  151.     return -1;
  152.   return atoi (ptr);
  153. }
  154.  
  155. int
  156. tgetflag (cap)
  157.      char *cap;
  158. {
  159.   register char *ptr = find_capability (term_entry, cap);
  160.   return ptr && ptr[-1] == ':';
  161. }
  162.  
  163. /* Look up a string-valued capability CAP.
  164.    If AREA is non-null, it points to a pointer to a block in which
  165.    to store the string.  That pointer is advanced over the space used.
  166.    If AREA is null, space is allocated with `malloc'.  */
  167.  
  168. char *
  169. tgetstr (cap, area)
  170.      char *cap;
  171.      char **area;
  172. {
  173.   register char *ptr = find_capability (term_entry, cap);
  174.   if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
  175.     return NULL;
  176.   return tgetst1 (ptr, area);
  177. }
  178.  
  179. #ifdef IS_EBCDIC_HOST
  180. /* Table, indexed by a character in range 0200 to 0300 with 0200 subtracted,
  181.    gives meaning of character following \, or a space if no special meaning.
  182.    Sixteen characters per line within the string.  */
  183.  
  184. static char esctab[]
  185.   = " \057\026  \047\014         \
  186.      \025   \015      \
  187.    \005 \013          \
  188.                 ";
  189. #else
  190. /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
  191.    gives meaning of character following \, or a space if no special meaning.
  192.    Eight characters per line within the string.  */
  193.  
  194. static char esctab[]
  195.   = " \007\010  \033\014 \
  196.       \012 \
  197.   \015 \011 \013 \
  198.         ";
  199. #endif
  200.  
  201. /* PTR points to a string value inside a termcap entry.
  202.    Copy that value, processing \ and ^ abbreviations,
  203.    into the block that *AREA points to,
  204.    or to newly allocated storage if AREA is NULL.
  205.    Return the address to which we copied the value,
  206.    or NULL if PTR is NULL.  */
  207.  
  208. static char *
  209. tgetst1 (ptr, area)
  210.      char *ptr;
  211.      char **area;
  212. {
  213.   register char *p, *r;
  214.   register int c;
  215.   register int size;
  216.   char *ret;
  217.   register int c1;
  218.  
  219.   if (!ptr)
  220.     return NULL;
  221.  
  222.   /* `ret' gets address of where to store the string.  */
  223.   if (!area)
  224.     {
  225.       /* Compute size of block needed (may overestimate).  */
  226.       p = ptr;
  227.       while ((c = *p++) && c != ':' && c != '\n')
  228.     ;
  229.       ret = (char *) xmalloc (p - ptr + 1);
  230.     }
  231.   else
  232.     ret = *area;
  233.  
  234.   /* Copy the string value, stopping at null or colon.
  235.      Also process ^ and \ abbreviations.  */
  236.   p = ptr;
  237.   r = ret;
  238.   while ((c = *p++) && c != ':' && c != '\n')
  239.     {
  240.       if (c == '^')
  241.     {
  242.       c = *p++;
  243.       if (c == '?')
  244.         c = 0177;
  245.       else
  246.         c &= 037;
  247.     }
  248.       else if (c == '\\')
  249.     {
  250.       c = *p++;
  251.       if (c >= '0' && c <= '7')
  252.         {
  253.           c -= '0';
  254.           size = 0;
  255.  
  256.           while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
  257.         {
  258.           c *= 8;
  259.           c += c1 - '0';
  260.           p++;
  261.         }
  262.         }
  263. #ifdef IS_EBCDIC_HOST
  264.       else if (c >= 0200 && c < 0360)
  265.         {
  266.           c1 = esctab[(c & ~0100) - 0200];
  267.           if (c1 != ' ')
  268.         c = c1;
  269.         }
  270. #else
  271.       else if (c >= 0100 && c < 0200)
  272.         {
  273.           c1 = esctab[(c & ~040) - 0100];
  274.           if (c1 != ' ')
  275.         c = c1;
  276.         }
  277. #endif
  278.     }
  279.       *r++ = c;
  280.     }
  281.   *r = '\0';
  282.   /* Update *AREA.  */
  283.   if (area)
  284.     *area = r + 1;
  285.   return ret;
  286. }
  287.  
  288. /* Outputting a string with padding.  */
  289.  
  290. short ospeed;
  291. /* If OSPEED is 0, we use this as the actual baud rate.  */
  292. int tputs_baud_rate;
  293. char PC;
  294.  
  295. /* Actual baud rate if positive;
  296.    - baud rate / 100 if negative.  */
  297.  
  298. static int speeds[] =
  299.   {
  300. #ifdef VMS
  301.     0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
  302.     -20, -24, -36, -48, -72, -96, -192
  303. #else /* not VMS */
  304.     0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
  305.     -18, -24, -48, -96, -192, -288, -384, -576, -1152
  306. #endif /* not VMS */
  307.   };
  308.  
  309. void
  310. tputs (str, nlines, outfun)
  311.      register char *str;
  312.      int nlines;
  313.      register int (*outfun) ();
  314. {
  315.   register int padcount = 0;
  316.   register int speed;
  317.  
  318. #ifdef emacs
  319.   extern baud_rate;
  320.   speed = baud_rate;
  321.   /* For quite high speeds, convert to the smaller
  322.      units to avoid overflow.  */
  323.   if (speed > 10000)
  324.     speed = - speed / 100;
  325. #else
  326.   if (ospeed == 0)
  327.     speed = tputs_baud_rate;
  328.   else if (ospeed > 0 && ospeed < (sizeof speeds / sizeof speeds[0]))
  329.     speed = speeds[ospeed];
  330.   else
  331.     speed = 0;
  332. #endif
  333.  
  334.   if (!str)
  335.     return;
  336.  
  337.   while (*str >= '0' && *str <= '9')
  338.     {
  339.       padcount += *str++ - '0';
  340.       padcount *= 10;
  341.     }
  342.   if (*str == '.')
  343.     {
  344.       str++;
  345.       padcount += *str++ - '0';
  346.     }
  347.   if (*str == '*')
  348.     {
  349.       str++;
  350.       padcount *= nlines;
  351.     }
  352.   while (*str)
  353.     (*outfun) (*str++);
  354.  
  355.   /* PADCOUNT is now in units of tenths of msec.
  356.      SPEED is measured in characters per 10 seconds
  357.      or in characters per .1 seconds (if negative).
  358.      We use the smaller units for larger speeds to avoid overflow.  */
  359.   padcount *= speed;
  360.   padcount += 500;
  361.   padcount /= 1000;
  362.   if (speed < 0)
  363.     padcount = -padcount;
  364.   else
  365.     {
  366.       padcount += 50;
  367.       padcount /= 100;
  368.     }
  369.  
  370.   while (padcount-- > 0)
  371.     (*outfun) (PC);
  372. }
  373.  
  374. /* Finding the termcap entry in the termcap data base.  */
  375.  
  376. struct termcap_buffer
  377.   {
  378.     char *beg;
  379.     int size;
  380.     char *ptr;
  381.     int ateof;
  382.     int full;
  383.   };
  384.  
  385. /* Forward declarations of static functions.  */
  386.  
  387. static int scan_file ();
  388. static char *gobble_line ();
  389. static int compare_contin ();
  390. static int name_match ();
  391.  
  392. #ifdef EMX
  393.  
  394. #define valid_filename_p(fn) (IS_DIRECTORY_SEP (*(fn)) || _fngetdrive (fn))
  395.  
  396. #else /* not EMX */
  397. #ifdef VMS
  398.  
  399. #include <rmsdef.h>
  400. #include <fab.h>
  401. #include <nam.h>
  402.  
  403. static int
  404. valid_filename_p (fn)
  405.      char *fn;
  406. {
  407.   struct FAB fab = cc$rms_fab;
  408.   struct NAM nam = cc$rms_nam;
  409.   char esa[NAM$C_MAXRSS];
  410.  
  411.   fab.fab$l_fna = fn;
  412.   fab.fab$b_fns = strlen(fn);
  413.   fab.fab$l_nam = &nam;
  414.   fab.fab$l_fop = FAB$M_NAM;
  415.  
  416.   nam.nam$l_esa = esa;
  417.   nam.nam$b_ess = sizeof esa;
  418.  
  419.   return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL;
  420. }
  421.  
  422. #else /* !VMS */
  423.  
  424. #ifdef MSDOS /* MW, May 1993 */
  425. static int
  426. valid_filename_p (fn)
  427.      char *fn;
  428. {
  429.   return *fn == '/' || fn[1] == ':';
  430. }
  431. #else
  432. #define valid_filename_p(fn) (*(fn) == '/')
  433. #endif
  434.  
  435. #endif /* !VMS */
  436. #endif /* not EMX */
  437.  
  438. /* Find the termcap entry data for terminal type NAME
  439.    and store it in the block that BP points to.
  440.    Record its address for future use.
  441.  
  442.    If BP is null, space is dynamically allocated.
  443.  
  444.    Return -1 if there is some difficulty accessing the data base
  445.    of terminal types,
  446.    0 if the data base is accessible but the type NAME is not defined
  447.    in it, and some other value otherwise.  */
  448.  
  449. int
  450. tgetent (bp, name)
  451.      char *bp, *name;
  452. {
  453.   register char *termcap_name;
  454.   register int fd;
  455.   struct termcap_buffer buf;
  456.   register char *bp1;
  457.   char *tc_search_point;
  458.   char *term;
  459.   int malloc_size = 0;
  460.   register int c;
  461.   char *tcenv;            /* TERMCAP value, if it contains :tc=.  */
  462.   char *indirect = NULL;    /* Terminal type in :tc= in TERMCAP value.  */
  463.   int filep;
  464.  
  465. #ifdef INTERNAL_TERMINAL
  466.   /* For the internal terminal we don't want to read any termcap file,
  467.      so fake it.  */
  468.   if (!strcmp (name, "internal"))
  469.     {
  470.       term = INTERNAL_TERMINAL;
  471.       if (!bp)
  472.     {
  473.       malloc_size = 1 + strlen (term);
  474.       bp = (char *) xmalloc (malloc_size);
  475.     }
  476.       strcpy (bp, term);
  477.       goto ret;
  478.     }
  479. #endif /* INTERNAL_TERMINAL */
  480.  
  481.   /* For compatibility with programs like `less' that want to
  482.      put data in the termcap buffer themselves as a fallback.  */
  483.   if (bp)
  484.     term_entry = bp;
  485.  
  486.   termcap_name = getenv ("TERMCAP");
  487.   if (termcap_name && *termcap_name == '\0')
  488.     termcap_name = NULL;
  489. #if defined (MSDOS) && !defined (TEST)
  490.   if (termcap_name && (*termcap_name == '\\'
  491.                || *termcap_name == '/'
  492.                || termcap_name[1] == ':'))
  493.     dostounix_filename(termcap_name);
  494. #endif
  495.  
  496.   filep = termcap_name && valid_filename_p (termcap_name);
  497.  
  498.   /* If termcap_name is non-null and starts with / (in the un*x case, that is),
  499.      it is a file name to use instead of /etc/termcap.
  500.      If it is non-null and does not start with /,
  501.      it is the entry itself, but only if
  502.      the name the caller requested matches the TERM variable.  */
  503.  
  504.   if (termcap_name && !filep && !strcmp (name, getenv ("TERM")))
  505.     {
  506.       indirect = tgetst1 (find_capability (termcap_name, "tc"), (char **) 0);
  507.       if (!indirect)
  508.     {
  509.       if (!bp)
  510.         bp = termcap_name;
  511.       else
  512.         strcpy (bp, termcap_name);
  513.       goto ret;
  514.     }
  515.       else
  516.     {            /* It has tc=.  Need to read /etc/termcap.  */
  517.       tcenv = termcap_name;
  518.        termcap_name = NULL;
  519.     }
  520.     }
  521.  
  522.   if (!termcap_name || !filep)
  523.     termcap_name = TERMCAP_FILE;
  524.  
  525.   /* Here we know we must search a file and termcap_name has its name.  */
  526.  
  527. #ifdef MSDOS
  528.   fd = open (termcap_name, O_RDONLY|O_TEXT, 0);
  529. #else
  530.   fd = open (termcap_name, O_RDONLY, 0);
  531. #endif
  532.   if (fd < 0)
  533.     return -1;
  534.  
  535.   buf.size = BUFSIZE;
  536.   /* Add 1 to size to ensure room for terminating null.  */
  537.   buf.beg = (char *) xmalloc (buf.size + 1);
  538.   term = indirect ? indirect : name;
  539.  
  540.   if (!bp)
  541.     {
  542.       malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
  543.       bp = (char *) xmalloc (malloc_size);
  544.     }
  545.   tc_search_point = bp1 = bp;
  546.  
  547.   if (indirect)
  548.     /* Copy the data from the environment variable.  */
  549.     {
  550.       strcpy (bp, tcenv);
  551.       bp1 += strlen (tcenv);
  552.     }
  553.  
  554.   while (term)
  555.     {
  556.       /* Scan the file, reading it via buf, till find start of main entry.  */
  557.       if (scan_file (term, fd, &buf) == 0)
  558.     {
  559.       close (fd);
  560.       free (buf.beg);
  561.       if (malloc_size)
  562.         free (bp);
  563.       return 0;
  564.     }
  565.  
  566.       /* Free old `term' if appropriate.  */
  567.       if (term != name)
  568.     free (term);
  569.  
  570.       /* If BP is malloc'd by us, make sure it is big enough.  */
  571.       if (malloc_size)
  572.     {
  573.       malloc_size = bp1 - bp + buf.size;
  574.       termcap_name = (char *) xrealloc (bp, malloc_size);
  575.       bp1 += termcap_name - bp;
  576.       tc_search_point += termcap_name - bp;
  577.       bp = termcap_name;
  578.     }
  579.  
  580.       /* Copy the line of the entry from buf into bp.  */
  581.       termcap_name = buf.ptr;
  582.       while ((*bp1++ = c = *termcap_name++) && c != '\n')
  583.     /* Drop out any \ newline sequence.  */
  584.     if (c == '\\' && *termcap_name == '\n')
  585.       {
  586.         bp1--;
  587.         termcap_name++;
  588.       }
  589.       *bp1 = '\0';
  590.  
  591.       /* Does this entry refer to another terminal type's entry?
  592.      If something is found, copy it into heap and null-terminate it.  */
  593.       tc_search_point = find_capability (tc_search_point, "tc");
  594.       term = tgetst1 (tc_search_point, (char **) 0);
  595.     }
  596.  
  597.   close (fd);
  598.   free (buf.beg);
  599.  
  600.   if (malloc_size)
  601.     bp = (char *) xrealloc (bp, bp1 - bp + 1);
  602.  
  603.  ret:
  604.   term_entry = bp;
  605.   return 1;
  606. }
  607.  
  608. /* Given file open on FD and buffer BUFP,
  609.    scan the file from the beginning until a line is found
  610.    that starts the entry for terminal type STR.
  611.    Return 1 if successful, with that line in BUFP,
  612.    or 0 if no entry is found in the file.  */
  613.  
  614. static int
  615. scan_file (str, fd, bufp)
  616.      char *str;
  617.      int fd;
  618.      register struct termcap_buffer *bufp;
  619. {
  620.   register char *end;
  621.  
  622.   bufp->ptr = bufp->beg;
  623.   bufp->full = 0;
  624.   bufp->ateof = 0;
  625.   *bufp->ptr = '\0';
  626.  
  627.   lseek (fd, 0L, 0);
  628.  
  629.   while (!bufp->ateof)
  630.     {
  631.       /* Read a line into the buffer.  */
  632.       end = NULL;
  633.       do
  634.     {
  635.       /* if it is continued, append another line to it,
  636.          until a non-continued line ends.  */
  637.       end = gobble_line (fd, bufp, end);
  638.     }
  639.       while (!bufp->ateof && end[-2] == '\\');
  640.  
  641.       if (*bufp->ptr != '#'
  642.       && name_match (bufp->ptr, str))
  643.     return 1;
  644.  
  645.       /* Discard the line just processed.  */
  646.       bufp->ptr = end;
  647.     }
  648.   return 0;
  649. }
  650.  
  651. /* Return nonzero if NAME is one of the names specified
  652.    by termcap entry LINE.  */
  653.  
  654. static int
  655. name_match (line, name)
  656.      char *line, *name;
  657. {
  658.   register char *tem;
  659.  
  660.   if (!compare_contin (line, name))
  661.     return 1;
  662.   /* This line starts an entry.  Is it the right one?  */
  663.   for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
  664.     if (*tem == '|' && !compare_contin (tem + 1, name))
  665.       return 1;
  666.  
  667.   return 0;
  668. }
  669.  
  670. static int
  671. compare_contin (str1, str2)
  672.      register char *str1, *str2;
  673. {
  674.   register int c1, c2;
  675.   while (1)
  676.     {
  677.       c1 = *str1++;
  678.       c2 = *str2++;
  679.       while (c1 == '\\' && *str1 == '\n')
  680.     {
  681.       str1++;
  682.       while ((c1 = *str1++) == ' ' || c1 == '\t');
  683.     }
  684.       if (c2 == '\0')
  685.     {
  686.       /* End of type being looked up.  */
  687.       if (c1 == '|' || c1 == ':')
  688.         /* If end of name in data base, we win.  */
  689.         return 0;
  690.       else
  691.         return 1;
  692.         }
  693.       else if (c1 != c2)
  694.     return 1;
  695.     }
  696. }
  697.  
  698. /* Make sure that the buffer <- BUFP contains a full line
  699.    of the file open on FD, starting at the place BUFP->ptr
  700.    points to.  Can read more of the file, discard stuff before
  701.    BUFP->ptr, or make the buffer bigger.
  702.  
  703.    Return the pointer to after the newline ending the line,
  704.    or to the end of the file, if there is no newline to end it.
  705.  
  706.    Can also merge on continuation lines.  If APPEND_END is
  707.    non-null, it points past the newline of a line that is
  708.    continued; we add another line onto it and regard the whole
  709.    thing as one line.  The caller decides when a line is continued.  */
  710.  
  711. static char *
  712. gobble_line (fd, bufp, append_end)
  713.      int fd;
  714.      register struct termcap_buffer *bufp;
  715.      char *append_end;
  716. {
  717.   register char *end;
  718.   register int nread;
  719.   register char *buf = bufp->beg;
  720.   register char *tem;
  721.  
  722.   if (!append_end)
  723.     append_end = bufp->ptr;
  724.  
  725.   while (1)
  726.     {
  727.       end = append_end;
  728.       while (*end && *end != '\n') end++;
  729.       if (*end)
  730.         break;
  731.       if (bufp->ateof)
  732.     return buf + bufp->full;
  733.       if (bufp->ptr == buf)
  734.     {
  735.       if (bufp->full == bufp->size)
  736.         {
  737.           bufp->size *= 2;
  738.           /* Add 1 to size to ensure room for terminating null.  */
  739.           tem = (char *) xrealloc (buf, bufp->size + 1);
  740.           bufp->ptr = (bufp->ptr - buf) + tem;
  741.           append_end = (append_end - buf) + tem;
  742.           bufp->beg = buf = tem;
  743.         }
  744.     }
  745.       else
  746.     {
  747.       append_end -= bufp->ptr - buf;
  748.       bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf);
  749.       bufp->ptr = buf;
  750.     }
  751.       if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
  752.     bufp->ateof = 1;
  753.       bufp->full += nread;
  754.       buf[bufp->full] = '\0';
  755.     }
  756.   return end + 1;
  757. }
  758.  
  759. #ifdef TEST
  760.  
  761. #ifdef NULL
  762. #undef NULL
  763. #endif
  764.  
  765. #include <stdio.h>
  766.  
  767. main (argc, argv)
  768.      int argc;
  769.      char **argv;
  770. {
  771.   char *term;
  772.   char *buf;
  773.  
  774.   term = argv[1];
  775.   printf ("TERM: %s\n", term);
  776.  
  777.   buf = (char *) tgetent (0, term);
  778.   if ((int) buf <= 0)
  779.     {
  780.       printf ("No entry.\n");
  781.       return 0;
  782.     }
  783.  
  784.   printf ("Entry: %s\n", buf);
  785.  
  786.   tprint ("cm");
  787.   tprint ("AL");
  788.  
  789.   printf ("co: %d\n", tgetnum ("co"));
  790.   printf ("am: %d\n", tgetflag ("am"));
  791. }
  792.  
  793. tprint (cap)
  794.      char *cap;
  795. {
  796.   char *x = tgetstr (cap, 0);
  797.   register char *y;
  798.  
  799.   printf ("%s: ", cap);
  800.   if (x)
  801.     {
  802.       for (y = x; *y; y++)
  803.     if (*y <= ' ' || *y == 0177)
  804.       printf ("\\%0o", *y);
  805.     else
  806.       putchar (*y);
  807.       free (x);
  808.     }
  809.   else
  810.     printf ("none");
  811.   putchar ('\n');
  812. }
  813.  
  814. #endif /* TEST */
  815.