vms.termcap.c revision 167466
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"
12RCSID("$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
34char		*capab;		/* the capability itself */
35
36extern char	*getenv();	/* new, improved getenv */
37#ifndef fopen
38extern 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
47int
48tgetent(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
87sscanf 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 */
127int
128tgetnum(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 */
160int
161tgetflag(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 */
185char *
186tgetstr(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 */
263char *
264tgoto(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 */
316int
317tputs(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