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 */
41 /* BUFSIZE is the initial size allocated for the buffer
42 for reading the termcap file.
44 Make it large normally for speed.
45 Make it variable when debugging, so can exercise
46 increasing the space dynamically. */
50 #define BUFSIZE bufsize
59 static void memory_out()
61 write(2, "virtual memory exhausted\n", 25);
65 static char *xmalloc_atomic(size)
68 char *tem = malloc(size);
75 static char *xrealloc(ptr, size)
79 char *tem = realloc(ptr, size);
85 #endif /* not emacs */
87 /* Looking up capabilities in the entry already found. */
89 /* The pointer to the data made by tgetent is left here
90 for tgetnum, tgetflag and tgetstr to find. */
91 static char *term_entry;
93 static const char *tgetst1(const char *ptr, char **area);
95 /* Search entry BP for capability CAP.
96 Return a pointer to the capability (in BP) if found,
99 static const char *find_capability(bp, cap)
104 if (bp[0] == ':' && bp[1] == cap[0]
113 const char *ptr = find_capability(term_entry, cap);
114 if (!ptr || ptr[-1] != '#')
122 const char *ptr = find_capability(term_entry, cap);
123 return 0 != ptr && ptr[-1] == ':';
126 /* Look up a string-valued capability CAP.
127 If AREA is nonzero, it points to a pointer to a block in which
128 to store the string. That pointer is advanced over the space used.
129 If AREA is zero, space is allocated with `malloc'. */
131 const char *tgetstr(cap, area)
135 const char *ptr = find_capability(term_entry, cap);
136 if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
138 return tgetst1(ptr, area);
141 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
142 gives meaning of character following \, or a space if no special meaning.
143 Eight characters per line within the string. */
146 = " \007\010 \033\014 " " \012 " " \015 \011 \013 " " ";
148 /* PTR points to a string value inside a termcap entry.
149 Copy that value, processing \ and ^ abbreviations,
150 into the block that *AREA points to,
151 or to newly allocated storage if AREA is 0. */
153 static const char *tgetst1(ptr, area)
167 /* `ret' gets address of where to store the string. */
169 /* Compute size of block needed (may overestimate). */
171 while ((c = *p++) && c != ':' && c != '\n') ;
172 ret = (char *)xmalloc_atomic(p - ptr + 1);
176 /* Copy the string value, stopping at null or colon.
177 Also process ^ and \ abbreviations. */
180 while ((c = *p++) && c != ':' && c != '\n') {
183 else if (c == '\\') {
185 if (c >= '0' && c <= '7') {
189 while (++size < 3 && (c1 = *p) >= '0'
195 } else if (c >= 0100 && c < 0200) {
196 c1 = esctab[(c & ~040) - 0100];
210 /* Outputting a string with padding. */
217 /* If `ospeed' is 0, we use `tputs_baud_rate' as the actual baud rate. */
221 /* Actual baud rate if positive;
222 - baud rate / 100 if negative. */
224 static short speeds[] = {
225 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
226 -18, -24, -48, -96, -192, -288, -384, -576, -1152
229 void tputs(string, nlines, outfun)
232 void (*outfun) (int);
238 speed = DEVICE_BAUD_RATE(XDEVICE(Fselected_device(Qnil)));
241 speed = tputs_baud_rate;
243 speed = speeds[ospeed];
246 if (string == (char *)0)
249 while (isdigit(*(const unsigned char *)string)) {
250 padcount += *string++ - '0';
253 if (*string == '.') {
255 padcount += *string++ - '0';
257 if (*string == '*') {
262 (*outfun) (*string++);
264 /* padcount is now in units of tenths of msec. */
265 padcount *= speeds[ospeed];
268 if (speeds[ospeed] < 0)
269 padcount = -padcount;
275 while (padcount-- > 0)
279 /* Finding the termcap entry in the termcap data base. */
289 /* Forward declarations of static functions. */
291 static int scan_file();
292 static char *gobble_line();
293 static int compare_contin();
294 static int name_match();
296 /* Find the termcap entry data for terminal type NAME
297 and store it in the block that BP points to.
298 Record its address for future use.
300 If BP is zero, space is dynamically allocated. */
302 int tgetent(bp, name)
314 char *tcenv; /* TERMCAP value, if it contains :tc=. */
315 const char *indirect = 0; /* Terminal type in :tc= in TERMCAP value. */
317 tem = getenv("TERMCAP");
318 if (tem && *tem == 0)
321 /* If tem is non-null and starts with / (in the un*x case, that is),
322 it is a file name to use instead of /etc/termcap.
323 If it is non-null and does not start with /,
324 it is the entry itself, but only if
325 the name the caller requested matches the TERM variable. */
327 if (tem && !IS_DIRECTORY_SEP(*tem) && !strcmp(name, getenv("TERM"))) {
328 indirect = tgetst1(find_capability(tem, "tc"), 0);
335 } else { /* We will need to read /etc/termcap. */
340 indirect = (char *)0;
343 tem = "/etc/termcap";
345 /* Here we know we must search a file and tem has its name. */
347 fd = open(tem, 0, 0);
352 /* Add 1 to size to ensure room for terminating null. */
353 buf.beg = (char *)xmalloc_atomic(buf.size + 1);
354 term = indirect ? indirect : name;
357 malloc_size = indirect ? strlen(tcenv) + 1 : buf.size;
358 bp = (char *)xmalloc_atomic(malloc_size);
363 /* Copy the data from the environment variable. */
366 bp1 += strlen(tcenv);
370 /* Scan the file, reading it via buf, till find start of main entry. */
371 if (scan_file(term, fd, &buf) == 0)
374 /* Free old `term' if appropriate. */
378 /* If BP is malloc'd by us, make sure it is big enough. */
380 malloc_size = bp1 - bp + buf.size;
381 tem = (char *)xrealloc(bp, malloc_size);
388 /* Copy the line of the entry from buf into bp. */
390 while ((*bp1++ = c = *tem++) && c != '\n')
391 /* Drop out any \ newline sequence. */
392 if (c == '\\' && *tem == '\n') {
398 /* Does this entry refer to another terminal type's entry?
399 If something is found, copy it into heap and null-terminate it. */
400 term = tgetst1(find_capability(bp2, "tc"), 0);
407 bp = (char *)xrealloc(bp, bp1 - bp + 1);
413 /* #### yuck, why the hell are we casting a pointer to an int? */
414 return (int)(long)bp;
418 /* Given file open on FD and buffer BUFP,
419 scan the file from the beginning until a line is found
420 that starts the entry for terminal type STRING.
421 Returns 1 if successful, with that line in BUFP,
422 or returns 0 if no entry found in the file. */
424 static int scan_file(string, fd, bufp)
431 bufp->ptr = bufp->beg;
438 while (!bufp->ateof) {
439 /* Read a line into the buffer. */
442 /* if it is continued, append another line to it,
443 until a non-continued line ends. */
444 end = gobble_line(fd, bufp, end);
446 while (!bufp->ateof && end[-2] == '\\');
448 if (*bufp->ptr != '#' && name_match(bufp->ptr, string))
451 /* Discard the line just processed. */
457 /* Return nonzero if NAME is one of the names specified
458 by termcap entry LINE. */
460 static int name_match(line, name)
465 if (!compare_contin(line, name))
467 /* This line starts an entry. Is it the right one? */
468 for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
469 if (*tem == '|' && !compare_contin(tem + 1, name))
475 static int compare_contin(str1, str2)
482 while (c1 == '\\' && *str1 == '\n') {
484 while ((c1 = *str1++) == ' ' || c1 == '\t') ;
487 /* End of type being looked up. */
488 if (c1 == '|' || c1 == ':')
489 /* If end of name in data base, we win. */
498 /* Make sure that the buffer <- BUFP contains a full line
499 of the file open on FD, starting at the place BUFP->ptr
500 points to. Can read more of the file, discard stuff before
501 BUFP->ptr, or make the buffer bigger.
503 Returns the pointer to after the newline ending the line,
504 or to the end of the file, if there is no newline to end it.
506 Can also merge on continuation lines. If APPEND_END is
507 nonzero, it points past the newline of a line that is
508 continued; we add another line onto it and regard the whole
509 thing as one line. The caller decides when a line is continued. */
511 static char *gobble_line(fd, bufp, append_end)
518 char *buf = bufp->beg;
522 append_end = bufp->ptr;
526 while (*end && *end != '\n')
531 return buf + bufp->full;
532 if (bufp->ptr == buf) {
533 if (bufp->full == bufp->size) {
535 /* Add 1 to size to ensure room for terminating null. */
536 tem = (char *)xrealloc(buf, bufp->size + 1);
537 bufp->ptr = (bufp->ptr - buf) + tem;
538 append_end = (append_end - buf) + tem;
539 bufp->beg = buf = tem;
542 append_end -= bufp->ptr - buf;
543 memcpy(buf, bufp->ptr, bufp->full -= bufp->ptr - buf);
548 read(fd, buf + bufp->full, bufp->size - bufp->full)))
568 printf("TERM: %s\n", term);
570 buf = (char *)tgetent(0, term);
572 printf("No entry.\n");
576 printf("Entry: %s\n", buf);
581 printf("co: %d\n", tgetnum("co"));
582 printf("am: %d\n", tgetflag("am"));
588 char *x = tgetstr(cap, 0);
594 if (*y <= ' ' || *y == 0177)