xref: /freebsd/contrib/tcsh/vms.termcap.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
1 /* $Header: /p/tcsh/cvsroot/tcsh/vms.termcap.c,v 1.11 2006/03/02 18:46:45 christos Exp $ */
2 /*
3  *	termcap.c	1.1	20/7/87		agc	Joypace Ltd
4  *
5  *	Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
6  *	This file may be freely distributed provided that this notice
7  *	remains attached.
8  *
9  *	A public domain implementation of the termcap(3) routines.
10  */
11 #include "sh.h"
12 RCSID("$tcsh: vms.termcap.c,v 1.11 2006/03/02 18:46:45 christos Exp $")
13 #if defined(_VMS_POSIX) || defined(_OSD_POSIX)
14 /*    efth      1988-Apr-29
15 
16     - Correct when TERM != name and TERMCAP is defined   [tgetent]
17     - Correct the comparison for the terminal name       [tgetent]
18     - Correct the value of ^x escapes                    [tgetstr]
19     - Added %r to reverse row/column			 [tgoto]
20 
21      Paul Gillingwater <paul@actrix.gen.nz> July 1992
22 	- Modified to allow terminal aliases in termcap file
23 	- Uses TERMCAP environment variable for file only
24 */
25 
26 #include	<stdio.h>
27 #include	<string.h>
28 
29 #define CAPABLEN	2
30 
31 #define ISSPACE(c)  ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
32 #define ISDIGIT(x)  ((x) >= '0' && (x) <= '9')
33 
34 char		*capab;		/* the capability itself */
35 
36 extern char	*getenv();	/* new, improved getenv */
37 #ifndef fopen
38 extern FILE	*fopen();	/* old fopen */
39 #endif
40 
41 /*
42  *	tgetent - get the termcap entry for terminal name, and put it
43  *	in bp (which must be an array of 1024 chars). Returns 1 if
44  *	termcap entry found, 0 if not found, and -1 if file not found.
45  */
46 
47 int
48 tgetent(char *bp, char *name)
49 {
50 	FILE	*fp;
51 	char	*termfile;
52 	char	*cp,
53 		*ptr,		/* temporary pointer */
54 		tmp[1024];	/* buffer for terminal name *//*FIXBUF*/
55 	size_t	len = strlen(name);
56 
57 	capab = bp;
58 
59 	/* Use TERMCAP to override default. */
60 
61 	termfile = getenv("TERMCAP");
62 	if (termfile == NULL ) termfile = "/etc/termcap";
63 
64 	if ((fp = fopen(termfile, "r")) == (FILE *) NULL) {
65 		fprintf(stderr, CGETS(31, 1,
66 		        "Can't open TERMCAP: [%s]\n"), termfile);
67 		fprintf(stderr, CGETS(31, 2, "Can't open %s.\n"), termfile);
68 		sleep(1);
69 		return(-1);
70 	}
71 
72 	while (fgets(bp, 1024, fp) != NULL) {
73 		/* Any line starting with # or NL is skipped as a comment */
74 		if ((*bp == '#') || (*bp == '\n')) continue;
75 
76 		/* Look for lines which end with two backslashes,
77 		and then append the next line. */
78 		while (*(cp = &bp[strlen(bp) - 2]) == '\\')
79 			fgets(cp, 1024, fp);
80 
81 		/* Skip over any spaces or tabs */
82 		for (++cp ; ISSPACE(*cp) ; cp++);
83 
84 		/*  Make sure "name" matches exactly  (efth)  */
85 
86 /* Here we might want to look at any aliases as well.  We'll use
87 sscanf to look at aliases.  These are delimited by '|'. */
88 
89 		sscanf(bp,"%[^|]",tmp);
90 		if (strncmp(name, tmp, len) == 0) {
91 			fclose(fp);
92 #ifdef DEBUG
93 	fprintf(stderr, CGETS(31, 3, "Found %s in %s.\n"), name, termfile);
94 	sleep(1);
95 #endif /* DEBUG */
96 			return(1);
97 		}
98 		ptr = bp;
99 		while ((ptr = strchr(ptr,'|')) != NULL) {
100 			ptr++;
101 			if (strchr(ptr,'|') == NULL) break;
102 			sscanf(ptr,"%[^|]",tmp);
103 			if (strncmp(name, tmp, len) == 0) {
104 				fclose(fp);
105 #ifdef DEBUG
106 	fprintf(stderr,CGETS(31, 3, "Found %s in %s.\n"), name, termfile);
107 	sleep(1);
108 #endif /* DEBUG */
109 				return(1);
110 			}
111 		}
112 	}
113 	/* If we get here, then we haven't found a match. */
114 	fclose(fp);
115 #ifdef DEBUG
116 	fprintf(stderr,CGETS(31, 4, "No match found for %s in file %s\n"),
117 		name, termfile);
118 	sleep(1);
119 #endif /* DEBUG */
120 	return(0);
121 }
122 
123 /*
124  *	tgetnum - get the numeric terminal capability corresponding
125  *	to id. Returns the value, -1 if invalid.
126  */
127 int
128 tgetnum(char *id)
129 {
130 	char	*cp;
131 	int	ret;
132 
133 	if ((cp = capab) == NULL || id == NULL)
134 		return(-1);
135 	while (*++cp != ':')
136 		;
137 	for (++cp ; *cp ; cp++) {
138 		while (ISSPACE(*cp))
139 			cp++;
140 		if (strncmp(cp, id, CAPABLEN) == 0) {
141 			while (*cp && *cp != ':' && *cp != '#')
142 				cp++;
143 			if (*cp != '#')
144 				return(-1);
145 			for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++)
146 				ret = ret * 10 + *cp - '0';
147 			return(ret);
148 		}
149 		while (*cp && *cp != ':')
150 			cp++;
151 	}
152 	return(-1);
153 }
154 
155 /*
156  *	tgetflag - get the boolean flag corresponding to id. Returns -1
157  *	if invalid, 0 if the flag is not in termcap entry, or 1 if it is
158  *	present.
159  */
160 int
161 tgetflag(char *id)
162 {
163 	char	*cp;
164 
165 	if ((cp = capab) == NULL || id == NULL)
166 		return(-1);
167 	while (*++cp != ':')
168 		;
169 	for (++cp ; *cp ; cp++) {
170 		while (ISSPACE(*cp))
171 			cp++;
172 		if (strncmp(cp, id, CAPABLEN) == 0)
173 			return(1);
174 		while (*cp && *cp != ':')
175 			cp++;
176 	}
177 	return(0);
178 }
179 
180 /*
181  *	tgetstr - get the string capability corresponding to id and place
182  *	it in area (advancing area at same time). Expand escape sequences
183  *	etc. Returns the string, or NULL if it can't do it.
184  */
185 char *
186 tgetstr(char *id, char **area)
187 {
188 	char	*cp;
189 	char	*ret;
190 	int	i;
191 
192 	if ((cp = capab) == NULL || id == NULL)
193 		return(NULL);
194 	while (*++cp != ':')
195 		;
196 	for (++cp ; *cp ; cp++) {
197 		while (ISSPACE(*cp))
198 			cp++;
199 		if (strncmp(cp, id, CAPABLEN) == 0) {
200 			while (*cp && *cp != ':' && *cp != '=')
201 				cp++;
202 			if (*cp != '=')
203 				return(NULL);
204 			for (ret = *area, cp++; *cp && *cp != ':' ;
205 				(*area)++, cp++)
206 				switch(*cp) {
207 				case '^' :
208 					**area = *++cp - '@'; /* fix (efth)*/
209 					break;
210 				case '\\' :
211 					switch(*++cp) {
212 					case 'E' :
213 						**area = CTL_ESC('\033');
214 						break;
215 					case 'n' :
216 						**area = '\n';
217 						break;
218 					case 'r' :
219 						**area = '\r';
220 						break;
221 					case 't' :
222 						**area = '\t';
223 						break;
224 					case 'b' :
225 						**area = '\b';
226 						break;
227 					case 'f' :
228 						**area = '\f';
229 						break;
230 					case '0' :
231 					case '1' :
232 					case '2' :
233 					case '3' :
234 						for (i=0 ; *cp && ISDIGIT(*cp) ;
235 							 cp++)
236 							i = i * 8 + *cp - '0';
237 						**area = i;
238 						cp--;
239 						break;
240 					case '^' :
241 					case '\\' :
242 						**area = *cp;
243 						break;
244 					}
245 					break;
246 				default :
247 					**area = *cp;
248 				}
249 			*(*area)++ = '\0';
250 			return(ret);
251 		}
252 		while (*cp && *cp != ':')
253 			cp++;
254 	}
255 	return(NULL);
256 }
257 
258 /*
259  *	tgoto - given the cursor motion string cm, make up the string
260  *	for the cursor to go to (destcol, destline), and return the string.
261  *	Returns "OOPS" if something's gone wrong, or the string otherwise.
262  */
263 char *
264 tgoto(char *cm, int destcol, int destline)
265 {
266 	char	*rp;
267 	static char	ret[24];
268 	int		incr = 0;
269 	int 		argno = 0, numval;
270 
271 	for (rp = ret ; *cm ; cm++) {
272 		switch(*cm) {
273 		case '%' :
274 			switch(*++cm) {
275 			case '+' :
276 				numval = (argno == 0 ? destline : destcol);
277 				argno = 1 - argno;
278 				*rp++ = numval + incr + *++cm;
279 				break;
280 
281 			case '%' :
282 				*rp++ = '%';
283 				break;
284 
285 			case 'i' :
286 				incr = 1;
287 				break;
288 
289 			case 'd' :
290 				numval = (argno == 0 ? destline : destcol);
291 				numval += incr;
292 				argno = 1 - argno;
293 				*rp++ = '0' + (numval/10);
294 				*rp++ = '0' + (numval%10);
295 				break;
296 
297 			case 'r' :
298 				argno = 1;
299 				break;
300 			}
301 
302 			break;
303 		default :
304 			*rp++ = *cm;
305 		}
306 	}
307 	*rp = '\0';
308 	return(ret);
309 }
310 
311 /*
312  *	tputs - put the string cp out onto the terminal, using the function
313  *	outc. This should do padding for the terminal, but I can't find a
314  *	terminal that needs padding at the moment...
315  */
316 int
317 tputs(char *cp, int affcnt, int (*outc)())
318 {
319 	unsigned long delay = 0;
320 
321 	if (cp == NULL)
322 		return(1);
323 	/* do any padding interpretation - left null for MINIX just now */
324 	for (delay = 0; *cp && ISDIGIT(*cp) ; cp++)
325 		delay = delay * 10 + *cp - '0';
326 	while (*cp)
327 		(*outc)(*cp++);
328 #ifdef _OSD_POSIX
329 	usleep(delay*100); /* strictly spoken, it should be *1000 */
330 #endif
331 	return(1);
332 }
333 #endif /* _VMS_POSIX || _OSD_POSIX */
334