xref: /freebsd/contrib/tcsh/vms.termcap.c (revision 2b743a9e9ddc6736208dc8ca1ce06ce64ad20a19)
1 /* $Header: /src/pub/tcsh/vms.termcap.c,v 1.8 2005/03/03 16:49:16 kim 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("$Id: vms.termcap.c,v 1.8 2005/03/03 16:49:16 kim 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(bp, name)
49 char	*bp;
50 char	*name;
51 {
52 	FILE	*fp;
53 	char	*termfile;
54 	char	*cp,
55 		*ptr,		/* temporary pointer */
56 		tmp[1024];	/* buffer for terminal name */
57 	short	len = strlen(name);
58 
59 	capab = bp;
60 
61 	/* Use TERMCAP to override default. */
62 
63 	termfile = getenv("TERMCAP");
64 	if (termfile == NULL ) termfile = "/etc/termcap";
65 
66 	if ((fp = fopen(termfile, "r")) == (FILE *) NULL) {
67 		fprintf(stderr, CGETS(31, 1,
68 		        "Can't open TERMCAP: [%s]\n"), termfile);
69 		fprintf(stderr, CGETS(31, 2, "Can't open %s.\n"), termfile);
70 		sleep(1);
71 		return(-1);
72 	}
73 
74 	while (fgets(bp, 1024, fp) != NULL) {
75 		/* Any line starting with # or NL is skipped as a comment */
76 		if ((*bp == '#') || (*bp == '\n')) continue;
77 
78 		/* Look for lines which end with two backslashes,
79 		and then append the next line. */
80 		while (*(cp = &bp[strlen(bp) - 2]) == '\\')
81 			fgets(cp, 1024, fp);
82 
83 		/* Skip over any spaces or tabs */
84 		for (++cp ; ISSPACE(*cp) ; cp++);
85 
86 		/*  Make sure "name" matches exactly  (efth)  */
87 
88 /* Here we might want to look at any aliases as well.  We'll use
89 sscanf to look at aliases.  These are delimited by '|'. */
90 
91 		sscanf(bp,"%[^|]",tmp);
92 		if (strncmp(name, tmp, len) == 0) {
93 			fclose(fp);
94 #ifdef DEBUG
95 	fprintf(stderr, CGETS(31, 3, "Found %s in %s.\n"), name, termfile);
96 	sleep(1);
97 #endif /* DEBUG */
98 			return(1);
99 		}
100 		ptr = bp;
101 		while ((ptr = strchr(ptr,'|')) != NULL) {
102 			ptr++;
103 			if (strchr(ptr,'|') == NULL) break;
104 			sscanf(ptr,"%[^|]",tmp);
105 			if (strncmp(name, tmp, len) == 0) {
106 				fclose(fp);
107 #ifdef DEBUG
108 	fprintf(stderr,CGETS(31, 3, "Found %s in %s.\n"), name, termfile);
109 	sleep(1);
110 #endif /* DEBUG */
111 				return(1);
112 			}
113 		}
114 	}
115 	/* If we get here, then we haven't found a match. */
116 	fclose(fp);
117 #ifdef DEBUG
118 	fprintf(stderr,CGETS(31, 4, "No match found for %s in file %s\n"),
119 		name, termfile);
120 	sleep(1);
121 #endif /* DEBUG */
122 	return(0);
123 
124 }
125 
126 /*
127  *	tgetnum - get the numeric terminal capability corresponding
128  *	to id. Returns the value, -1 if invalid.
129  */
130 int
131 tgetnum(id)
132 char	*id;
133 {
134 	char	*cp;
135 	int	ret;
136 
137 	if ((cp = capab) == NULL || id == NULL)
138 		return(-1);
139 	while (*++cp != ':')
140 		;
141 	for (++cp ; *cp ; cp++) {
142 		while (ISSPACE(*cp))
143 			cp++;
144 		if (strncmp(cp, id, CAPABLEN) == 0) {
145 			while (*cp && *cp != ':' && *cp != '#')
146 				cp++;
147 			if (*cp != '#')
148 				return(-1);
149 			for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++)
150 				ret = ret * 10 + *cp - '0';
151 			return(ret);
152 		}
153 		while (*cp && *cp != ':')
154 			cp++;
155 	}
156 	return(-1);
157 }
158 
159 /*
160  *	tgetflag - get the boolean flag corresponding to id. Returns -1
161  *	if invalid, 0 if the flag is not in termcap entry, or 1 if it is
162  *	present.
163  */
164 int
165 tgetflag(id)
166 char	*id;
167 {
168 	char	*cp;
169 
170 	if ((cp = capab) == NULL || id == NULL)
171 		return(-1);
172 	while (*++cp != ':')
173 		;
174 	for (++cp ; *cp ; cp++) {
175 		while (ISSPACE(*cp))
176 			cp++;
177 		if (strncmp(cp, id, CAPABLEN) == 0)
178 			return(1);
179 		while (*cp && *cp != ':')
180 			cp++;
181 	}
182 	return(0);
183 }
184 
185 /*
186  *	tgetstr - get the string capability corresponding to id and place
187  *	it in area (advancing area at same time). Expand escape sequences
188  *	etc. Returns the string, or NULL if it can't do it.
189  */
190 char *
191 tgetstr(id, area)
192 char	*id;
193 char	**area;
194 {
195 	char	*cp;
196 	char	*ret;
197 	int	i;
198 
199 	if ((cp = capab) == NULL || id == NULL)
200 		return(NULL);
201 	while (*++cp != ':')
202 		;
203 	for (++cp ; *cp ; cp++) {
204 		while (ISSPACE(*cp))
205 			cp++;
206 		if (strncmp(cp, id, CAPABLEN) == 0) {
207 			while (*cp && *cp != ':' && *cp != '=')
208 				cp++;
209 			if (*cp != '=')
210 				return(NULL);
211 			for (ret = *area, cp++; *cp && *cp != ':' ;
212 				(*area)++, cp++)
213 				switch(*cp) {
214 				case '^' :
215 					**area = *++cp - '@'; /* fix (efth)*/
216 					break;
217 				case '\\' :
218 					switch(*++cp) {
219 					case 'E' :
220 						**area = CTL_ESC('\033');
221 						break;
222 					case 'n' :
223 						**area = '\n';
224 						break;
225 					case 'r' :
226 						**area = '\r';
227 						break;
228 					case 't' :
229 						**area = '\t';
230 						break;
231 					case 'b' :
232 						**area = '\b';
233 						break;
234 					case 'f' :
235 						**area = '\f';
236 						break;
237 					case '0' :
238 					case '1' :
239 					case '2' :
240 					case '3' :
241 						for (i=0 ; *cp && ISDIGIT(*cp) ;
242 							 cp++)
243 							i = i * 8 + *cp - '0';
244 						**area = i;
245 						cp--;
246 						break;
247 					case '^' :
248 					case '\\' :
249 						**area = *cp;
250 						break;
251 					}
252 					break;
253 				default :
254 					**area = *cp;
255 				}
256 			*(*area)++ = '\0';
257 			return(ret);
258 		}
259 		while (*cp && *cp != ':')
260 			cp++;
261 	}
262 	return(NULL);
263 }
264 
265 /*
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.
269  */
270 char *
271 tgoto(cm, destcol, destline)
272 char	*cm;
273 int	destcol;
274 int	destline;
275 {
276 	char	*rp;
277 	static char	ret[24];
278 	int		incr = 0;
279 	int 		argno = 0, numval;
280 
281 	for (rp = ret ; *cm ; cm++) {
282 		switch(*cm) {
283 		case '%' :
284 			switch(*++cm) {
285 			case '+' :
286 				numval = (argno == 0 ? destline : destcol);
287 				argno = 1 - argno;
288 				*rp++ = numval + incr + *++cm;
289 				break;
290 
291 			case '%' :
292 				*rp++ = '%';
293 				break;
294 
295 			case 'i' :
296 				incr = 1;
297 				break;
298 
299 			case 'd' :
300 				numval = (argno == 0 ? destline : destcol);
301 				numval += incr;
302 				argno = 1 - argno;
303 				*rp++ = '0' + (numval/10);
304 				*rp++ = '0' + (numval%10);
305 				break;
306 
307 			case 'r' :
308 				argno = 1;
309 				break;
310 			}
311 
312 			break;
313 		default :
314 			*rp++ = *cm;
315 		}
316 	}
317 	*rp = '\0';
318 	return(ret);
319 }
320 
321 /*
322  *	tputs - put the string cp out onto the terminal, using the function
323  *	outc. This should do padding for the terminal, but I can't find a
324  *	terminal that needs padding at the moment...
325  */
326 int
327 tputs(cp, affcnt, outc)
328 char	*cp;
329 int		affcnt;
330 int		(*outc)();
331 {
332 	unsigned long delay = 0;
333 
334 	if (cp == NULL)
335 		return(1);
336 	/* do any padding interpretation - left null for MINIX just now */
337 	for (delay = 0; *cp && ISDIGIT(*cp) ; cp++)
338 		delay = delay * 10 + *cp - '0';
339 	while (*cp)
340 		(*outc)(*cp++);
341 #ifdef _OSD_POSIX
342 	usleep(delay*100); /* strictly spoken, it should be *1000 */
343 #endif
344 	return(1);
345 }
346 #endif /* _VMS_POSIX || _OSD_POSIX */
347