vms.termcap.c revision 145479
1277325Sdim/* $Header: /src/pub/tcsh/vms.termcap.c,v 1.8 2005/03/03 16:49:16 kim Exp $ */
2277325Sdim/*
3353358Sdim *	termcap.c	1.1	20/7/87		agc	Joypace Ltd
4353358Sdim *
5353358Sdim *	Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
6277325Sdim *	This file may be freely distributed provided that this notice
7277325Sdim *	remains attached.
8277325Sdim *
9277325Sdim *	A public domain implementation of the termcap(3) routines.
10341825Sdim */
11277325Sdim#include "sh.h"
12277325SdimRCSID("$Id: vms.termcap.c,v 1.8 2005/03/03 16:49:16 kim Exp $")
13277325Sdim#if defined(_VMS_POSIX) || defined(_OSD_POSIX)
14277325Sdim/*    efth      1988-Apr-29
15277325Sdim
16277325Sdim    - Correct when TERM != name and TERMCAP is defined   [tgetent]
17277325Sdim    - Correct the comparison for the terminal name       [tgetent]
18277325Sdim    - Correct the value of ^x escapes                    [tgetstr]
19277325Sdim    - Added %r to reverse row/column			 [tgoto]
20277325Sdim
21277325Sdim     Paul Gillingwater <paul@actrix.gen.nz> July 1992
22277325Sdim	- Modified to allow terminal aliases in termcap file
23277325Sdim	- Uses TERMCAP environment variable for file only
24277325Sdim*/
25341825Sdim
26277325Sdim#include	<stdio.h>
27277325Sdim#include	<string.h>
28277325Sdim
29277325Sdim#define CAPABLEN	2
30277325Sdim
31277325Sdim#define ISSPACE(c)  ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
32277325Sdim#define ISDIGIT(x)  ((x) >= '0' && (x) <= '9')
33277325Sdim
34277325Sdimchar		*capab;		/* the capability itself */
35277325Sdim
36277325Sdimextern char	*getenv();	/* new, improved getenv */
37277325Sdim#ifndef fopen
38277325Sdimextern FILE	*fopen();	/* old fopen */
39277325Sdim#endif
40277325Sdim
41277325Sdim/*
42277325Sdim *	tgetent - get the termcap entry for terminal name, and put it
43277325Sdim *	in bp (which must be an array of 1024 chars). Returns 1 if
44277325Sdim *	termcap entry found, 0 if not found, and -1 if file not found.
45277325Sdim */
46
47int
48tgetent(bp, name)
49char	*bp;
50char	*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
89sscanf 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 */
130int
131tgetnum(id)
132char	*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 */
164int
165tgetflag(id)
166char	*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 */
190char *
191tgetstr(id, area)
192char	*id;
193char	**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 */
270char *
271tgoto(cm, destcol, destline)
272char	*cm;
273int	destcol;
274int	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 */
326int
327tputs(cp, affcnt, outc)
328char	*cp;
329int		affcnt;
330int		(*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