160250Shibler /* Work-alike for termcap, plus extra features.
260250Shibler    Copyright (C) 1985, 1986 Free Software Foundation, Inc.
360250Shibler 
460250Shibler     This program is free software; you can redistribute it and/or modify
560250Shibler     it under the terms of the GNU General Public License as published by
660250Shibler     the Free Software Foundation; either version 1, or (at your option)
760250Shibler     any later version.
860250Shibler 
960250Shibler     This program is distributed in the hope that it will be useful,
1060250Shibler     but WITHOUT ANY WARRANTY; without even the implied warranty of
1160250Shibler     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1260250Shibler     GNU General Public License for more details.
1360250Shibler 
1460250Shibler     You should have received a copy of the GNU General Public License
1560250Shibler     along with this program; if not, write to the Free Software
1660250Shibler     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1760250Shibler 
1860250Shibler In other words, you are welcome to use, share and improve this program.
1960250Shibler You are forbidden to forbid anyone else to use, share and improve
2060250Shibler what you give them.   Help stamp out software-hoarding!  */
2160250Shibler 
2260250Shibler 
2360250Shibler 
2460250Shibler /* BUFSIZE is the initial size allocated for the buffer
2560250Shibler    for reading the termcap file.
2660250Shibler    It is not a limit.
2760250Shibler    Make it large normally for speed.
2860250Shibler    Make it variable when debugging, so can exercise
2960250Shibler    increasing the space dynamically.  */
3060250Shibler 
31*60297Shibler #include <sys/types.h>
32*60297Shibler 
3360250Shibler #ifdef emacs
3460250Shibler #include "config.h"
3560250Shibler #endif
3660250Shibler 
3760250Shibler #ifndef BUFSIZE
3860250Shibler #ifdef DEBUG
3960250Shibler #define BUFSIZE bufsize
4060250Shibler 
4160250Shibler int bufsize = 128;
4260250Shibler #else
4360250Shibler #define BUFSIZE 2048
4460250Shibler #endif
4560250Shibler #endif
4660250Shibler 
4760250Shibler #ifndef emacs
4860250Shibler static
memory_out()4960250Shibler memory_out ()
5060250Shibler {
5160250Shibler   write (2, "Virtual memory exhausted\n", 25);
5260250Shibler   exit (1);
5360250Shibler }
5460250Shibler 
5560250Shibler static int
xmalloc(size)5660250Shibler xmalloc (size)
5760250Shibler      int size;
5860250Shibler {
5960250Shibler   register tem = malloc (size);
6060250Shibler   if (!tem)
6160250Shibler     memory_out ();
6260250Shibler   return tem;
6360250Shibler }
6460250Shibler 
6560250Shibler static int
xrealloc(ptr,size)6660250Shibler xrealloc (ptr, size)
6760250Shibler      int ptr;
6860250Shibler      int size;
6960250Shibler {
7060250Shibler   register tem = realloc (ptr, size);
7160250Shibler   if (!tem)
7260250Shibler     memory_out ();
7360250Shibler   return tem;
7460250Shibler }
7560250Shibler #endif /* not emacs */
7660250Shibler 
7760250Shibler /* Looking up capabilities in the entry already found */
7860250Shibler 
7960250Shibler /* The pointer to the data made by tgetent is left here
8060250Shibler    for tgetnum, tgetflag and tgetstr to find.  */
8160250Shibler 
8260250Shibler static char *term_entry;
8360250Shibler 
8460250Shibler static char *tgetst1 ();
8560250Shibler 
8660250Shibler /* This is the main subroutine that is used to search
8760250Shibler    an entry for a particular capability */
8860250Shibler 
8960250Shibler static char *
find_capability(bp,cap)9060250Shibler find_capability (bp, cap)
9160250Shibler      register char *bp, *cap;
9260250Shibler {
9360250Shibler   for (; *bp; bp++)
9460250Shibler     if (bp[0] == ':'
9560250Shibler 	&& bp[1] == cap[0]
9660250Shibler 	&& bp[2] == cap[1])
9760250Shibler       return &bp[4];
9860250Shibler   return 0;
9960250Shibler }
10060250Shibler 
10160250Shibler int
tgetnum(cap)10260250Shibler tgetnum (cap)
10360250Shibler      char *cap;
10460250Shibler {
10560250Shibler   register char *ptr = find_capability (term_entry, cap);
10660250Shibler   if (!ptr || ptr[-1] != '#')
10760250Shibler     return -1;
10860250Shibler   return atoi (ptr);
10960250Shibler }
11060250Shibler 
11160250Shibler int
tgetflag(cap)11260250Shibler tgetflag (cap)
11360250Shibler      char *cap;
11460250Shibler {
11560250Shibler   register char *ptr = find_capability (term_entry, cap);
11660250Shibler   return 0 != ptr && ptr[-1] == ':';
11760250Shibler }
11860250Shibler 
11960250Shibler /* Look up a string-valued capability `cap'.
12060250Shibler    If `area' is nonzero, it points to a pointer to a block in which
12160250Shibler    to store the string.  That pointer is advanced over the space used.
12260250Shibler    If `area' is zero, space is allocated with `malloc'.  */
12360250Shibler 
12460250Shibler char *
tgetstr(cap,area)12560250Shibler tgetstr (cap, area)
12660250Shibler      char *cap;
12760250Shibler      char **area;
12860250Shibler {
12960250Shibler   register char *ptr = find_capability (term_entry, cap);
13060250Shibler   if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
13160250Shibler     return 0;
13260250Shibler   return tgetst1 (ptr, area);
13360250Shibler }
13460250Shibler 
13560250Shibler /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
13660250Shibler    gives meaning of character following \, or a space if no special meaning.
13760250Shibler    Eight characters per line within the string.  */
13860250Shibler 
13960250Shibler static char esctab[]
14060250Shibler   = " \007\010  \033\014 \
14160250Shibler       \012 \
14260250Shibler   \015 \011 \013 \
14360250Shibler         ";
14460250Shibler 
14560250Shibler /* Given a pointer to a string value inside a termcap entry (`ptr'),
14660250Shibler    copy the value and process \ and ^ abbreviations.
14760250Shibler    Copy into block that *area points to,
14860250Shibler    or to newly allocated storage if area is 0.  */
14960250Shibler 
15060250Shibler static char *
tgetst1(ptr,area)15160250Shibler tgetst1 (ptr, area)
15260250Shibler      char *ptr;
15360250Shibler      char **area;
15460250Shibler {
15560250Shibler   register char *p, *r;
15660250Shibler   register int c;
15760250Shibler   register int size;
15860250Shibler   char *ret;
15960250Shibler   register int c1;
16060250Shibler 
16160250Shibler   if (!ptr)
16260250Shibler     return 0;
16360250Shibler 
16460250Shibler   /* `ret' gets address of where to store the string */
16560250Shibler   if (!area)
16660250Shibler     {
16760250Shibler       /* Compute size of block needed (may overestimate) */
16860250Shibler       p = ptr;
16960250Shibler       while ((c = *p++) && c != ':' && c != '\n');
17060250Shibler       ret = (char *) xmalloc (p - ptr + 1);
17160250Shibler     }
17260250Shibler   else
17360250Shibler     ret = *area;
17460250Shibler 
17560250Shibler   /* Copy the string value, stopping at null or colon.  */
17660250Shibler   /* Also process ^ and \ abbreviations.  */
17760250Shibler   p = ptr;
17860250Shibler   r = ret;
17960250Shibler   while ((c = *p++) && c != ':' && c != '\n')
18060250Shibler     {
18160250Shibler       if (c == '^')
18260250Shibler 	c = *p++ & 037;
18360250Shibler       else if (c == '\\')
18460250Shibler 	{
18560250Shibler 	  c = *p++;
18660250Shibler 	  if (c >= '0' && c <= '7')
18760250Shibler 	    {
18860250Shibler 	      c -= '0';
18960250Shibler 	      size = 0;
19060250Shibler 
19160250Shibler 	      while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
19260250Shibler 		{
19360250Shibler 		  c *= 8;
19460250Shibler 		  c += c1 - '0';
19560250Shibler 		  p++;
19660250Shibler 		}
19760250Shibler 	    }
19860250Shibler 	  else if (c >= 0100 && c < 0200)
19960250Shibler 	    {
20060250Shibler 	      c1 = esctab[(c & ~040) - 0100];
20160250Shibler 	      if (c1 != ' ')
20260250Shibler 		c = c1;
20360250Shibler 	    }
20460250Shibler 	}
20560250Shibler       *r++ = c;
20660250Shibler     }
20760250Shibler   *r = 0;
20860250Shibler   /* Update *area */
20960250Shibler   if (area)
21060250Shibler     *area = r + 1;
21160250Shibler   return ret;
21260250Shibler }
21360250Shibler 
21460250Shibler /* Outputting a string with padding */
21560250Shibler 
21660250Shibler short ospeed;
21760250Shibler char PC;
21860250Shibler 
21960250Shibler /* Actual baud rate if positive;
22060250Shibler    - baud rate / 100 if negative.  */
22160250Shibler 
22260250Shibler static short speeds[] =
22360250Shibler   {
22460250Shibler #ifdef VMS
22560250Shibler     0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
22660250Shibler     -20, -24, -36, -48, -72, -96, -192
22760250Shibler #else /* not VMS */
22860250Shibler     0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
22960250Shibler     -18, -24, -48, -96, -192, -384
23060250Shibler #endif /* not VMS */
23160250Shibler   };
23260250Shibler 
tputs(string,nlines,outfun)23360250Shibler tputs (string, nlines, outfun)
23460250Shibler      register char *string;
23560250Shibler      int nlines;
23660250Shibler      register int (*outfun) ();
23760250Shibler {
23860250Shibler   register int padcount = 0;
23960250Shibler 
24060250Shibler   if (string == (char *) 0)
24160250Shibler     return;
24260250Shibler   while (*string >= '0' && *string <= '9')
24360250Shibler     {
24460250Shibler       padcount += *string++ - '0';
24560250Shibler       padcount *= 10;
24660250Shibler     }
24760250Shibler   if (*string == '.')
24860250Shibler     {
24960250Shibler       string++;
25060250Shibler       padcount += *string++ - '0';
25160250Shibler     }
25260250Shibler   if (*string == '*')
25360250Shibler     {
25460250Shibler       string++;
25560250Shibler       padcount *= nlines;
25660250Shibler     }
25760250Shibler   while (*string)
25860250Shibler     (*outfun) (*string++);
25960250Shibler 
26060250Shibler   /* padcount is now in units of tenths of msec.  */
26160250Shibler   padcount *= speeds[ospeed];
26260250Shibler   padcount += 500;
26360250Shibler   padcount /= 1000;
26460250Shibler   if (speeds[ospeed] < 0)
26560250Shibler     padcount = -padcount;
26660250Shibler   else
26760250Shibler     {
26860250Shibler       padcount += 50;
26960250Shibler       padcount /= 100;
27060250Shibler     }
27160250Shibler 
27260250Shibler   while (padcount-- > 0)
27360250Shibler     (*outfun) (PC);
27460250Shibler }
27560250Shibler 
27660250Shibler /* Finding the termcap entry in the termcap data base */
27760250Shibler 
27860250Shibler struct buffer
27960250Shibler   {
28060250Shibler     char *beg;
28160250Shibler     int size;
28260250Shibler     char *ptr;
28360250Shibler     int ateof;
28460250Shibler     int full;
28560250Shibler   };
28660250Shibler 
28760250Shibler /* Forward declarations of static functions */
28860250Shibler 
28960250Shibler static int scan_file ();
29060250Shibler static char *gobble_line ();
29160250Shibler static int compare_contin ();
29260250Shibler static int name_match ();
29360250Shibler 
29460250Shibler #ifdef VMS
29560250Shibler 
29660250Shibler #include <rmsdef.h>
29760250Shibler #include <fab.h>
29860250Shibler #include <nam.h>
29960250Shibler 
30060250Shibler static int
legal_filename_p(fn)30160250Shibler legal_filename_p (fn)
30260250Shibler      char *fn;
30360250Shibler {
30460250Shibler   struct FAB fab = cc$rms_fab;
30560250Shibler   struct NAM nam = cc$rms_nam;
30660250Shibler   char esa[NAM$C_MAXRSS];
30760250Shibler 
30860250Shibler   fab.fab$l_fna = fn;
30960250Shibler   fab.fab$b_fns = strlen(fn);
31060250Shibler   fab.fab$l_nam = &nam;
31160250Shibler   fab.fab$l_fop = FAB$M_NAM;
31260250Shibler 
31360250Shibler   nam.nam$l_esa = esa;
31460250Shibler   nam.nam$b_ess = sizeof esa;
31560250Shibler 
31660250Shibler   return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL;
31760250Shibler }
31860250Shibler 
31960250Shibler #endif /* VMS */
32060250Shibler 
32160250Shibler /* Find the termcap entry data for terminal type `name'
32260250Shibler    and store it in the block that `bp' points to.
32360250Shibler    Record its address for future use.
32460250Shibler 
32560250Shibler    If `bp' is zero, space is dynamically allocated.  */
32660250Shibler 
32760250Shibler int
tgetent(bp,name)32860250Shibler tgetent (bp, name)
32960250Shibler      char *bp, *name;
33060250Shibler {
33160250Shibler   register char *tem;
33260250Shibler   register int fd;
33360250Shibler   struct buffer buf;
33460250Shibler   register char *bp1;
33560250Shibler   char *bp2;
33660250Shibler   char *term;
33760250Shibler   int malloc_size = 0;
33860250Shibler   register int c;
33960250Shibler   char *tcenv;			/* TERMCAP value, if it contais :tc=.  */
34060250Shibler   char *indirect = 0;		/* Terminal type in :tc= in TERMCAP value.  */
34160250Shibler   int filep;
34260250Shibler 
34360250Shibler   tem = (char *) getenv ("TERMCAP");
34460250Shibler   if (tem && *tem == 0) tem = 0;
34560250Shibler 
34660250Shibler #ifdef VMS
34760250Shibler   filep = tem && legal_filename_p (tem);
34860250Shibler #else
34960250Shibler   filep = tem && (*tem == '/');
35060250Shibler #endif /* VMS */
35160250Shibler 
35260250Shibler   /* If tem is non-null and starts with / (in the un*x case, that is),
35360250Shibler      it is a file name to use instead of /etc/termcap.
35460250Shibler      If it is non-null and does not start with /,
35560250Shibler      it is the entry itself, but only if
35660250Shibler      the name the caller requested matches the TERM variable.  */
35760250Shibler 
35860250Shibler   if (tem && !filep && !strcmp (name, getenv ("TERM")))
35960250Shibler     {
36060250Shibler       indirect = tgetst1 (find_capability (tem, "tc"), 0);
36160250Shibler       if (!indirect)
36260250Shibler 	{
36360250Shibler 	  if (!bp)
36460250Shibler 	    bp = tem;
36560250Shibler 	  else
36660250Shibler 	    strcpy (bp, tem);
36760250Shibler 	  goto ret;
36860250Shibler 	}
36960250Shibler       else
37060250Shibler 	{			/* we will need to read /etc/termcap */
37160250Shibler 	  tcenv = tem;
37260250Shibler  	  tem = 0;
37360250Shibler 	}
37460250Shibler     }
37560250Shibler   else
37660250Shibler     indirect = (char *) 0;
37760250Shibler 
37860250Shibler   if (!tem)
37960250Shibler #ifdef VMS
38060250Shibler     tem = "emacs_library:[etc]termcap.dat";
38160250Shibler #else
38260250Shibler     tem = "/etc/termcap";
38360250Shibler #endif
38460250Shibler 
38560250Shibler   /* Here we know we must search a file and tem has its name.  */
38660250Shibler 
38760250Shibler   fd = open (tem, 0, 0);
38860250Shibler   if (fd < 0)
38960250Shibler     return -1;
39060250Shibler 
39160250Shibler   buf.size = BUFSIZE;
39260250Shibler   /* Add 1 to size to ensure room for terminating null.  */
39360250Shibler   buf.beg = (char *) xmalloc (buf.size + 1);
39460250Shibler   term = indirect ? indirect : name;
39560250Shibler 
39660250Shibler   if (!bp)
39760250Shibler     {
39860250Shibler       malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
39960250Shibler       bp = (char *) xmalloc (malloc_size);
40060250Shibler     }
40160250Shibler   bp1 = bp;
40260250Shibler 
40360250Shibler   if (indirect)			/* copy the data from the environment variable */
40460250Shibler     {
40560250Shibler       strcpy (bp, tcenv);
40660250Shibler       bp1 += strlen (tcenv);
40760250Shibler     }
40860250Shibler 
40960250Shibler   while (term)
41060250Shibler     {
41160250Shibler       /* Scan file, reading it via buf, till find start of main entry */
41260250Shibler       if (scan_file (term, fd, &buf) == 0)
41360250Shibler 	return 0;
41460250Shibler 
41560250Shibler       /* Free old `term' if appropriate.  */
41660250Shibler       if (term != name)
41760250Shibler 	free (term);
41860250Shibler 
41960250Shibler       /* If `bp' is malloc'd by us, make sure it is big enough.  */
42060250Shibler       if (malloc_size)
42160250Shibler 	{
42260250Shibler 	  malloc_size = bp1 - bp + buf.size;
42360250Shibler 	  tem = (char *) xrealloc (bp, malloc_size);
42460250Shibler 	  bp1 += tem - bp;
42560250Shibler 	  bp = tem;
42660250Shibler 	}
42760250Shibler 
42860250Shibler       bp2 = bp1;
42960250Shibler 
43060250Shibler       /* Copy the line of the entry from buf into bp.  */
43160250Shibler       tem = buf.ptr;
43260250Shibler       while ((*bp1++ = c = *tem++) && c != '\n')
43360250Shibler 	/* Drop out any \ newline sequence. */
43460250Shibler 	if (c == '\\' && *tem == '\n')
43560250Shibler 	  {
43660250Shibler 	    bp1--;
43760250Shibler 	    tem++;
43860250Shibler 	  }
43960250Shibler       *bp1 = 0;
44060250Shibler 
44160250Shibler       /* Does this entry refer to another terminal type's entry?  */
44260250Shibler       /* If something is found, copy it into heap and null-terminate it */
44360250Shibler       term = tgetst1 (find_capability (bp2, "tc"), 0);
44460250Shibler     }
44560250Shibler 
44660250Shibler   close (fd);
44760250Shibler   free (buf.beg);
44860250Shibler 
44960250Shibler   if (malloc_size)
45060250Shibler     {
45160250Shibler       bp = (char *) xrealloc (bp, bp1 - bp + 1);
45260250Shibler     }
45360250Shibler 
45460250Shibler  ret:
45560250Shibler   term_entry = bp;
45660250Shibler   if (malloc_size)
45760250Shibler     return (int) bp;
45860250Shibler   return 1;
45960250Shibler }
46060250Shibler 
46160250Shibler /* Given file open on `fd' and buffer `bufp',
46260250Shibler    scan the file from the beginning until a line is found
46360250Shibler    that starts the entry for terminal type `string'.
46460250Shibler    Returns 1 if successful, with that line in `bufp',
46560250Shibler    or returns 0 if no entry found in the file.  */
46660250Shibler 
46760250Shibler static int
scan_file(string,fd,bufp)46860250Shibler scan_file (string, fd, bufp)
46960250Shibler      char *string;
47060250Shibler      int fd;
47160250Shibler      register struct buffer *bufp;
47260250Shibler {
47360250Shibler   register char *tem;
47460250Shibler   register char *end;
47560250Shibler 
47660250Shibler   bufp->ptr = bufp->beg;
47760250Shibler   bufp->full = 0;
47860250Shibler   bufp->ateof = 0;
47960250Shibler   *bufp->ptr = 0;
48060250Shibler 
481*60297Shibler   lseek (fd, (off_t) 0, 0);
48260250Shibler 
48360250Shibler   while (!bufp->ateof)
48460250Shibler     {
48560250Shibler       /* Read a line into the buffer */
48660250Shibler       end = 0;
48760250Shibler       do
48860250Shibler 	{
48960250Shibler 	  /* if it is continued, append another line to it,
49060250Shibler 	     until a non-continued line ends */
49160250Shibler 	  end = gobble_line (fd, bufp, end);
49260250Shibler 	}
49360250Shibler       while (!bufp->ateof && end[-2] == '\\');
49460250Shibler 
49560250Shibler       if (*bufp->ptr != '#'
49660250Shibler 	  && name_match (bufp->ptr, string))
49760250Shibler 	return 1;
49860250Shibler 
49960250Shibler       /* Discard the line just processed */
50060250Shibler       bufp->ptr = end;
50160250Shibler     }
50260250Shibler   return 0;
50360250Shibler }
50460250Shibler 
50560250Shibler /* Return nonzero if NAME is one of the names specified
50660250Shibler    by termcap entry LINE.  */
50760250Shibler 
50860250Shibler static int
name_match(line,name)50960250Shibler name_match (line, name)
51060250Shibler      char *line, *name;
51160250Shibler {
51260250Shibler   register char *tem;
51360250Shibler 
51460250Shibler   if (!compare_contin (line, name))
51560250Shibler     return 1;
51660250Shibler   /* This line starts an entry.  Is it the right one?  */
51760250Shibler   for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
51860250Shibler     if (*tem == '|' && !compare_contin (tem + 1, name))
51960250Shibler       return 1;
52060250Shibler 
52160250Shibler   return 0;
52260250Shibler }
52360250Shibler 
52460250Shibler static int
compare_contin(str1,str2)52560250Shibler compare_contin (str1, str2)
52660250Shibler      register char *str1, *str2;
52760250Shibler {
52860250Shibler   register int c1, c2;
52960250Shibler   while (1)
53060250Shibler     {
53160250Shibler       c1 = *str1++;
53260250Shibler       c2 = *str2++;
53360250Shibler       while (c1 == '\\' && *str1 == '\n')
53460250Shibler 	{
53560250Shibler 	  str1++;
53660250Shibler 	  while ((c1 = *str1++) == ' ' || c1 == '\t');
53760250Shibler 	}
53860250Shibler       if (c2 == '\0')		/* end of type being looked up */
53960250Shibler 	{
54060250Shibler 	  if (c1 == '|' || c1 == ':') /* If end of name in data base, */
54160250Shibler 	    return 0;		/* we win. */
54260250Shibler 	  else
54360250Shibler 	    return 1;
54460250Shibler         }
54560250Shibler       else if (c1 != c2)
54660250Shibler 	return 1;
54760250Shibler     }
54860250Shibler }
54960250Shibler 
55060250Shibler /* Make sure that the buffer <- `bufp' contains a full line
55160250Shibler    of the file open on `fd', starting at the place `bufp->ptr'
55260250Shibler    points to.  Can read more of the file, discard stuff before
55360250Shibler    `bufp->ptr', or make the buffer bigger.
55460250Shibler 
55560250Shibler    Returns the pointer to after the newline ending the line,
55660250Shibler    or to the end of the file, if there is no newline to end it.
55760250Shibler 
55860250Shibler    Can also merge on continuation lines.  If `append_end' is
55960250Shibler    nonzero, it points past the newline of a line that is
56060250Shibler    continued; we add another line onto it and regard the whole
56160250Shibler    thing as one line.  The caller decides when a line is continued.  */
56260250Shibler 
56360250Shibler static char *
gobble_line(fd,bufp,append_end)56460250Shibler gobble_line (fd, bufp, append_end)
56560250Shibler      int fd;
56660250Shibler      register struct buffer *bufp;
56760250Shibler      char *append_end;
56860250Shibler {
56960250Shibler   register char *end;
57060250Shibler   register int nread;
57160250Shibler   register char *buf = bufp->beg;
57260250Shibler   register char *tem;
57360250Shibler 
57460250Shibler   if (append_end == 0)
57560250Shibler     append_end = bufp->ptr;
57660250Shibler 
57760250Shibler   while (1)
57860250Shibler     {
57960250Shibler       end = append_end;
58060250Shibler       while (*end && *end != '\n') end++;
58160250Shibler       if (*end)
58260250Shibler         break;
58360250Shibler       if (bufp->ateof)
58460250Shibler 	return buf + bufp->full;
58560250Shibler       if (bufp->ptr == buf)
58660250Shibler 	{
58760250Shibler 	  if (bufp->full == bufp->size)
58860250Shibler 	    {
58960250Shibler 	      bufp->size *= 2;
59060250Shibler 	      /* Add 1 to size to ensure room for terminating null.  */
59160250Shibler 	      tem = (char *) xrealloc (buf, bufp->size + 1);
59260250Shibler 	      bufp->ptr = (bufp->ptr - buf) + tem;
59360250Shibler 	      append_end = (append_end - buf) + tem;
59460250Shibler 	      bufp->beg = buf = tem;
59560250Shibler 	    }
59660250Shibler 	}
59760250Shibler       else
59860250Shibler 	{
59960250Shibler 	  append_end -= bufp->ptr - buf;
60060250Shibler 	  bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf);
60160250Shibler 	  bufp->ptr = buf;
60260250Shibler 	}
60360250Shibler       if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
60460250Shibler 	bufp->ateof = 1;
60560250Shibler       bufp->full += nread;
60660250Shibler       buf[bufp->full] = 0;
60760250Shibler     }
60860250Shibler   return end + 1;
60960250Shibler }
61060250Shibler 
61160250Shibler #ifdef TEST
61260250Shibler 
61360250Shibler #include <stdio.h>
61460250Shibler 
main(argc,argv)61560250Shibler main (argc, argv)
61660250Shibler      int argc;
61760250Shibler      char **argv;
61860250Shibler {
61960250Shibler   char *term;
62060250Shibler   char *buf;
62160250Shibler 
62260250Shibler   term = argv[1];
62360250Shibler   printf ("TERM: %s\n", term);
62460250Shibler 
62560250Shibler   buf = (char *) tgetent (0, term);
62660250Shibler   if ((int) buf <= 0)
62760250Shibler     {
62860250Shibler       printf ("No entry.\n");
62960250Shibler       return 0;
63060250Shibler     }
63160250Shibler 
63260250Shibler   printf ("Entry: %s\n", buf);
63360250Shibler 
63460250Shibler   tprint ("cm");
63560250Shibler   tprint ("AL");
63660250Shibler 
63760250Shibler   printf ("co: %d\n", tgetnum ("co"));
63860250Shibler   printf ("am: %d\n", tgetflag ("am"));
63960250Shibler }
64060250Shibler 
tprint(cap)64160250Shibler tprint (cap)
64260250Shibler      char *cap;
64360250Shibler {
64460250Shibler   char *x = tgetstr (cap, 0);
64560250Shibler   register char *y;
64660250Shibler 
64760250Shibler   printf ("%s: ", cap);
64860250Shibler   if (x)
64960250Shibler     {
65060250Shibler       for (y = x; *y; y++)
65160250Shibler 	if (*y <= ' ' || *y == 0177)
65260250Shibler 	  printf ("\\%0o", *y);
65360250Shibler 	else
65460250Shibler 	  putchar (*y);
65560250Shibler       free (x);
65660250Shibler     }
65760250Shibler   else
65860250Shibler     printf ("none");
65960250Shibler   putchar ('\n');
66060250Shibler }
66160250Shibler 
66260250Shibler #endif /* TEST */
66360250Shibler 
664