1c80476e4SDavid E. O'Brien /*
2c80476e4SDavid E. O'Brien * termcap.c 1.1 20/7/87 agc Joypace Ltd
3c80476e4SDavid E. O'Brien *
4c80476e4SDavid E. O'Brien * Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
5c80476e4SDavid E. O'Brien * This file may be freely distributed provided that this notice
6c80476e4SDavid E. O'Brien * remains attached.
7c80476e4SDavid E. O'Brien *
8c80476e4SDavid E. O'Brien * A public domain implementation of the termcap(3) routines.
9c80476e4SDavid E. O'Brien */
10c80476e4SDavid E. O'Brien #include "sh.h"
11*cc698b49SBrooks Davis
129ccc37e3SMark Peek #if defined(_VMS_POSIX) || defined(_OSD_POSIX) || defined(__ANDROID__)
13c80476e4SDavid E. O'Brien /* efth 1988-Apr-29
14c80476e4SDavid E. O'Brien
15c80476e4SDavid E. O'Brien - Correct when TERM != name and TERMCAP is defined [tgetent]
16c80476e4SDavid E. O'Brien - Correct the comparison for the terminal name [tgetent]
17c80476e4SDavid E. O'Brien - Correct the value of ^x escapes [tgetstr]
18c80476e4SDavid E. O'Brien - Added %r to reverse row/column [tgoto]
19c80476e4SDavid E. O'Brien
20c80476e4SDavid E. O'Brien Paul Gillingwater <paul@actrix.gen.nz> July 1992
21c80476e4SDavid E. O'Brien - Modified to allow terminal aliases in termcap file
22c80476e4SDavid E. O'Brien - Uses TERMCAP environment variable for file only
23c80476e4SDavid E. O'Brien */
24c80476e4SDavid E. O'Brien
25c80476e4SDavid E. O'Brien #include <stdio.h>
26c80476e4SDavid E. O'Brien #include <string.h>
27c80476e4SDavid E. O'Brien
28c80476e4SDavid E. O'Brien #define CAPABLEN 2
29c80476e4SDavid E. O'Brien
30c80476e4SDavid E. O'Brien #define ISSPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
31c80476e4SDavid E. O'Brien #define ISDIGIT(x) ((x) >= '0' && (x) <= '9')
32c80476e4SDavid E. O'Brien
33c80476e4SDavid E. O'Brien char *capab; /* the capability itself */
34c80476e4SDavid E. O'Brien
35c80476e4SDavid E. O'Brien extern char *getenv(); /* new, improved getenv */
3623338178SMark Peek #ifndef fopen
37c80476e4SDavid E. O'Brien extern FILE *fopen(); /* old fopen */
3823338178SMark Peek #endif
39c80476e4SDavid E. O'Brien
40c80476e4SDavid E. O'Brien /*
41c80476e4SDavid E. O'Brien * tgetent - get the termcap entry for terminal name, and put it
42c80476e4SDavid E. O'Brien * in bp (which must be an array of 1024 chars). Returns 1 if
43c80476e4SDavid E. O'Brien * termcap entry found, 0 if not found, and -1 if file not found.
44c80476e4SDavid E. O'Brien */
45c80476e4SDavid E. O'Brien int
tgetent(char * bp,char * name)4645e5710bSMark Peek tgetent(char *bp, char *name)
47c80476e4SDavid E. O'Brien {
489ccc37e3SMark Peek #ifdef __ANDROID__
499ccc37e3SMark Peek /* Use static termcap entry since termcap file usually doesn't exist. */
509ccc37e3SMark Peek capab = bp;
519ccc37e3SMark Peek strcpy(bp,
529ccc37e3SMark Peek "linux|linux console:"
539ccc37e3SMark Peek ":am:eo:mi:ms:xn:xo:"
549ccc37e3SMark Peek ":it#8:"
559ccc37e3SMark Peek ":AL=\\E[%dL:DC=\\E[%dP:DL=\\E[%dM:IC=\\E[%d@:K2=\\E[G:al=\\E[L:"
569ccc37e3SMark Peek ":bl=^G:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:cr=^M:"
579ccc37e3SMark Peek ":cs=\\E[%i%d;%dr:ct=\\E[3g:dc=\\E[P:dl=\\E[M:do=^J:ec=\\E[%dX:"
589ccc37e3SMark Peek ":ei=\\E[4l:ho=\\E[H:ic=\\E[@:im=\\E[4h:k1=\\E[[A:k2=\\E[[B:"
599ccc37e3SMark Peek ":k3=\\E[[C:k4=\\E[[D:k5=\\E[[E:k6=\\E[17~:k7=\\E[18~:k8=\\E[19~:"
609ccc37e3SMark Peek ":k9=\\E[20~:kD=\\E[3~:kI=\\E[2~:kN=\\E[6~:kP=\\E[5~:kb=\\177:"
619ccc37e3SMark Peek ":kd=\\E[B:kh=\\E[1~:kl=\\E[D:kr=\\E[C:ku=\\E[A:le=^H:mb=\\E[5m:"
629ccc37e3SMark Peek ":md=\\E[1m:me=\\E[0m:mh=\\E[2m:mr=\\E[7m:nd=\\E[C:nw=^M^J:"
639ccc37e3SMark Peek ":rc=\\E8:sc=\\E7:se=\\E[27m:sf=^J:so=\\E[7m:sr=\\EM:st=\\EH:ta=^I:"
649ccc37e3SMark Peek ":ue=\\E[24m:up=\\E[A:us=\\E[4m:vb=200\\E[?5h\\E[?5l:"
659ccc37e3SMark Peek ":ve=\\E[?25h\\E[?0c:vi=\\E[?25l\\E[?1c:vs=\\E[?25h\\E[?0c:"
669ccc37e3SMark Peek );
679ccc37e3SMark Peek return(1);
689ccc37e3SMark Peek #else
69c80476e4SDavid E. O'Brien FILE *fp;
70c80476e4SDavid E. O'Brien char *termfile;
71c80476e4SDavid E. O'Brien char *cp,
72c80476e4SDavid E. O'Brien *ptr, /* temporary pointer */
7345e5710bSMark Peek tmp[1024]; /* buffer for terminal name *//*FIXBUF*/
7445e5710bSMark Peek size_t len = strlen(name);
75c80476e4SDavid E. O'Brien
76c80476e4SDavid E. O'Brien capab = bp;
77c80476e4SDavid E. O'Brien
78c80476e4SDavid E. O'Brien /* Use TERMCAP to override default. */
79c80476e4SDavid E. O'Brien
80c80476e4SDavid E. O'Brien termfile = getenv("TERMCAP");
81c80476e4SDavid E. O'Brien if (termfile == NULL ) termfile = "/etc/termcap";
82c80476e4SDavid E. O'Brien
83c80476e4SDavid E. O'Brien if ((fp = fopen(termfile, "r")) == (FILE *) NULL) {
84c80476e4SDavid E. O'Brien fprintf(stderr, CGETS(31, 1,
85c80476e4SDavid E. O'Brien "Can't open TERMCAP: [%s]\n"), termfile);
86c80476e4SDavid E. O'Brien fprintf(stderr, CGETS(31, 2, "Can't open %s.\n"), termfile);
87c80476e4SDavid E. O'Brien sleep(1);
88c80476e4SDavid E. O'Brien return(-1);
89c80476e4SDavid E. O'Brien }
90c80476e4SDavid E. O'Brien
91c80476e4SDavid E. O'Brien while (fgets(bp, 1024, fp) != NULL) {
92c80476e4SDavid E. O'Brien /* Any line starting with # or NL is skipped as a comment */
93c80476e4SDavid E. O'Brien if ((*bp == '#') || (*bp == '\n')) continue;
94c80476e4SDavid E. O'Brien
95c80476e4SDavid E. O'Brien /* Look for lines which end with two backslashes,
96c80476e4SDavid E. O'Brien and then append the next line. */
97c80476e4SDavid E. O'Brien while (*(cp = &bp[strlen(bp) - 2]) == '\\')
98c80476e4SDavid E. O'Brien fgets(cp, 1024, fp);
99c80476e4SDavid E. O'Brien
100c80476e4SDavid E. O'Brien /* Skip over any spaces or tabs */
101c80476e4SDavid E. O'Brien for (++cp ; ISSPACE(*cp) ; cp++);
102c80476e4SDavid E. O'Brien
103c80476e4SDavid E. O'Brien /* Make sure "name" matches exactly (efth) */
104c80476e4SDavid E. O'Brien
105c80476e4SDavid E. O'Brien /* Here we might want to look at any aliases as well. We'll use
106c80476e4SDavid E. O'Brien sscanf to look at aliases. These are delimited by '|'. */
107c80476e4SDavid E. O'Brien
108c80476e4SDavid E. O'Brien sscanf(bp,"%[^|]",tmp);
109c80476e4SDavid E. O'Brien if (strncmp(name, tmp, len) == 0) {
110c80476e4SDavid E. O'Brien fclose(fp);
111c80476e4SDavid E. O'Brien #ifdef DEBUG
112c80476e4SDavid E. O'Brien fprintf(stderr, CGETS(31, 3, "Found %s in %s.\n"), name, termfile);
113c80476e4SDavid E. O'Brien sleep(1);
114c80476e4SDavid E. O'Brien #endif /* DEBUG */
115c80476e4SDavid E. O'Brien return(1);
116c80476e4SDavid E. O'Brien }
117c80476e4SDavid E. O'Brien ptr = bp;
118c80476e4SDavid E. O'Brien while ((ptr = strchr(ptr,'|')) != NULL) {
119c80476e4SDavid E. O'Brien ptr++;
120c80476e4SDavid E. O'Brien if (strchr(ptr,'|') == NULL) break;
121c80476e4SDavid E. O'Brien sscanf(ptr,"%[^|]",tmp);
122c80476e4SDavid E. O'Brien if (strncmp(name, tmp, len) == 0) {
123c80476e4SDavid E. O'Brien fclose(fp);
124c80476e4SDavid E. O'Brien #ifdef DEBUG
125c80476e4SDavid E. O'Brien fprintf(stderr,CGETS(31, 3, "Found %s in %s.\n"), name, termfile);
126c80476e4SDavid E. O'Brien sleep(1);
127c80476e4SDavid E. O'Brien #endif /* DEBUG */
128c80476e4SDavid E. O'Brien return(1);
129c80476e4SDavid E. O'Brien }
130c80476e4SDavid E. O'Brien }
131c80476e4SDavid E. O'Brien }
132c80476e4SDavid E. O'Brien /* If we get here, then we haven't found a match. */
133c80476e4SDavid E. O'Brien fclose(fp);
134c80476e4SDavid E. O'Brien #ifdef DEBUG
135c80476e4SDavid E. O'Brien fprintf(stderr,CGETS(31, 4, "No match found for %s in file %s\n"),
136c80476e4SDavid E. O'Brien name, termfile);
137c80476e4SDavid E. O'Brien sleep(1);
138c80476e4SDavid E. O'Brien #endif /* DEBUG */
139c80476e4SDavid E. O'Brien return(0);
1409ccc37e3SMark Peek #endif /* ANDROID */
141c80476e4SDavid E. O'Brien }
142c80476e4SDavid E. O'Brien
143c80476e4SDavid E. O'Brien /*
144c80476e4SDavid E. O'Brien * tgetnum - get the numeric terminal capability corresponding
145c80476e4SDavid E. O'Brien * to id. Returns the value, -1 if invalid.
146c80476e4SDavid E. O'Brien */
147c80476e4SDavid E. O'Brien int
tgetnum(char * id)14845e5710bSMark Peek tgetnum(char *id)
149c80476e4SDavid E. O'Brien {
150c80476e4SDavid E. O'Brien char *cp;
151c80476e4SDavid E. O'Brien int ret;
152c80476e4SDavid E. O'Brien
153c80476e4SDavid E. O'Brien if ((cp = capab) == NULL || id == NULL)
154c80476e4SDavid E. O'Brien return(-1);
155c80476e4SDavid E. O'Brien while (*++cp != ':')
156c80476e4SDavid E. O'Brien ;
157c80476e4SDavid E. O'Brien for (++cp ; *cp ; cp++) {
158c80476e4SDavid E. O'Brien while (ISSPACE(*cp))
159c80476e4SDavid E. O'Brien cp++;
160c80476e4SDavid E. O'Brien if (strncmp(cp, id, CAPABLEN) == 0) {
161c80476e4SDavid E. O'Brien while (*cp && *cp != ':' && *cp != '#')
162c80476e4SDavid E. O'Brien cp++;
163c80476e4SDavid E. O'Brien if (*cp != '#')
164c80476e4SDavid E. O'Brien return(-1);
165c80476e4SDavid E. O'Brien for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++)
166c80476e4SDavid E. O'Brien ret = ret * 10 + *cp - '0';
167c80476e4SDavid E. O'Brien return(ret);
168c80476e4SDavid E. O'Brien }
169c80476e4SDavid E. O'Brien while (*cp && *cp != ':')
170c80476e4SDavid E. O'Brien cp++;
171c80476e4SDavid E. O'Brien }
172c80476e4SDavid E. O'Brien return(-1);
173c80476e4SDavid E. O'Brien }
174c80476e4SDavid E. O'Brien
175c80476e4SDavid E. O'Brien /*
176c80476e4SDavid E. O'Brien * tgetflag - get the boolean flag corresponding to id. Returns -1
177c80476e4SDavid E. O'Brien * if invalid, 0 if the flag is not in termcap entry, or 1 if it is
178c80476e4SDavid E. O'Brien * present.
179c80476e4SDavid E. O'Brien */
180c80476e4SDavid E. O'Brien int
tgetflag(char * id)18145e5710bSMark Peek tgetflag(char *id)
182c80476e4SDavid E. O'Brien {
183c80476e4SDavid E. O'Brien char *cp;
184c80476e4SDavid E. O'Brien
185c80476e4SDavid E. O'Brien if ((cp = capab) == NULL || id == NULL)
186c80476e4SDavid E. O'Brien return(-1);
187c80476e4SDavid E. O'Brien while (*++cp != ':')
188c80476e4SDavid E. O'Brien ;
189c80476e4SDavid E. O'Brien for (++cp ; *cp ; cp++) {
190c80476e4SDavid E. O'Brien while (ISSPACE(*cp))
191c80476e4SDavid E. O'Brien cp++;
192c80476e4SDavid E. O'Brien if (strncmp(cp, id, CAPABLEN) == 0)
193c80476e4SDavid E. O'Brien return(1);
194c80476e4SDavid E. O'Brien while (*cp && *cp != ':')
195c80476e4SDavid E. O'Brien cp++;
196c80476e4SDavid E. O'Brien }
197c80476e4SDavid E. O'Brien return(0);
198c80476e4SDavid E. O'Brien }
199c80476e4SDavid E. O'Brien
200c80476e4SDavid E. O'Brien /*
201c80476e4SDavid E. O'Brien * tgetstr - get the string capability corresponding to id and place
202c80476e4SDavid E. O'Brien * it in area (advancing area at same time). Expand escape sequences
203c80476e4SDavid E. O'Brien * etc. Returns the string, or NULL if it can't do it.
204c80476e4SDavid E. O'Brien */
205c80476e4SDavid E. O'Brien char *
tgetstr(char * id,char ** area)20645e5710bSMark Peek tgetstr(char *id, char **area)
207c80476e4SDavid E. O'Brien {
208c80476e4SDavid E. O'Brien char *cp;
209c80476e4SDavid E. O'Brien char *ret;
210c80476e4SDavid E. O'Brien int i;
211c80476e4SDavid E. O'Brien
212c80476e4SDavid E. O'Brien if ((cp = capab) == NULL || id == NULL)
213c80476e4SDavid E. O'Brien return(NULL);
214c80476e4SDavid E. O'Brien while (*++cp != ':')
215c80476e4SDavid E. O'Brien ;
216c80476e4SDavid E. O'Brien for (++cp ; *cp ; cp++) {
217c80476e4SDavid E. O'Brien while (ISSPACE(*cp))
218c80476e4SDavid E. O'Brien cp++;
219c80476e4SDavid E. O'Brien if (strncmp(cp, id, CAPABLEN) == 0) {
220c80476e4SDavid E. O'Brien while (*cp && *cp != ':' && *cp != '=')
221c80476e4SDavid E. O'Brien cp++;
222c80476e4SDavid E. O'Brien if (*cp != '=')
223c80476e4SDavid E. O'Brien return(NULL);
224c80476e4SDavid E. O'Brien for (ret = *area, cp++; *cp && *cp != ':' ;
225c80476e4SDavid E. O'Brien (*area)++, cp++)
226c80476e4SDavid E. O'Brien switch(*cp) {
227c80476e4SDavid E. O'Brien case '^' :
228c80476e4SDavid E. O'Brien **area = *++cp - '@'; /* fix (efth)*/
229c80476e4SDavid E. O'Brien break;
230c80476e4SDavid E. O'Brien case '\\' :
231c80476e4SDavid E. O'Brien switch(*++cp) {
232c80476e4SDavid E. O'Brien case 'E' :
233c80476e4SDavid E. O'Brien **area = CTL_ESC('\033');
234c80476e4SDavid E. O'Brien break;
235c80476e4SDavid E. O'Brien case 'n' :
236c80476e4SDavid E. O'Brien **area = '\n';
237c80476e4SDavid E. O'Brien break;
238c80476e4SDavid E. O'Brien case 'r' :
239c80476e4SDavid E. O'Brien **area = '\r';
240c80476e4SDavid E. O'Brien break;
241c80476e4SDavid E. O'Brien case 't' :
242c80476e4SDavid E. O'Brien **area = '\t';
243c80476e4SDavid E. O'Brien break;
244c80476e4SDavid E. O'Brien case 'b' :
245c80476e4SDavid E. O'Brien **area = '\b';
246c80476e4SDavid E. O'Brien break;
247c80476e4SDavid E. O'Brien case 'f' :
248c80476e4SDavid E. O'Brien **area = '\f';
249c80476e4SDavid E. O'Brien break;
250c80476e4SDavid E. O'Brien case '0' :
251c80476e4SDavid E. O'Brien case '1' :
252c80476e4SDavid E. O'Brien case '2' :
253c80476e4SDavid E. O'Brien case '3' :
254c80476e4SDavid E. O'Brien for (i=0 ; *cp && ISDIGIT(*cp) ;
255c80476e4SDavid E. O'Brien cp++)
256c80476e4SDavid E. O'Brien i = i * 8 + *cp - '0';
257c80476e4SDavid E. O'Brien **area = i;
258c80476e4SDavid E. O'Brien cp--;
259c80476e4SDavid E. O'Brien break;
260c80476e4SDavid E. O'Brien case '^' :
261c80476e4SDavid E. O'Brien case '\\' :
262c80476e4SDavid E. O'Brien **area = *cp;
263c80476e4SDavid E. O'Brien break;
264c80476e4SDavid E. O'Brien }
265c80476e4SDavid E. O'Brien break;
266c80476e4SDavid E. O'Brien default :
267c80476e4SDavid E. O'Brien **area = *cp;
268c80476e4SDavid E. O'Brien }
269c80476e4SDavid E. O'Brien *(*area)++ = '\0';
270c80476e4SDavid E. O'Brien return(ret);
271c80476e4SDavid E. O'Brien }
272c80476e4SDavid E. O'Brien while (*cp && *cp != ':')
273c80476e4SDavid E. O'Brien cp++;
274c80476e4SDavid E. O'Brien }
275c80476e4SDavid E. O'Brien return(NULL);
276c80476e4SDavid E. O'Brien }
277c80476e4SDavid E. O'Brien
278c80476e4SDavid E. O'Brien /*
279c80476e4SDavid E. O'Brien * tgoto - given the cursor motion string cm, make up the string
280c80476e4SDavid E. O'Brien * for the cursor to go to (destcol, destline), and return the string.
281c80476e4SDavid E. O'Brien * Returns "OOPS" if something's gone wrong, or the string otherwise.
282c80476e4SDavid E. O'Brien */
283c80476e4SDavid E. O'Brien char *
tgoto(char * cm,int destcol,int destline)28445e5710bSMark Peek tgoto(char *cm, int destcol, int destline)
285c80476e4SDavid E. O'Brien {
28623338178SMark Peek char *rp;
287c80476e4SDavid E. O'Brien static char ret[24];
288c80476e4SDavid E. O'Brien int incr = 0;
289c80476e4SDavid E. O'Brien int argno = 0, numval;
290c80476e4SDavid E. O'Brien
291c80476e4SDavid E. O'Brien for (rp = ret ; *cm ; cm++) {
292c80476e4SDavid E. O'Brien switch(*cm) {
293c80476e4SDavid E. O'Brien case '%' :
294c80476e4SDavid E. O'Brien switch(*++cm) {
295c80476e4SDavid E. O'Brien case '+' :
296c80476e4SDavid E. O'Brien numval = (argno == 0 ? destline : destcol);
297c80476e4SDavid E. O'Brien argno = 1 - argno;
298c80476e4SDavid E. O'Brien *rp++ = numval + incr + *++cm;
299c80476e4SDavid E. O'Brien break;
300c80476e4SDavid E. O'Brien
301c80476e4SDavid E. O'Brien case '%' :
302c80476e4SDavid E. O'Brien *rp++ = '%';
303c80476e4SDavid E. O'Brien break;
304c80476e4SDavid E. O'Brien
305c80476e4SDavid E. O'Brien case 'i' :
306c80476e4SDavid E. O'Brien incr = 1;
307c80476e4SDavid E. O'Brien break;
308c80476e4SDavid E. O'Brien
309c80476e4SDavid E. O'Brien case 'd' :
310c80476e4SDavid E. O'Brien numval = (argno == 0 ? destline : destcol);
311c80476e4SDavid E. O'Brien numval += incr;
312c80476e4SDavid E. O'Brien argno = 1 - argno;
313c80476e4SDavid E. O'Brien *rp++ = '0' + (numval/10);
314c80476e4SDavid E. O'Brien *rp++ = '0' + (numval%10);
315c80476e4SDavid E. O'Brien break;
316c80476e4SDavid E. O'Brien
317c80476e4SDavid E. O'Brien case 'r' :
318c80476e4SDavid E. O'Brien argno = 1;
319c80476e4SDavid E. O'Brien break;
320c80476e4SDavid E. O'Brien }
321c80476e4SDavid E. O'Brien
322c80476e4SDavid E. O'Brien break;
323c80476e4SDavid E. O'Brien default :
324c80476e4SDavid E. O'Brien *rp++ = *cm;
325c80476e4SDavid E. O'Brien }
326c80476e4SDavid E. O'Brien }
327c80476e4SDavid E. O'Brien *rp = '\0';
328c80476e4SDavid E. O'Brien return(ret);
329c80476e4SDavid E. O'Brien }
330c80476e4SDavid E. O'Brien
331c80476e4SDavid E. O'Brien /*
332c80476e4SDavid E. O'Brien * tputs - put the string cp out onto the terminal, using the function
333c80476e4SDavid E. O'Brien * outc. This should do padding for the terminal, but I can't find a
334c80476e4SDavid E. O'Brien * terminal that needs padding at the moment...
335c80476e4SDavid E. O'Brien */
336c80476e4SDavid E. O'Brien int
tputs(char * cp,int affcnt,int (* outc)())33745e5710bSMark Peek tputs(char *cp, int affcnt, int (*outc)())
338c80476e4SDavid E. O'Brien {
33923338178SMark Peek unsigned long delay = 0;
34023338178SMark Peek
341c80476e4SDavid E. O'Brien if (cp == NULL)
342c80476e4SDavid E. O'Brien return(1);
343c80476e4SDavid E. O'Brien /* do any padding interpretation - left null for MINIX just now */
34423338178SMark Peek for (delay = 0; *cp && ISDIGIT(*cp) ; cp++)
34523338178SMark Peek delay = delay * 10 + *cp - '0';
346c80476e4SDavid E. O'Brien while (*cp)
347c80476e4SDavid E. O'Brien (*outc)(*cp++);
34823338178SMark Peek #ifdef _OSD_POSIX
34923338178SMark Peek usleep(delay*100); /* strictly spoken, it should be *1000 */
35023338178SMark Peek #endif
351c80476e4SDavid E. O'Brien return(1);
352c80476e4SDavid E. O'Brien }
3533b6eaa7bSAndrey A. Chernov #endif /* _VMS_POSIX || _OSD_POSIX */
354