2 * termcap.c 1.1 20/7/87 agc Joypace Ltd
4 * Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
5 * This file may be freely distributed provided that this notice
8 * A public domain implementation of the termcap(3) routines.
10 * Made fully functional by Ceriel J.H. Jacobs.
13 * - does not check termcap entry sizes
16 /* $Id: termcap.c,v 1.3 1994/06/24 11:45:47 ceriel Exp $ */
24 #define ISSPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
25 #define ISDIGIT(x) ((x) >= '0' && (x) <= '9')
27 short ospeed; /* output speed */
28 char PC; /* padding character */
29 char *BC; /* back cursor movement */
30 char *UP; /* up cursor movement */
32 static const char *capab; /* the capability itself */
33 static int check_for_tc(void);
34 static int match_name(const char *buf, const char *name);
37 * tgetent - get the termcap entry for terminal name, and put it
38 * in bp (which must be an array of 1024 chars). Returns 1 if
39 * termcap entry found, 0 if not found, and -1 if file not found.
42 tgetent(char *bp, const char *name)
50 if ((file = getenv("TERMCAP")) != (char *) NULL) {
52 (cp = getenv("TERM")) != NULL && strcmp(name, cp) == 0) {
53 (void) strcpy(bp, file);
56 else file = "/etc/termcap";
58 file = "/etc/termcap";
59 if ((fp = fopen(file, "r")) == (FILE *) NULL)
61 while (fgets(buf, 1024, fp) != NULL) {
62 if (buf[0] == '#') continue;
63 while (*(cp = &buf[strlen(buf) - 2]) == '\\')
64 if (fgets(cp, 1024, fp) == NULL)
66 if (match_name(buf, name)) {
69 return(check_for_tc());
77 * Compare the terminal name with each termcap entry name; Return 1 if a
81 match_name(const char *buf, const char *name)
83 register const char *tp = buf;
84 register const char *np;
87 for (np = name; *np && *tp == *np; np++, tp++) { }
88 if (*np == 0 && (*tp == '|' || *tp == ':' || *tp == 0))
90 while (*tp != 0 && *tp != '|' && *tp != ':') tp++;
91 if (*tp++ != '|') return (0);
96 * Handle tc= definitions recursively.
101 static int count = 0;
102 const char *savcapab = capab;
104 char terminalname[128];
105 register char *p = (char *)capab + strlen(capab) - 2, *q;
108 if (--p < (char *)capab)
109 return(0); /* no : in termcap entry */
110 if (p[1] != 't' || p[2] != 'c')
112 if (count > 16) return(0); /* recursion in tc= definitions */
114 strcpy(terminalname, &p[4]);
116 while (*q && *q != ':') q++;
118 if (tgetent(buf, terminalname) != 1) {
123 for (q = buf; *q && *q != ':'; q++) { }
130 * tgetnum - get the numeric terminal capability corresponding
131 * to id. Returns the value, -1 if invalid.
134 tgetnum(const char *id)
139 if ((cp = capab) == NULL || id == NULL)
147 if (strncmp(cp, id, CAPABLEN) == 0) {
148 while (*cp && *cp != ':' && *cp != '#')
152 for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++)
153 ret = ret * 10 + *cp - '0';
156 while (*cp && *cp != ':')
163 * tgetflag - get the boolean flag corresponding to id. Returns -1
164 * if invalid, 0 if the flag is not in termcap entry, or 1 if it is
168 tgetflag(const char *id)
172 if ((cp = capab) == NULL || id == NULL)
180 if (strncmp(cp, id, CAPABLEN) == 0)
182 while (*cp && *cp != ':')
189 * tgetstr - get the string capability corresponding to id and place
190 * it in area (advancing area at same time). Expand escape sequences
191 * etc. Returns the string, or NULL if it can't do it.
194 tgetstr(const char *id, char ** const area)
200 if ((cp = capab) == NULL || id == NULL)
208 if (strncmp(cp, id, CAPABLEN) == 0) {
209 while (*cp && *cp != ':' && *cp != '=')
213 for (ret = *area, cp++; *cp && *cp != ':' ; (*area)++, cp++)
216 **area = *++cp - 'A' + 1;
242 for (i=0 ; *cp && ISDIGIT(*cp) ; cp++)
243 i = i * 8 + *cp - '0';
259 while (*cp && *cp != ':')
266 * tgoto - given the cursor motion string cm, make up the string
267 * for the cursor to go to (destcol, destline), and return the string.
268 * Returns "OOPS" if something's gone wrong, or the string otherwise.
271 tgoto(const char *cm, int destcol, int destline)
281 for (rp = ret ; *cm ; cm++) {
296 if (*cm == '+') *dp = *dp + *++cm;
303 /* filter these out */
304 if (dp == &destcol || swapped || UP) {
305 strcat(added, dp == &destcol || swapped ?
315 dp = (dp == &destline) ? &destcol : NULL;
323 swapped = 1 - swapped;
343 *dp = 16 * (*dp / 10) + *dp % 10;
349 *dp = *dp - 2 * (*dp % 16);
358 dp = (dp == &destline) ? &destcol : NULL;
360 *rp++ = '0' + numval / 100;
362 else if (*cm == '3') {
366 *rp++ = '0' + ((numval%100)/10);
368 else if (*cm == '3' || *cm == '2') {
371 *rp++ = '0' + (numval%10);
384 static int tens_of_ms_p_char[] = { /* index as returned by gtty */
385 /* assume 10 bits per char */
386 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 2
389 * tputs - put the string cp out onto the terminal, using the function
390 * outc. Also handle padding.
393 tputs(register const char *cp, int affcnt, int (*outc)(int))
398 while (ISDIGIT(*cp)) {
399 delay = delay * 10 + (*cp++ - '0');
405 delay += *cp++ - '0';
407 while (ISDIGIT(*cp)) cp++;
417 ospeed < (sizeof tens_of_ms_p_char / sizeof tens_of_ms_p_char[0])) {
418 delay = (delay + tens_of_ms_p_char[ospeed] - 1) /
419 tens_of_ms_p_char[ospeed];
420 while (delay--) (*outc)(PC);
426 * That's all, folks...