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