* lisp/emacs-lisp/bytecomp.el (byte-compile-disable-print-circle): Obsolete.
[emacs.git] / src / termcap.c
blob69ce56d93b3d1e3fe3f4d30e77d4d7a32bd5e4fa
1 /* Work-alike for termcap, plus extra features.
2 Copyright (C) 1985, 1986, 1993, 1994, 1995, 2000, 2001, 2002, 2003,
3 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA. */
20 /* Emacs config.h may rename various library functions such as malloc. */
21 #include <config.h>
22 #include <setjmp.h>
23 #include <sys/file.h>
24 #include <fcntl.h>
25 #include <unistd.h>
27 #include "lisp.h"
29 #ifndef NULL
30 #define NULL (char *) 0
31 #endif
33 /* BUFSIZE is the initial size allocated for the buffer
34 for reading the termcap file.
35 It is not a limit.
36 Make it large normally for speed.
37 Make it variable when debugging, so can exercise
38 increasing the space dynamically. */
40 #ifndef BUFSIZE
41 #ifdef DEBUG
42 #define BUFSIZE bufsize
44 int bufsize = 128;
45 #else
46 #define BUFSIZE 2048
47 #endif
48 #endif
50 #ifndef TERMCAP_FILE
51 #define TERMCAP_FILE "/etc/termcap"
52 #endif
55 /* Looking up capabilities in the entry already found. */
57 /* The pointer to the data made by tgetent is left here
58 for tgetnum, tgetflag and tgetstr to find. */
59 static char *term_entry;
61 static char *tgetst1 (char *ptr, char **area);
63 /* Search entry BP for capability CAP.
64 Return a pointer to the capability (in BP) if found,
65 0 if not found. */
67 static char *
68 find_capability (register char *bp, register char *cap)
70 for (; *bp; bp++)
71 if (bp[0] == ':'
72 && bp[1] == cap[0]
73 && bp[2] == cap[1])
74 return &bp[4];
75 return NULL;
78 int
79 tgetnum (char *cap)
81 register char *ptr = find_capability (term_entry, cap);
82 if (!ptr || ptr[-1] != '#')
83 return -1;
84 return atoi (ptr);
87 int
88 tgetflag (char *cap)
90 register char *ptr = find_capability (term_entry, cap);
91 return ptr && ptr[-1] == ':';
94 /* Look up a string-valued capability CAP.
95 If AREA is non-null, it points to a pointer to a block in which
96 to store the string. That pointer is advanced over the space used.
97 If AREA is null, space is allocated with `malloc'. */
99 char *
100 tgetstr (char *cap, char **area)
102 register char *ptr = find_capability (term_entry, cap);
103 if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
104 return NULL;
105 return tgetst1 (ptr, area);
108 #ifdef IS_EBCDIC_HOST
109 /* Table, indexed by a character in range 0200 to 0300 with 0200 subtracted,
110 gives meaning of character following \, or a space if no special meaning.
111 Sixteen characters per line within the string. */
113 static const char esctab[]
114 = " \057\026 \047\014 \
115 \025 \015 \
116 \005 \013 \
118 #else
119 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
120 gives meaning of character following \, or a space if no special meaning.
121 Eight characters per line within the string. */
123 static const char esctab[]
124 = " \007\010 \033\014 \
125 \012 \
126 \015 \011 \013 \
128 #endif
130 /* PTR points to a string value inside a termcap entry.
131 Copy that value, processing \ and ^ abbreviations,
132 into the block that *AREA points to,
133 or to newly allocated storage if AREA is NULL.
134 Return the address to which we copied the value,
135 or NULL if PTR is NULL. */
137 static char *
138 tgetst1 (char *ptr, char **area)
140 register char *p, *r;
141 register int c;
142 register int size;
143 char *ret;
144 register int c1;
146 if (!ptr)
147 return NULL;
149 /* `ret' gets address of where to store the string. */
150 if (!area)
152 /* Compute size of block needed (may overestimate). */
153 p = ptr;
154 while ((c = *p++) && c != ':' && c != '\n')
156 ret = (char *) xmalloc (p - ptr + 1);
158 else
159 ret = *area;
161 /* Copy the string value, stopping at null or colon.
162 Also process ^ and \ abbreviations. */
163 p = ptr;
164 r = ret;
165 while ((c = *p++) && c != ':' && c != '\n')
167 if (c == '^')
169 c = *p++;
170 if (c == '?')
171 c = 0177;
172 else
173 c &= 037;
175 else if (c == '\\')
177 c = *p++;
178 if (c >= '0' && c <= '7')
180 c -= '0';
181 size = 0;
183 while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
185 c *= 8;
186 c += c1 - '0';
187 p++;
190 #ifdef IS_EBCDIC_HOST
191 else if (c >= 0200 && c < 0360)
193 c1 = esctab[(c & ~0100) - 0200];
194 if (c1 != ' ')
195 c = c1;
197 #else
198 else if (c >= 0100 && c < 0200)
200 c1 = esctab[(c & ~040) - 0100];
201 if (c1 != ' ')
202 c = c1;
204 #endif
206 *r++ = c;
209 /* Sometimes entries have "%pN" which means use parameter N in the
210 next %-substitution. If all such N are continuous in the range
211 [1,9] we can remove each "%pN" because they are redundant, thus
212 reducing bandwidth requirements. True, Emacs is well beyond the
213 days of 150baud teletypes, but some of its users aren't much so.
215 This pass could probably be integrated into the one above but
216 abbreviation expansion makes that effort a little more hairy than
217 its worth; this is cleaner. */
219 register int last_p_param = 0;
220 int remove_p_params = 1;
221 struct { char *beg; int len; } cut[11];
223 for (cut[0].beg = p = ret; p < r - 3; p++)
225 if (!remove_p_params)
226 break;
227 if (*p == '%' && *(p + 1) == 'p')
229 if (*(p + 2) - '0' == 1 + last_p_param)
231 cut[last_p_param].len = p - cut[last_p_param].beg;
232 last_p_param++;
233 p += 3;
234 cut[last_p_param].beg = p;
236 else /* not continuous: bail */
237 remove_p_params = 0;
238 if (last_p_param > 10) /* too many: bail */
239 remove_p_params = 0;
242 if (remove_p_params && last_p_param)
244 register int i;
245 char *wp;
247 cut[last_p_param].len = r - cut[last_p_param].beg;
248 for (i = 0, wp = ret; i <= last_p_param; wp += cut[i++].len)
249 memcpy (wp, cut[i].beg, cut[i].len);
250 r = wp;
254 *r = '\0';
255 /* Update *AREA. */
256 if (area)
257 *area = r + 1;
258 return ret;
261 /* Outputting a string with padding. */
263 char PC;
265 void
266 tputs (register char *str, int nlines, register int (*outfun) (/* ??? */))
268 register int padcount = 0;
269 register int speed;
271 speed = baud_rate;
272 /* For quite high speeds, convert to the smaller
273 units to avoid overflow. */
274 if (speed > 10000)
275 speed = - speed / 100;
277 if (!str)
278 return;
280 while (*str >= '0' && *str <= '9')
282 padcount += *str++ - '0';
283 padcount *= 10;
285 if (*str == '.')
287 str++;
288 padcount += *str++ - '0';
290 if (*str == '*')
292 str++;
293 padcount *= nlines;
295 while (*str)
296 (*outfun) (*str++);
298 /* PADCOUNT is now in units of tenths of msec.
299 SPEED is measured in characters per 10 seconds
300 or in characters per .1 seconds (if negative).
301 We use the smaller units for larger speeds to avoid overflow. */
302 padcount *= speed;
303 padcount += 500;
304 padcount /= 1000;
305 if (speed < 0)
306 padcount = -padcount;
307 else
309 padcount += 50;
310 padcount /= 100;
313 while (padcount-- > 0)
314 (*outfun) (PC);
317 /* Finding the termcap entry in the termcap data base. */
319 struct termcap_buffer
321 char *beg;
322 int size;
323 char *ptr;
324 int ateof;
325 int full;
328 /* Forward declarations of static functions. */
330 static int scan_file (char *str, int fd, register struct termcap_buffer *bufp);
331 static char *gobble_line (int fd, register struct termcap_buffer *bufp, char *append_end);
332 static int compare_contin (register char *str1, register char *str2);
333 static int name_match (char *line, char *name);
335 #ifdef MSDOS /* MW, May 1993 */
336 static int
337 valid_filename_p (fn)
338 char *fn;
340 return *fn == '/' || fn[1] == ':';
342 #else
343 #define valid_filename_p(fn) (*(fn) == '/')
344 #endif
346 /* Find the termcap entry data for terminal type NAME
347 and store it in the block that BP points to.
348 Record its address for future use.
350 If BP is null, space is dynamically allocated.
352 Return -1 if there is some difficulty accessing the data base
353 of terminal types,
354 0 if the data base is accessible but the type NAME is not defined
355 in it, and some other value otherwise. */
358 tgetent (char *bp, char *name)
360 register char *termcap_name;
361 register int fd;
362 struct termcap_buffer buf;
363 register char *bp1;
364 char *tc_search_point;
365 char *term;
366 int malloc_size = 0;
367 register int c;
368 char *tcenv = NULL; /* TERMCAP value, if it contains :tc=. */
369 char *indirect = NULL; /* Terminal type in :tc= in TERMCAP value. */
370 int filep;
372 #ifdef INTERNAL_TERMINAL
373 /* For the internal terminal we don't want to read any termcap file,
374 so fake it. */
375 if (!strcmp (name, "internal"))
377 term = INTERNAL_TERMINAL;
378 if (!bp)
380 malloc_size = 1 + strlen (term);
381 bp = (char *) xmalloc (malloc_size);
383 strcpy (bp, term);
384 goto ret;
386 #endif /* INTERNAL_TERMINAL */
388 /* For compatibility with programs like `less' that want to
389 put data in the termcap buffer themselves as a fallback. */
390 if (bp)
391 term_entry = bp;
393 termcap_name = getenv ("TERMCAP");
394 if (termcap_name && *termcap_name == '\0')
395 termcap_name = NULL;
396 #if defined (MSDOS) && !defined (TEST)
397 if (termcap_name && (*termcap_name == '\\'
398 || *termcap_name == '/'
399 || termcap_name[1] == ':'))
400 dostounix_filename(termcap_name);
401 #endif
403 filep = termcap_name && valid_filename_p (termcap_name);
405 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
406 it is a file name to use instead of /etc/termcap.
407 If it is non-null and does not start with /,
408 it is the entry itself, but only if
409 the name the caller requested matches the TERM variable. */
411 if (termcap_name && !filep && !strcmp (name, getenv ("TERM")))
413 indirect = tgetst1 (find_capability (termcap_name, "tc"), (char **) 0);
414 if (!indirect)
416 if (!bp)
417 bp = termcap_name;
418 else
419 strcpy (bp, termcap_name);
420 goto ret;
422 else
423 { /* It has tc=. Need to read /etc/termcap. */
424 tcenv = termcap_name;
425 termcap_name = NULL;
429 if (!termcap_name || !filep)
430 termcap_name = TERMCAP_FILE;
432 /* Here we know we must search a file and termcap_name has its name. */
434 #ifdef MSDOS
435 fd = open (termcap_name, O_RDONLY|O_TEXT, 0);
436 #else
437 fd = open (termcap_name, O_RDONLY, 0);
438 #endif
439 if (fd < 0)
440 return -1;
442 buf.size = BUFSIZE;
443 /* Add 1 to size to ensure room for terminating null. */
444 buf.beg = (char *) xmalloc (buf.size + 1);
445 term = indirect ? indirect : name;
447 if (!bp)
449 malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
450 bp = (char *) xmalloc (malloc_size);
452 tc_search_point = bp1 = bp;
454 if (indirect)
455 /* Copy the data from the environment variable. */
457 strcpy (bp, tcenv);
458 bp1 += strlen (tcenv);
461 while (term)
463 /* Scan the file, reading it via buf, till find start of main entry. */
464 if (scan_file (term, fd, &buf) == 0)
466 close (fd);
467 free (buf.beg);
468 if (malloc_size)
469 free (bp);
470 return 0;
473 /* Free old `term' if appropriate. */
474 if (term != name)
475 free (term);
477 /* If BP is malloc'd by us, make sure it is big enough. */
478 if (malloc_size)
480 int offset1 = bp1 - bp, offset2 = tc_search_point - bp;
481 malloc_size = offset1 + buf.size;
482 bp = termcap_name = (char *) xrealloc (bp, malloc_size);
483 bp1 = termcap_name + offset1;
484 tc_search_point = termcap_name + offset2;
487 /* Copy the line of the entry from buf into bp. */
488 termcap_name = buf.ptr;
489 while ((*bp1++ = c = *termcap_name++) && c != '\n')
490 /* Drop out any \ newline sequence. */
491 if (c == '\\' && *termcap_name == '\n')
493 bp1--;
494 termcap_name++;
496 *bp1 = '\0';
498 /* Does this entry refer to another terminal type's entry?
499 If something is found, copy it into heap and null-terminate it. */
500 tc_search_point = find_capability (tc_search_point, "tc");
501 term = tgetst1 (tc_search_point, (char **) 0);
504 close (fd);
505 free (buf.beg);
507 if (malloc_size)
508 bp = (char *) xrealloc (bp, bp1 - bp + 1);
510 ret:
511 term_entry = bp;
512 return 1;
515 /* Given file open on FD and buffer BUFP,
516 scan the file from the beginning until a line is found
517 that starts the entry for terminal type STR.
518 Return 1 if successful, with that line in BUFP,
519 or 0 if no entry is found in the file. */
521 static int
522 scan_file (char *str, int fd, register struct termcap_buffer *bufp)
524 register char *end;
526 bufp->ptr = bufp->beg;
527 bufp->full = 0;
528 bufp->ateof = 0;
529 *bufp->ptr = '\0';
531 lseek (fd, 0L, 0);
533 while (!bufp->ateof)
535 /* Read a line into the buffer. */
536 end = NULL;
539 /* if it is continued, append another line to it,
540 until a non-continued line ends. */
541 end = gobble_line (fd, bufp, end);
543 while (!bufp->ateof && end[-2] == '\\');
545 if (*bufp->ptr != '#'
546 && name_match (bufp->ptr, str))
547 return 1;
549 /* Discard the line just processed. */
550 bufp->ptr = end;
552 return 0;
555 /* Return nonzero if NAME is one of the names specified
556 by termcap entry LINE. */
558 static int
559 name_match (char *line, char *name)
561 register char *tem;
563 if (!compare_contin (line, name))
564 return 1;
565 /* This line starts an entry. Is it the right one? */
566 for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
567 if (*tem == '|' && !compare_contin (tem + 1, name))
568 return 1;
570 return 0;
573 static int
574 compare_contin (register char *str1, register char *str2)
576 register int c1, c2;
577 while (1)
579 c1 = *str1++;
580 c2 = *str2++;
581 while (c1 == '\\' && *str1 == '\n')
583 str1++;
584 while ((c1 = *str1++) == ' ' || c1 == '\t');
586 if (c2 == '\0')
588 /* End of type being looked up. */
589 if (c1 == '|' || c1 == ':')
590 /* If end of name in data base, we win. */
591 return 0;
592 else
593 return 1;
595 else if (c1 != c2)
596 return 1;
600 /* Make sure that the buffer <- BUFP contains a full line
601 of the file open on FD, starting at the place BUFP->ptr
602 points to. Can read more of the file, discard stuff before
603 BUFP->ptr, or make the buffer bigger.
605 Return the pointer to after the newline ending the line,
606 or to the end of the file, if there is no newline to end it.
608 Can also merge on continuation lines. If APPEND_END is
609 non-null, it points past the newline of a line that is
610 continued; we add another line onto it and regard the whole
611 thing as one line. The caller decides when a line is continued. */
613 static char *
614 gobble_line (int fd, register struct termcap_buffer *bufp, char *append_end)
616 register char *end;
617 register int nread;
618 register char *buf = bufp->beg;
619 register char *tem;
621 if (!append_end)
622 append_end = bufp->ptr;
624 while (1)
626 end = append_end;
627 while (*end && *end != '\n') end++;
628 if (*end)
629 break;
630 if (bufp->ateof)
631 return buf + bufp->full;
632 if (bufp->ptr == buf)
634 if (bufp->full == bufp->size)
636 bufp->size *= 2;
637 /* Add 1 to size to ensure room for terminating null. */
638 tem = (char *) xrealloc (buf, bufp->size + 1);
639 bufp->ptr = (bufp->ptr - buf) + tem;
640 append_end = (append_end - buf) + tem;
641 bufp->beg = buf = tem;
644 else
646 append_end -= bufp->ptr - buf;
647 memcpy (buf, bufp->ptr, bufp->full -= bufp->ptr - buf);
648 bufp->ptr = buf;
650 if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
651 bufp->ateof = 1;
652 bufp->full += nread;
653 buf[bufp->full] = '\0';
655 return end + 1;
658 #ifdef TEST
660 #ifdef NULL
661 #undef NULL
662 #endif
664 #include <stdio.h>
666 main (argc, argv)
667 int argc;
668 char **argv;
670 char *term;
671 char *buf;
673 term = argv[1];
674 printf ("TERM: %s\n", term);
676 buf = (char *) tgetent (0, term);
677 if ((int) buf <= 0)
679 printf ("No entry.\n");
680 return 0;
683 printf ("Entry: %s\n", buf);
685 tprint ("cm");
686 tprint ("AL");
688 printf ("co: %d\n", tgetnum ("co"));
689 printf ("am: %d\n", tgetflag ("am"));
692 tprint (cap)
693 char *cap;
695 char *x = tgetstr (cap, 0);
696 register char *y;
698 printf ("%s: ", cap);
699 if (x)
701 for (y = x; *y; y++)
702 if (*y <= ' ' || *y == 0177)
703 printf ("\\%0o", *y);
704 else
705 putchar (*y);
706 free (x);
708 else
709 printf ("none");
710 putchar ('\n');
713 #endif /* TEST */