1 /* Work-alike for termcap, plus extra features.
2 Copyright (C) 1985, 1986, 1993 Free Software Foundation, Inc.
4 This file is part of SXEmacs
6 SXEmacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 SXEmacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 /* Synched up with: Not synched with FSF. */
22 /* config.h may rename various library functions such as malloc. */
25 #include "lisp.h" /* For encapsulated open, close, read */
26 #include "ui/device.h" /* For DEVICE_BAUD_RATE */
39 #endif /* not emacs */
49 /* BUFSIZE is the initial size allocated for the buffer
50 for reading the termcap file.
52 Make it large normally for speed.
53 Make it variable when debugging, so can exercise
54 increasing the space dynamically. */
58 #define BUFSIZE bufsize
67 static void memory_out()
69 write(2, "virtual memory exhausted\n", 25);
73 static char *xmalloc_atomic(size)
76 char *tem = malloc(size);
83 static char *xrealloc(ptr, size)
87 char *tem = realloc(ptr, size);
93 #endif /* not emacs */
95 /* Looking up capabilities in the entry already found. */
97 /* The pointer to the data made by tgetent is left here
98 for tgetnum, tgetflag and tgetstr to find. */
99 static char *term_entry;
101 static const char *tgetst1(const char *ptr, char **area);
103 /* Search entry BP for capability CAP.
104 Return a pointer to the capability (in BP) if found,
107 static const char *find_capability(bp, cap)
112 if (bp[0] == ':' && bp[1] == cap[0]
121 const char *ptr = find_capability(term_entry, cap);
122 if (!ptr || ptr[-1] != '#')
130 const char *ptr = find_capability(term_entry, cap);
131 return 0 != ptr && ptr[-1] == ':';
134 /* Look up a string-valued capability CAP.
135 If AREA is nonzero, it points to a pointer to a block in which
136 to store the string. That pointer is advanced over the space used.
137 If AREA is zero, space is allocated with `malloc'. */
139 const char *tgetstr(cap, area)
143 const char *ptr = find_capability(term_entry, cap);
144 if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
146 return tgetst1(ptr, area);
149 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
150 gives meaning of character following \, or a space if no special meaning.
151 Eight characters per line within the string. */
154 = " \007\010 \033\014 " " \012 " " \015 \011 \013 " " ";
156 /* PTR points to a string value inside a termcap entry.
157 Copy that value, processing \ and ^ abbreviations,
158 into the block that *AREA points to,
159 or to newly allocated storage if AREA is 0. */
161 static const char *tgetst1(ptr, area)
175 /* `ret' gets address of where to store the string. */
177 /* Compute size of block needed (may overestimate). */
179 while ((c = *p++) && c != ':' && c != '\n') ;
180 ret = (char *)xmalloc_atomic(p - ptr + 1);
184 /* Copy the string value, stopping at null or colon.
185 Also process ^ and \ abbreviations. */
188 while ((c = *p++) && c != ':' && c != '\n') {
191 else if (c == '\\') {
193 if (c >= '0' && c <= '7') {
197 while (++size < 3 && (c1 = *p) >= '0'
203 } else if (c >= 0100 && c < 0200) {
204 c1 = esctab[(c & ~040) - 0100];
218 /* Outputting a string with padding. */
225 /* If `ospeed' is 0, we use `tputs_baud_rate' as the actual baud rate. */
229 /* Actual baud rate if positive;
230 - baud rate / 100 if negative. */
232 static short speeds[] = {
233 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
234 -18, -24, -48, -96, -192, -288, -384, -576, -1152
237 void tputs(string, nlines, outfun)
240 void (*outfun) (int);
246 speed = DEVICE_BAUD_RATE(XDEVICE(Fselected_device(Qnil)));
249 speed = tputs_baud_rate;
251 speed = speeds[ospeed];
254 if (string == (char *)0)
257 while (isdigit(*(const unsigned char *)string)) {
258 padcount += *string++ - '0';
261 if (*string == '.') {
263 padcount += *string++ - '0';
265 if (*string == '*') {
270 (*outfun) (*string++);
272 /* padcount is now in units of tenths of msec. */
273 padcount *= speeds[ospeed];
276 if (speeds[ospeed] < 0)
277 padcount = -padcount;
283 while (padcount-- > 0)
287 /* Finding the termcap entry in the termcap data base. */
297 /* Forward declarations of static functions. */
299 static int scan_file();
300 static char *gobble_line();
301 static int compare_contin();
302 static int name_match();
304 /* Find the termcap entry data for terminal type NAME
305 and store it in the block that BP points to.
306 Record its address for future use.
308 If BP is zero, space is dynamically allocated. */
310 int tgetent(bp, name)
322 char *tcenv; /* TERMCAP value, if it contains :tc=. */
323 const char *indirect = 0; /* Terminal type in :tc= in TERMCAP value. */
325 tem = getenv("TERMCAP");
326 if (tem && *tem == 0)
329 /* If tem is non-null and starts with / (in the un*x case, that is),
330 it is a file name to use instead of /etc/termcap.
331 If it is non-null and does not start with /,
332 it is the entry itself, but only if
333 the name the caller requested matches the TERM variable. */
335 if (tem && !IS_DIRECTORY_SEP(*tem) && !strcmp(name, getenv("TERM"))) {
336 indirect = tgetst1(find_capability(tem, "tc"), 0);
343 } else { /* We will need to read /etc/termcap. */
348 indirect = (char *)0;
351 tem = "/etc/termcap";
353 /* Here we know we must search a file and tem has its name. */
355 fd = open(tem, 0, 0);
360 /* Add 1 to size to ensure room for terminating null. */
361 buf.beg = (char *)xmalloc_atomic(buf.size + 1);
362 term = indirect ? indirect : name;
365 malloc_size = indirect ? strlen(tcenv) + 1 : buf.size;
366 bp = (char *)xmalloc_atomic(malloc_size);
371 /* Copy the data from the environment variable. */
374 bp1 += strlen(tcenv);
378 /* Scan the file, reading it via buf, till find start of main entry. */
379 if (scan_file(term, fd, &buf) == 0)
382 /* Free old `term' if appropriate. */
386 /* If BP is malloc'd by us, make sure it is big enough. */
388 malloc_size = bp1 - bp + buf.size;
389 tem = (char *)xrealloc(bp, malloc_size);
396 /* Copy the line of the entry from buf into bp. */
398 while ((*bp1++ = c = *tem++) && c != '\n')
399 /* Drop out any \ newline sequence. */
400 if (c == '\\' && *tem == '\n') {
406 /* Does this entry refer to another terminal type's entry?
407 If something is found, copy it into heap and null-terminate it. */
408 term = tgetst1(find_capability(bp2, "tc"), 0);
415 bp = (char *)xrealloc(bp, bp1 - bp + 1);
421 /* #### yuck, why the hell are we casting a pointer to an int? */
422 return (int)(long)bp;
426 /* Given file open on FD and buffer BUFP,
427 scan the file from the beginning until a line is found
428 that starts the entry for terminal type STRING.
429 Returns 1 if successful, with that line in BUFP,
430 or returns 0 if no entry found in the file. */
432 static int scan_file(string, fd, bufp)
439 bufp->ptr = bufp->beg;
446 while (!bufp->ateof) {
447 /* Read a line into the buffer. */
450 /* if it is continued, append another line to it,
451 until a non-continued line ends. */
452 end = gobble_line(fd, bufp, end);
454 while (!bufp->ateof && end[-2] == '\\');
456 if (*bufp->ptr != '#' && name_match(bufp->ptr, string))
459 /* Discard the line just processed. */
465 /* Return nonzero if NAME is one of the names specified
466 by termcap entry LINE. */
468 static int name_match(line, name)
473 if (!compare_contin(line, name))
475 /* This line starts an entry. Is it the right one? */
476 for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
477 if (*tem == '|' && !compare_contin(tem + 1, name))
483 static int compare_contin(str1, str2)
490 while (c1 == '\\' && *str1 == '\n') {
492 while ((c1 = *str1++) == ' ' || c1 == '\t') ;
495 /* End of type being looked up. */
496 if (c1 == '|' || c1 == ':')
497 /* If end of name in data base, we win. */
506 /* Make sure that the buffer <- BUFP contains a full line
507 of the file open on FD, starting at the place BUFP->ptr
508 points to. Can read more of the file, discard stuff before
509 BUFP->ptr, or make the buffer bigger.
511 Returns the pointer to after the newline ending the line,
512 or to the end of the file, if there is no newline to end it.
514 Can also merge on continuation lines. If APPEND_END is
515 nonzero, it points past the newline of a line that is
516 continued; we add another line onto it and regard the whole
517 thing as one line. The caller decides when a line is continued. */
519 static char *gobble_line(fd, bufp, append_end)
526 char *buf = bufp->beg;
530 append_end = bufp->ptr;
534 while (*end && *end != '\n')
539 return buf + bufp->full;
540 if (bufp->ptr == buf) {
541 if (bufp->full == bufp->size) {
543 /* Add 1 to size to ensure room for terminating null. */
544 tem = (char *)xrealloc(buf, bufp->size + 1);
545 bufp->ptr = (bufp->ptr - buf) + tem;
546 append_end = (append_end - buf) + tem;
547 bufp->beg = buf = tem;
550 append_end -= bufp->ptr - buf;
551 memcpy(buf, bufp->ptr, bufp->full -= bufp->ptr - buf);
556 read(fd, buf + bufp->full, bufp->size - bufp->full)))
576 printf("TERM: %s\n", term);
578 buf = (char *)tgetent(0, term);
580 printf("No entry.\n");
584 printf("Entry: %s\n", buf);
589 printf("co: %d\n", tgetnum("co"));
590 printf("am: %d\n", tgetflag("am"));
596 char *x = tgetstr(cap, 0);
602 if (*y <= ' ' || *y == 0177)