1*60250Shibler /* Work-alike for termcap, plus extra features.
2*60250Shibler    Copyright (C) 1985, 1986 Free Software Foundation, Inc.
3*60250Shibler 
4*60250Shibler     This program is free software; you can redistribute it and/or modify
5*60250Shibler     it under the terms of the GNU General Public License as published by
6*60250Shibler     the Free Software Foundation; either version 1, or (at your option)
7*60250Shibler     any later version.
8*60250Shibler 
9*60250Shibler     This program is distributed in the hope that it will be useful,
10*60250Shibler     but WITHOUT ANY WARRANTY; without even the implied warranty of
11*60250Shibler     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*60250Shibler     GNU General Public License for more details.
13*60250Shibler 
14*60250Shibler     You should have received a copy of the GNU General Public License
15*60250Shibler     along with this program; if not, write to the Free Software
16*60250Shibler     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17*60250Shibler 
18*60250Shibler In other words, you are welcome to use, share and improve this program.
19*60250Shibler You are forbidden to forbid anyone else to use, share and improve
20*60250Shibler what you give them.   Help stamp out software-hoarding!  */
21*60250Shibler 
22*60250Shibler 
23*60250Shibler 
24*60250Shibler /* BUFSIZE is the initial size allocated for the buffer
25*60250Shibler    for reading the termcap file.
26*60250Shibler    It is not a limit.
27*60250Shibler    Make it large normally for speed.
28*60250Shibler    Make it variable when debugging, so can exercise
29*60250Shibler    increasing the space dynamically.  */
30*60250Shibler 
31*60250Shibler #ifdef emacs
32*60250Shibler #include "config.h"
33*60250Shibler #endif
34*60250Shibler 
35*60250Shibler #ifndef BUFSIZE
36*60250Shibler #ifdef DEBUG
37*60250Shibler #define BUFSIZE bufsize
38*60250Shibler 
39*60250Shibler int bufsize = 128;
40*60250Shibler #else
41*60250Shibler #define BUFSIZE 2048
42*60250Shibler #endif
43*60250Shibler #endif
44*60250Shibler 
45*60250Shibler #ifndef emacs
46*60250Shibler static
47*60250Shibler memory_out ()
48*60250Shibler {
49*60250Shibler   write (2, "Virtual memory exhausted\n", 25);
50*60250Shibler   exit (1);
51*60250Shibler }
52*60250Shibler 
53*60250Shibler static int
54*60250Shibler xmalloc (size)
55*60250Shibler      int size;
56*60250Shibler {
57*60250Shibler   register tem = malloc (size);
58*60250Shibler   if (!tem)
59*60250Shibler     memory_out ();
60*60250Shibler   return tem;
61*60250Shibler }
62*60250Shibler 
63*60250Shibler static int
64*60250Shibler xrealloc (ptr, size)
65*60250Shibler      int ptr;
66*60250Shibler      int size;
67*60250Shibler {
68*60250Shibler   register tem = realloc (ptr, size);
69*60250Shibler   if (!tem)
70*60250Shibler     memory_out ();
71*60250Shibler   return tem;
72*60250Shibler }
73*60250Shibler #endif /* not emacs */
74*60250Shibler 
75*60250Shibler /* Looking up capabilities in the entry already found */
76*60250Shibler 
77*60250Shibler /* The pointer to the data made by tgetent is left here
78*60250Shibler    for tgetnum, tgetflag and tgetstr to find.  */
79*60250Shibler 
80*60250Shibler static char *term_entry;
81*60250Shibler 
82*60250Shibler static char *tgetst1 ();
83*60250Shibler 
84*60250Shibler /* This is the main subroutine that is used to search
85*60250Shibler    an entry for a particular capability */
86*60250Shibler 
87*60250Shibler static char *
88*60250Shibler find_capability (bp, cap)
89*60250Shibler      register char *bp, *cap;
90*60250Shibler {
91*60250Shibler   for (; *bp; bp++)
92*60250Shibler     if (bp[0] == ':'
93*60250Shibler 	&& bp[1] == cap[0]
94*60250Shibler 	&& bp[2] == cap[1])
95*60250Shibler       return &bp[4];
96*60250Shibler   return 0;
97*60250Shibler }
98*60250Shibler 
99*60250Shibler int
100*60250Shibler tgetnum (cap)
101*60250Shibler      char *cap;
102*60250Shibler {
103*60250Shibler   register char *ptr = find_capability (term_entry, cap);
104*60250Shibler   if (!ptr || ptr[-1] != '#')
105*60250Shibler     return -1;
106*60250Shibler   return atoi (ptr);
107*60250Shibler }
108*60250Shibler 
109*60250Shibler int
110*60250Shibler tgetflag (cap)
111*60250Shibler      char *cap;
112*60250Shibler {
113*60250Shibler   register char *ptr = find_capability (term_entry, cap);
114*60250Shibler   return 0 != ptr && ptr[-1] == ':';
115*60250Shibler }
116*60250Shibler 
117*60250Shibler /* Look up a string-valued capability `cap'.
118*60250Shibler    If `area' is nonzero, it points to a pointer to a block in which
119*60250Shibler    to store the string.  That pointer is advanced over the space used.
120*60250Shibler    If `area' is zero, space is allocated with `malloc'.  */
121*60250Shibler 
122*60250Shibler char *
123*60250Shibler tgetstr (cap, area)
124*60250Shibler      char *cap;
125*60250Shibler      char **area;
126*60250Shibler {
127*60250Shibler   register char *ptr = find_capability (term_entry, cap);
128*60250Shibler   if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
129*60250Shibler     return 0;
130*60250Shibler   return tgetst1 (ptr, area);
131*60250Shibler }
132*60250Shibler 
133*60250Shibler /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
134*60250Shibler    gives meaning of character following \, or a space if no special meaning.
135*60250Shibler    Eight characters per line within the string.  */
136*60250Shibler 
137*60250Shibler static char esctab[]
138*60250Shibler   = " \007\010  \033\014 \
139*60250Shibler       \012 \
140*60250Shibler   \015 \011 \013 \
141*60250Shibler         ";
142*60250Shibler 
143*60250Shibler /* Given a pointer to a string value inside a termcap entry (`ptr'),
144*60250Shibler    copy the value and process \ and ^ abbreviations.
145*60250Shibler    Copy into block that *area points to,
146*60250Shibler    or to newly allocated storage if area is 0.  */
147*60250Shibler 
148*60250Shibler static char *
149*60250Shibler tgetst1 (ptr, area)
150*60250Shibler      char *ptr;
151*60250Shibler      char **area;
152*60250Shibler {
153*60250Shibler   register char *p, *r;
154*60250Shibler   register int c;
155*60250Shibler   register int size;
156*60250Shibler   char *ret;
157*60250Shibler   register int c1;
158*60250Shibler 
159*60250Shibler   if (!ptr)
160*60250Shibler     return 0;
161*60250Shibler 
162*60250Shibler   /* `ret' gets address of where to store the string */
163*60250Shibler   if (!area)
164*60250Shibler     {
165*60250Shibler       /* Compute size of block needed (may overestimate) */
166*60250Shibler       p = ptr;
167*60250Shibler       while ((c = *p++) && c != ':' && c != '\n');
168*60250Shibler       ret = (char *) xmalloc (p - ptr + 1);
169*60250Shibler     }
170*60250Shibler   else
171*60250Shibler     ret = *area;
172*60250Shibler 
173*60250Shibler   /* Copy the string value, stopping at null or colon.  */
174*60250Shibler   /* Also process ^ and \ abbreviations.  */
175*60250Shibler   p = ptr;
176*60250Shibler   r = ret;
177*60250Shibler   while ((c = *p++) && c != ':' && c != '\n')
178*60250Shibler     {
179*60250Shibler       if (c == '^')
180*60250Shibler 	c = *p++ & 037;
181*60250Shibler       else if (c == '\\')
182*60250Shibler 	{
183*60250Shibler 	  c = *p++;
184*60250Shibler 	  if (c >= '0' && c <= '7')
185*60250Shibler 	    {
186*60250Shibler 	      c -= '0';
187*60250Shibler 	      size = 0;
188*60250Shibler 
189*60250Shibler 	      while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
190*60250Shibler 		{
191*60250Shibler 		  c *= 8;
192*60250Shibler 		  c += c1 - '0';
193*60250Shibler 		  p++;
194*60250Shibler 		}
195*60250Shibler 	    }
196*60250Shibler 	  else if (c >= 0100 && c < 0200)
197*60250Shibler 	    {
198*60250Shibler 	      c1 = esctab[(c & ~040) - 0100];
199*60250Shibler 	      if (c1 != ' ')
200*60250Shibler 		c = c1;
201*60250Shibler 	    }
202*60250Shibler 	}
203*60250Shibler       *r++ = c;
204*60250Shibler     }
205*60250Shibler   *r = 0;
206*60250Shibler   /* Update *area */
207*60250Shibler   if (area)
208*60250Shibler     *area = r + 1;
209*60250Shibler   return ret;
210*60250Shibler }
211*60250Shibler 
212*60250Shibler /* Outputting a string with padding */
213*60250Shibler 
214*60250Shibler short ospeed;
215*60250Shibler char PC;
216*60250Shibler 
217*60250Shibler /* Actual baud rate if positive;
218*60250Shibler    - baud rate / 100 if negative.  */
219*60250Shibler 
220*60250Shibler static short speeds[] =
221*60250Shibler   {
222*60250Shibler #ifdef VMS
223*60250Shibler     0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
224*60250Shibler     -20, -24, -36, -48, -72, -96, -192
225*60250Shibler #else /* not VMS */
226*60250Shibler     0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
227*60250Shibler     -18, -24, -48, -96, -192, -384
228*60250Shibler #endif /* not VMS */
229*60250Shibler   };
230*60250Shibler 
231*60250Shibler tputs (string, nlines, outfun)
232*60250Shibler      register char *string;
233*60250Shibler      int nlines;
234*60250Shibler      register int (*outfun) ();
235*60250Shibler {
236*60250Shibler   register int padcount = 0;
237*60250Shibler 
238*60250Shibler   if (string == (char *) 0)
239*60250Shibler     return;
240*60250Shibler   while (*string >= '0' && *string <= '9')
241*60250Shibler     {
242*60250Shibler       padcount += *string++ - '0';
243*60250Shibler       padcount *= 10;
244*60250Shibler     }
245*60250Shibler   if (*string == '.')
246*60250Shibler     {
247*60250Shibler       string++;
248*60250Shibler       padcount += *string++ - '0';
249*60250Shibler     }
250*60250Shibler   if (*string == '*')
251*60250Shibler     {
252*60250Shibler       string++;
253*60250Shibler       padcount *= nlines;
254*60250Shibler     }
255*60250Shibler   while (*string)
256*60250Shibler     (*outfun) (*string++);
257*60250Shibler 
258*60250Shibler   /* padcount is now in units of tenths of msec.  */
259*60250Shibler   padcount *= speeds[ospeed];
260*60250Shibler   padcount += 500;
261*60250Shibler   padcount /= 1000;
262*60250Shibler   if (speeds[ospeed] < 0)
263*60250Shibler     padcount = -padcount;
264*60250Shibler   else
265*60250Shibler     {
266*60250Shibler       padcount += 50;
267*60250Shibler       padcount /= 100;
268*60250Shibler     }
269*60250Shibler 
270*60250Shibler   while (padcount-- > 0)
271*60250Shibler     (*outfun) (PC);
272*60250Shibler }
273*60250Shibler 
274*60250Shibler /* Finding the termcap entry in the termcap data base */
275*60250Shibler 
276*60250Shibler struct buffer
277*60250Shibler   {
278*60250Shibler     char *beg;
279*60250Shibler     int size;
280*60250Shibler     char *ptr;
281*60250Shibler     int ateof;
282*60250Shibler     int full;
283*60250Shibler   };
284*60250Shibler 
285*60250Shibler /* Forward declarations of static functions */
286*60250Shibler 
287*60250Shibler static int scan_file ();
288*60250Shibler static char *gobble_line ();
289*60250Shibler static int compare_contin ();
290*60250Shibler static int name_match ();
291*60250Shibler 
292*60250Shibler #ifdef VMS
293*60250Shibler 
294*60250Shibler #include <rmsdef.h>
295*60250Shibler #include <fab.h>
296*60250Shibler #include <nam.h>
297*60250Shibler 
298*60250Shibler static int
299*60250Shibler legal_filename_p (fn)
300*60250Shibler      char *fn;
301*60250Shibler {
302*60250Shibler   struct FAB fab = cc$rms_fab;
303*60250Shibler   struct NAM nam = cc$rms_nam;
304*60250Shibler   char esa[NAM$C_MAXRSS];
305*60250Shibler 
306*60250Shibler   fab.fab$l_fna = fn;
307*60250Shibler   fab.fab$b_fns = strlen(fn);
308*60250Shibler   fab.fab$l_nam = &nam;
309*60250Shibler   fab.fab$l_fop = FAB$M_NAM;
310*60250Shibler 
311*60250Shibler   nam.nam$l_esa = esa;
312*60250Shibler   nam.nam$b_ess = sizeof esa;
313*60250Shibler 
314*60250Shibler   return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL;
315*60250Shibler }
316*60250Shibler 
317*60250Shibler #endif /* VMS */
318*60250Shibler 
319*60250Shibler /* Find the termcap entry data for terminal type `name'
320*60250Shibler    and store it in the block that `bp' points to.
321*60250Shibler    Record its address for future use.
322*60250Shibler 
323*60250Shibler    If `bp' is zero, space is dynamically allocated.  */
324*60250Shibler 
325*60250Shibler int
326*60250Shibler tgetent (bp, name)
327*60250Shibler      char *bp, *name;
328*60250Shibler {
329*60250Shibler   register char *tem;
330*60250Shibler   register int fd;
331*60250Shibler   struct buffer buf;
332*60250Shibler   register char *bp1;
333*60250Shibler   char *bp2;
334*60250Shibler   char *term;
335*60250Shibler   int malloc_size = 0;
336*60250Shibler   register int c;
337*60250Shibler   char *tcenv;			/* TERMCAP value, if it contais :tc=.  */
338*60250Shibler   char *indirect = 0;		/* Terminal type in :tc= in TERMCAP value.  */
339*60250Shibler   int filep;
340*60250Shibler 
341*60250Shibler   tem = (char *) getenv ("TERMCAP");
342*60250Shibler   if (tem && *tem == 0) tem = 0;
343*60250Shibler 
344*60250Shibler #ifdef VMS
345*60250Shibler   filep = tem && legal_filename_p (tem);
346*60250Shibler #else
347*60250Shibler   filep = tem && (*tem == '/');
348*60250Shibler #endif /* VMS */
349*60250Shibler 
350*60250Shibler   /* If tem is non-null and starts with / (in the un*x case, that is),
351*60250Shibler      it is a file name to use instead of /etc/termcap.
352*60250Shibler      If it is non-null and does not start with /,
353*60250Shibler      it is the entry itself, but only if
354*60250Shibler      the name the caller requested matches the TERM variable.  */
355*60250Shibler 
356*60250Shibler   if (tem && !filep && !strcmp (name, getenv ("TERM")))
357*60250Shibler     {
358*60250Shibler       indirect = tgetst1 (find_capability (tem, "tc"), 0);
359*60250Shibler       if (!indirect)
360*60250Shibler 	{
361*60250Shibler 	  if (!bp)
362*60250Shibler 	    bp = tem;
363*60250Shibler 	  else
364*60250Shibler 	    strcpy (bp, tem);
365*60250Shibler 	  goto ret;
366*60250Shibler 	}
367*60250Shibler       else
368*60250Shibler 	{			/* we will need to read /etc/termcap */
369*60250Shibler 	  tcenv = tem;
370*60250Shibler  	  tem = 0;
371*60250Shibler 	}
372*60250Shibler     }
373*60250Shibler   else
374*60250Shibler     indirect = (char *) 0;
375*60250Shibler 
376*60250Shibler   if (!tem)
377*60250Shibler #ifdef VMS
378*60250Shibler     tem = "emacs_library:[etc]termcap.dat";
379*60250Shibler #else
380*60250Shibler     tem = "/etc/termcap";
381*60250Shibler #endif
382*60250Shibler 
383*60250Shibler   /* Here we know we must search a file and tem has its name.  */
384*60250Shibler 
385*60250Shibler   fd = open (tem, 0, 0);
386*60250Shibler   if (fd < 0)
387*60250Shibler     return -1;
388*60250Shibler 
389*60250Shibler   buf.size = BUFSIZE;
390*60250Shibler   /* Add 1 to size to ensure room for terminating null.  */
391*60250Shibler   buf.beg = (char *) xmalloc (buf.size + 1);
392*60250Shibler   term = indirect ? indirect : name;
393*60250Shibler 
394*60250Shibler   if (!bp)
395*60250Shibler     {
396*60250Shibler       malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
397*60250Shibler       bp = (char *) xmalloc (malloc_size);
398*60250Shibler     }
399*60250Shibler   bp1 = bp;
400*60250Shibler 
401*60250Shibler   if (indirect)			/* copy the data from the environment variable */
402*60250Shibler     {
403*60250Shibler       strcpy (bp, tcenv);
404*60250Shibler       bp1 += strlen (tcenv);
405*60250Shibler     }
406*60250Shibler 
407*60250Shibler   while (term)
408*60250Shibler     {
409*60250Shibler       /* Scan file, reading it via buf, till find start of main entry */
410*60250Shibler       if (scan_file (term, fd, &buf) == 0)
411*60250Shibler 	return 0;
412*60250Shibler 
413*60250Shibler       /* Free old `term' if appropriate.  */
414*60250Shibler       if (term != name)
415*60250Shibler 	free (term);
416*60250Shibler 
417*60250Shibler       /* If `bp' is malloc'd by us, make sure it is big enough.  */
418*60250Shibler       if (malloc_size)
419*60250Shibler 	{
420*60250Shibler 	  malloc_size = bp1 - bp + buf.size;
421*60250Shibler 	  tem = (char *) xrealloc (bp, malloc_size);
422*60250Shibler 	  bp1 += tem - bp;
423*60250Shibler 	  bp = tem;
424*60250Shibler 	}
425*60250Shibler 
426*60250Shibler       bp2 = bp1;
427*60250Shibler 
428*60250Shibler       /* Copy the line of the entry from buf into bp.  */
429*60250Shibler       tem = buf.ptr;
430*60250Shibler       while ((*bp1++ = c = *tem++) && c != '\n')
431*60250Shibler 	/* Drop out any \ newline sequence. */
432*60250Shibler 	if (c == '\\' && *tem == '\n')
433*60250Shibler 	  {
434*60250Shibler 	    bp1--;
435*60250Shibler 	    tem++;
436*60250Shibler 	  }
437*60250Shibler       *bp1 = 0;
438*60250Shibler 
439*60250Shibler       /* Does this entry refer to another terminal type's entry?  */
440*60250Shibler       /* If something is found, copy it into heap and null-terminate it */
441*60250Shibler       term = tgetst1 (find_capability (bp2, "tc"), 0);
442*60250Shibler     }
443*60250Shibler 
444*60250Shibler   close (fd);
445*60250Shibler   free (buf.beg);
446*60250Shibler 
447*60250Shibler   if (malloc_size)
448*60250Shibler     {
449*60250Shibler       bp = (char *) xrealloc (bp, bp1 - bp + 1);
450*60250Shibler     }
451*60250Shibler 
452*60250Shibler  ret:
453*60250Shibler   term_entry = bp;
454*60250Shibler   if (malloc_size)
455*60250Shibler     return (int) bp;
456*60250Shibler   return 1;
457*60250Shibler }
458*60250Shibler 
459*60250Shibler /* Given file open on `fd' and buffer `bufp',
460*60250Shibler    scan the file from the beginning until a line is found
461*60250Shibler    that starts the entry for terminal type `string'.
462*60250Shibler    Returns 1 if successful, with that line in `bufp',
463*60250Shibler    or returns 0 if no entry found in the file.  */
464*60250Shibler 
465*60250Shibler static int
466*60250Shibler scan_file (string, fd, bufp)
467*60250Shibler      char *string;
468*60250Shibler      int fd;
469*60250Shibler      register struct buffer *bufp;
470*60250Shibler {
471*60250Shibler   register char *tem;
472*60250Shibler   register char *end;
473*60250Shibler 
474*60250Shibler   bufp->ptr = bufp->beg;
475*60250Shibler   bufp->full = 0;
476*60250Shibler   bufp->ateof = 0;
477*60250Shibler   *bufp->ptr = 0;
478*60250Shibler 
479*60250Shibler   lseek (fd, 0L, 0);
480*60250Shibler 
481*60250Shibler   while (!bufp->ateof)
482*60250Shibler     {
483*60250Shibler       /* Read a line into the buffer */
484*60250Shibler       end = 0;
485*60250Shibler       do
486*60250Shibler 	{
487*60250Shibler 	  /* if it is continued, append another line to it,
488*60250Shibler 	     until a non-continued line ends */
489*60250Shibler 	  end = gobble_line (fd, bufp, end);
490*60250Shibler 	}
491*60250Shibler       while (!bufp->ateof && end[-2] == '\\');
492*60250Shibler 
493*60250Shibler       if (*bufp->ptr != '#'
494*60250Shibler 	  && name_match (bufp->ptr, string))
495*60250Shibler 	return 1;
496*60250Shibler 
497*60250Shibler       /* Discard the line just processed */
498*60250Shibler       bufp->ptr = end;
499*60250Shibler     }
500*60250Shibler   return 0;
501*60250Shibler }
502*60250Shibler 
503*60250Shibler /* Return nonzero if NAME is one of the names specified
504*60250Shibler    by termcap entry LINE.  */
505*60250Shibler 
506*60250Shibler static int
507*60250Shibler name_match (line, name)
508*60250Shibler      char *line, *name;
509*60250Shibler {
510*60250Shibler   register char *tem;
511*60250Shibler 
512*60250Shibler   if (!compare_contin (line, name))
513*60250Shibler     return 1;
514*60250Shibler   /* This line starts an entry.  Is it the right one?  */
515*60250Shibler   for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
516*60250Shibler     if (*tem == '|' && !compare_contin (tem + 1, name))
517*60250Shibler       return 1;
518*60250Shibler 
519*60250Shibler   return 0;
520*60250Shibler }
521*60250Shibler 
522*60250Shibler static int
523*60250Shibler compare_contin (str1, str2)
524*60250Shibler      register char *str1, *str2;
525*60250Shibler {
526*60250Shibler   register int c1, c2;
527*60250Shibler   while (1)
528*60250Shibler     {
529*60250Shibler       c1 = *str1++;
530*60250Shibler       c2 = *str2++;
531*60250Shibler       while (c1 == '\\' && *str1 == '\n')
532*60250Shibler 	{
533*60250Shibler 	  str1++;
534*60250Shibler 	  while ((c1 = *str1++) == ' ' || c1 == '\t');
535*60250Shibler 	}
536*60250Shibler       if (c2 == '\0')		/* end of type being looked up */
537*60250Shibler 	{
538*60250Shibler 	  if (c1 == '|' || c1 == ':') /* If end of name in data base, */
539*60250Shibler 	    return 0;		/* we win. */
540*60250Shibler 	  else
541*60250Shibler 	    return 1;
542*60250Shibler         }
543*60250Shibler       else if (c1 != c2)
544*60250Shibler 	return 1;
545*60250Shibler     }
546*60250Shibler }
547*60250Shibler 
548*60250Shibler /* Make sure that the buffer <- `bufp' contains a full line
549*60250Shibler    of the file open on `fd', starting at the place `bufp->ptr'
550*60250Shibler    points to.  Can read more of the file, discard stuff before
551*60250Shibler    `bufp->ptr', or make the buffer bigger.
552*60250Shibler 
553*60250Shibler    Returns the pointer to after the newline ending the line,
554*60250Shibler    or to the end of the file, if there is no newline to end it.
555*60250Shibler 
556*60250Shibler    Can also merge on continuation lines.  If `append_end' is
557*60250Shibler    nonzero, it points past the newline of a line that is
558*60250Shibler    continued; we add another line onto it and regard the whole
559*60250Shibler    thing as one line.  The caller decides when a line is continued.  */
560*60250Shibler 
561*60250Shibler static char *
562*60250Shibler gobble_line (fd, bufp, append_end)
563*60250Shibler      int fd;
564*60250Shibler      register struct buffer *bufp;
565*60250Shibler      char *append_end;
566*60250Shibler {
567*60250Shibler   register char *end;
568*60250Shibler   register int nread;
569*60250Shibler   register char *buf = bufp->beg;
570*60250Shibler   register char *tem;
571*60250Shibler 
572*60250Shibler   if (append_end == 0)
573*60250Shibler     append_end = bufp->ptr;
574*60250Shibler 
575*60250Shibler   while (1)
576*60250Shibler     {
577*60250Shibler       end = append_end;
578*60250Shibler       while (*end && *end != '\n') end++;
579*60250Shibler       if (*end)
580*60250Shibler         break;
581*60250Shibler       if (bufp->ateof)
582*60250Shibler 	return buf + bufp->full;
583*60250Shibler       if (bufp->ptr == buf)
584*60250Shibler 	{
585*60250Shibler 	  if (bufp->full == bufp->size)
586*60250Shibler 	    {
587*60250Shibler 	      bufp->size *= 2;
588*60250Shibler 	      /* Add 1 to size to ensure room for terminating null.  */
589*60250Shibler 	      tem = (char *) xrealloc (buf, bufp->size + 1);
590*60250Shibler 	      bufp->ptr = (bufp->ptr - buf) + tem;
591*60250Shibler 	      append_end = (append_end - buf) + tem;
592*60250Shibler 	      bufp->beg = buf = tem;
593*60250Shibler 	    }
594*60250Shibler 	}
595*60250Shibler       else
596*60250Shibler 	{
597*60250Shibler 	  append_end -= bufp->ptr - buf;
598*60250Shibler 	  bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf);
599*60250Shibler 	  bufp->ptr = buf;
600*60250Shibler 	}
601*60250Shibler       if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
602*60250Shibler 	bufp->ateof = 1;
603*60250Shibler       bufp->full += nread;
604*60250Shibler       buf[bufp->full] = 0;
605*60250Shibler     }
606*60250Shibler   return end + 1;
607*60250Shibler }
608*60250Shibler 
609*60250Shibler #ifdef TEST
610*60250Shibler 
611*60250Shibler #include <stdio.h>
612*60250Shibler 
613*60250Shibler main (argc, argv)
614*60250Shibler      int argc;
615*60250Shibler      char **argv;
616*60250Shibler {
617*60250Shibler   char *term;
618*60250Shibler   char *buf;
619*60250Shibler 
620*60250Shibler   term = argv[1];
621*60250Shibler   printf ("TERM: %s\n", term);
622*60250Shibler 
623*60250Shibler   buf = (char *) tgetent (0, term);
624*60250Shibler   if ((int) buf <= 0)
625*60250Shibler     {
626*60250Shibler       printf ("No entry.\n");
627*60250Shibler       return 0;
628*60250Shibler     }
629*60250Shibler 
630*60250Shibler   printf ("Entry: %s\n", buf);
631*60250Shibler 
632*60250Shibler   tprint ("cm");
633*60250Shibler   tprint ("AL");
634*60250Shibler 
635*60250Shibler   printf ("co: %d\n", tgetnum ("co"));
636*60250Shibler   printf ("am: %d\n", tgetflag ("am"));
637*60250Shibler }
638*60250Shibler 
639*60250Shibler tprint (cap)
640*60250Shibler      char *cap;
641*60250Shibler {
642*60250Shibler   char *x = tgetstr (cap, 0);
643*60250Shibler   register char *y;
644*60250Shibler 
645*60250Shibler   printf ("%s: ", cap);
646*60250Shibler   if (x)
647*60250Shibler     {
648*60250Shibler       for (y = x; *y; y++)
649*60250Shibler 	if (*y <= ' ' || *y == 0177)
650*60250Shibler 	  printf ("\\%0o", *y);
651*60250Shibler 	else
652*60250Shibler 	  putchar (*y);
653*60250Shibler       free (x);
654*60250Shibler     }
655*60250Shibler   else
656*60250Shibler     printf ("none");
657*60250Shibler   putchar ('\n');
658*60250Shibler }
659*60250Shibler 
660*60250Shibler #endif /* TEST */
661*60250Shibler 
662