vms.termcap.c revision 69408
169408Sache/* $Header: /src/pub/tcsh/vms.termcap.c,v 1.6 2000/06/10 23:32:42 kim Exp $ */
259243Sobrien/*
359243Sobrien *	termcap.c	1.1	20/7/87		agc	Joypace Ltd
459243Sobrien *
559243Sobrien *	Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
659243Sobrien *	This file may be freely distributed provided that this notice
759243Sobrien *	remains attached.
859243Sobrien *
959243Sobrien *	A public domain implementation of the termcap(3) routines.
1059243Sobrien */
1159243Sobrien#include "sh.h"
1269408SacheRCSID("$Id: vms.termcap.c,v 1.6 2000/06/10 23:32:42 kim Exp $")
1359243Sobrien#if defined(_VMS_POSIX) || defined(_OSD_POSIX)
1459243Sobrien/*    efth      1988-Apr-29
1559243Sobrien
1659243Sobrien    - Correct when TERM != name and TERMCAP is defined   [tgetent]
1759243Sobrien    - Correct the comparison for the terminal name       [tgetent]
1859243Sobrien    - Correct the value of ^x escapes                    [tgetstr]
1959243Sobrien    - Added %r to reverse row/column			 [tgoto]
2059243Sobrien
2159243Sobrien     Paul Gillingwater <paul@actrix.gen.nz> July 1992
2259243Sobrien	- Modified to allow terminal aliases in termcap file
2359243Sobrien	- Uses TERMCAP environment variable for file only
2459243Sobrien*/
2559243Sobrien
2659243Sobrien#include	<stdio.h>
2759243Sobrien#include	<string.h>
2859243Sobrien
2959243Sobrien#define CAPABLEN	2
3059243Sobrien
3159243Sobrien#define ISSPACE(c)  ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
3259243Sobrien#define ISDIGIT(x)  ((x) >= '0' && (x) <= '9')
3359243Sobrien
3459243Sobrienchar		*capab;		/* the capability itself */
3559243Sobrien
3659243Sobrienextern char	*getenv();	/* new, improved getenv */
3759243Sobrienextern FILE	*fopen();	/* old fopen */
3859243Sobrien
3959243Sobrien/*
4059243Sobrien *	tgetent - get the termcap entry for terminal name, and put it
4159243Sobrien *	in bp (which must be an array of 1024 chars). Returns 1 if
4259243Sobrien *	termcap entry found, 0 if not found, and -1 if file not found.
4359243Sobrien */
4459243Sobrien
4559243Sobrienint
4659243Sobrientgetent(bp, name)
4759243Sobrienchar	*bp;
4859243Sobrienchar	*name;
4959243Sobrien{
5059243Sobrien	FILE	*fp;
5159243Sobrien	char	*termfile;
5259243Sobrien	char	*cp,
5359243Sobrien		*ptr,		/* temporary pointer */
5459243Sobrien		tmp[1024];	/* buffer for terminal name */
5559243Sobrien	short	len = strlen(name);
5659243Sobrien
5759243Sobrien	capab = bp;
5859243Sobrien
5959243Sobrien	/* Use TERMCAP to override default. */
6059243Sobrien
6159243Sobrien	termfile = getenv("TERMCAP");
6259243Sobrien	if (termfile == NULL ) termfile = "/etc/termcap";
6359243Sobrien
6459243Sobrien	if ((fp = fopen(termfile, "r")) == (FILE *) NULL) {
6559243Sobrien		fprintf(stderr, CGETS(31, 1,
6659243Sobrien		        "Can't open TERMCAP: [%s]\n"), termfile);
6759243Sobrien		fprintf(stderr, CGETS(31, 2, "Can't open %s.\n"), termfile);
6859243Sobrien		sleep(1);
6959243Sobrien		return(-1);
7059243Sobrien	}
7159243Sobrien
7259243Sobrien	while (fgets(bp, 1024, fp) != NULL) {
7359243Sobrien		/* Any line starting with # or NL is skipped as a comment */
7459243Sobrien		if ((*bp == '#') || (*bp == '\n')) continue;
7559243Sobrien
7659243Sobrien		/* Look for lines which end with two backslashes,
7759243Sobrien		and then append the next line. */
7859243Sobrien		while (*(cp = &bp[strlen(bp) - 2]) == '\\')
7959243Sobrien			fgets(cp, 1024, fp);
8059243Sobrien
8159243Sobrien		/* Skip over any spaces or tabs */
8259243Sobrien		for (++cp ; ISSPACE(*cp) ; cp++);
8359243Sobrien
8459243Sobrien		/*  Make sure "name" matches exactly  (efth)  */
8559243Sobrien
8659243Sobrien/* Here we might want to look at any aliases as well.  We'll use
8759243Sobriensscanf to look at aliases.  These are delimited by '|'. */
8859243Sobrien
8959243Sobrien		sscanf(bp,"%[^|]",tmp);
9059243Sobrien		if (strncmp(name, tmp, len) == 0) {
9159243Sobrien			fclose(fp);
9259243Sobrien#ifdef DEBUG
9359243Sobrien	fprintf(stderr, CGETS(31, 3, "Found %s in %s.\n"), name, termfile);
9459243Sobrien	sleep(1);
9559243Sobrien#endif /* DEBUG */
9659243Sobrien			return(1);
9759243Sobrien		}
9859243Sobrien		ptr = bp;
9959243Sobrien		while ((ptr = strchr(ptr,'|')) != NULL) {
10059243Sobrien			ptr++;
10159243Sobrien			if (strchr(ptr,'|') == NULL) break;
10259243Sobrien			sscanf(ptr,"%[^|]",tmp);
10359243Sobrien			if (strncmp(name, tmp, len) == 0) {
10459243Sobrien				fclose(fp);
10559243Sobrien#ifdef DEBUG
10659243Sobrien	fprintf(stderr,CGETS(31, 3, "Found %s in %s.\n"), name, termfile);
10759243Sobrien	sleep(1);
10859243Sobrien#endif /* DEBUG */
10959243Sobrien				return(1);
11059243Sobrien			}
11159243Sobrien		}
11259243Sobrien	}
11359243Sobrien	/* If we get here, then we haven't found a match. */
11459243Sobrien	fclose(fp);
11559243Sobrien#ifdef DEBUG
11659243Sobrien	fprintf(stderr,CGETS(31, 4, "No match found for %s in file %s\n"),
11759243Sobrien		name, termfile);
11859243Sobrien	sleep(1);
11959243Sobrien#endif /* DEBUG */
12059243Sobrien	return(0);
12159243Sobrien
12259243Sobrien}
12359243Sobrien
12459243Sobrien/*
12559243Sobrien *	tgetnum - get the numeric terminal capability corresponding
12659243Sobrien *	to id. Returns the value, -1 if invalid.
12759243Sobrien */
12859243Sobrienint
12959243Sobrientgetnum(id)
13059243Sobrienchar	*id;
13159243Sobrien{
13259243Sobrien	char	*cp;
13359243Sobrien	int	ret;
13459243Sobrien
13559243Sobrien	if ((cp = capab) == NULL || id == NULL)
13659243Sobrien		return(-1);
13759243Sobrien	while (*++cp != ':')
13859243Sobrien		;
13959243Sobrien	for (++cp ; *cp ; cp++) {
14059243Sobrien		while (ISSPACE(*cp))
14159243Sobrien			cp++;
14259243Sobrien		if (strncmp(cp, id, CAPABLEN) == 0) {
14359243Sobrien			while (*cp && *cp != ':' && *cp != '#')
14459243Sobrien				cp++;
14559243Sobrien			if (*cp != '#')
14659243Sobrien				return(-1);
14759243Sobrien			for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++)
14859243Sobrien				ret = ret * 10 + *cp - '0';
14959243Sobrien			return(ret);
15059243Sobrien		}
15159243Sobrien		while (*cp && *cp != ':')
15259243Sobrien			cp++;
15359243Sobrien	}
15459243Sobrien	return(-1);
15559243Sobrien}
15659243Sobrien
15759243Sobrien/*
15859243Sobrien *	tgetflag - get the boolean flag corresponding to id. Returns -1
15959243Sobrien *	if invalid, 0 if the flag is not in termcap entry, or 1 if it is
16059243Sobrien *	present.
16159243Sobrien */
16259243Sobrienint
16359243Sobrientgetflag(id)
16459243Sobrienchar	*id;
16559243Sobrien{
16659243Sobrien	char	*cp;
16759243Sobrien
16859243Sobrien	if ((cp = capab) == NULL || id == NULL)
16959243Sobrien		return(-1);
17059243Sobrien	while (*++cp != ':')
17159243Sobrien		;
17259243Sobrien	for (++cp ; *cp ; cp++) {
17359243Sobrien		while (ISSPACE(*cp))
17459243Sobrien			cp++;
17559243Sobrien		if (strncmp(cp, id, CAPABLEN) == 0)
17659243Sobrien			return(1);
17759243Sobrien		while (*cp && *cp != ':')
17859243Sobrien			cp++;
17959243Sobrien	}
18059243Sobrien	return(0);
18159243Sobrien}
18259243Sobrien
18359243Sobrien/*
18459243Sobrien *	tgetstr - get the string capability corresponding to id and place
18559243Sobrien *	it in area (advancing area at same time). Expand escape sequences
18659243Sobrien *	etc. Returns the string, or NULL if it can't do it.
18759243Sobrien */
18859243Sobrienchar *
18959243Sobrientgetstr(id, area)
19059243Sobrienchar	*id;
19159243Sobrienchar	**area;
19259243Sobrien{
19359243Sobrien	char	*cp;
19459243Sobrien	char	*ret;
19559243Sobrien	int	i;
19659243Sobrien
19759243Sobrien	if ((cp = capab) == NULL || id == NULL)
19859243Sobrien		return(NULL);
19959243Sobrien	while (*++cp != ':')
20059243Sobrien		;
20159243Sobrien	for (++cp ; *cp ; cp++) {
20259243Sobrien		while (ISSPACE(*cp))
20359243Sobrien			cp++;
20459243Sobrien		if (strncmp(cp, id, CAPABLEN) == 0) {
20559243Sobrien			while (*cp && *cp != ':' && *cp != '=')
20659243Sobrien				cp++;
20759243Sobrien			if (*cp != '=')
20859243Sobrien				return(NULL);
20959243Sobrien			for (ret = *area, cp++; *cp && *cp != ':' ;
21059243Sobrien				(*area)++, cp++)
21159243Sobrien				switch(*cp) {
21259243Sobrien				case '^' :
21359243Sobrien					**area = *++cp - '@'; /* fix (efth)*/
21459243Sobrien					break;
21559243Sobrien				case '\\' :
21659243Sobrien					switch(*++cp) {
21759243Sobrien					case 'E' :
21859243Sobrien						**area = CTL_ESC('\033');
21959243Sobrien						break;
22059243Sobrien					case 'n' :
22159243Sobrien						**area = '\n';
22259243Sobrien						break;
22359243Sobrien					case 'r' :
22459243Sobrien						**area = '\r';
22559243Sobrien						break;
22659243Sobrien					case 't' :
22759243Sobrien						**area = '\t';
22859243Sobrien						break;
22959243Sobrien					case 'b' :
23059243Sobrien						**area = '\b';
23159243Sobrien						break;
23259243Sobrien					case 'f' :
23359243Sobrien						**area = '\f';
23459243Sobrien						break;
23559243Sobrien					case '0' :
23659243Sobrien					case '1' :
23759243Sobrien					case '2' :
23859243Sobrien					case '3' :
23959243Sobrien						for (i=0 ; *cp && ISDIGIT(*cp) ;
24059243Sobrien							 cp++)
24159243Sobrien							i = i * 8 + *cp - '0';
24259243Sobrien						**area = i;
24359243Sobrien						cp--;
24459243Sobrien						break;
24559243Sobrien					case '^' :
24659243Sobrien					case '\\' :
24759243Sobrien						**area = *cp;
24859243Sobrien						break;
24959243Sobrien					}
25059243Sobrien					break;
25159243Sobrien				default :
25259243Sobrien					**area = *cp;
25359243Sobrien				}
25459243Sobrien			*(*area)++ = '\0';
25559243Sobrien			return(ret);
25659243Sobrien		}
25759243Sobrien		while (*cp && *cp != ':')
25859243Sobrien			cp++;
25959243Sobrien	}
26059243Sobrien	return(NULL);
26159243Sobrien}
26259243Sobrien
26359243Sobrien/*
26459243Sobrien *	tgoto - given the cursor motion string cm, make up the string
26559243Sobrien *	for the cursor to go to (destcol, destline), and return the string.
26659243Sobrien *	Returns "OOPS" if something's gone wrong, or the string otherwise.
26759243Sobrien */
26859243Sobrienchar *
26959243Sobrientgoto(cm, destcol, destline)
27059243Sobrienchar	*cm;
27159243Sobrienint	destcol;
27259243Sobrienint	destline;
27359243Sobrien{
27459243Sobrien	register char	*rp;
27559243Sobrien	static char	ret[24];
27659243Sobrien	int		incr = 0;
27759243Sobrien	int 		argno = 0, numval;
27859243Sobrien
27959243Sobrien	for (rp = ret ; *cm ; cm++) {
28059243Sobrien		switch(*cm) {
28159243Sobrien		case '%' :
28259243Sobrien			switch(*++cm) {
28359243Sobrien			case '+' :
28459243Sobrien				numval = (argno == 0 ? destline : destcol);
28559243Sobrien				argno = 1 - argno;
28659243Sobrien				*rp++ = numval + incr + *++cm;
28759243Sobrien				break;
28859243Sobrien
28959243Sobrien			case '%' :
29059243Sobrien				*rp++ = '%';
29159243Sobrien				break;
29259243Sobrien
29359243Sobrien			case 'i' :
29459243Sobrien				incr = 1;
29559243Sobrien				break;
29659243Sobrien
29759243Sobrien			case 'd' :
29859243Sobrien				numval = (argno == 0 ? destline : destcol);
29959243Sobrien				numval += incr;
30059243Sobrien				argno = 1 - argno;
30159243Sobrien				*rp++ = '0' + (numval/10);
30259243Sobrien				*rp++ = '0' + (numval%10);
30359243Sobrien				break;
30459243Sobrien
30559243Sobrien			case 'r' :
30659243Sobrien				argno = 1;
30759243Sobrien				break;
30859243Sobrien			}
30959243Sobrien
31059243Sobrien			break;
31159243Sobrien		default :
31259243Sobrien			*rp++ = *cm;
31359243Sobrien		}
31459243Sobrien	}
31559243Sobrien	*rp = '\0';
31659243Sobrien	return(ret);
31759243Sobrien}
31859243Sobrien
31959243Sobrien/*
32059243Sobrien *	tputs - put the string cp out onto the terminal, using the function
32159243Sobrien *	outc. This should do padding for the terminal, but I can't find a
32259243Sobrien *	terminal that needs padding at the moment...
32359243Sobrien */
32459243Sobrienint
32559243Sobrientputs(cp, affcnt, outc)
32659243Sobrienregister char	*cp;
32759243Sobrienint		affcnt;
32859243Sobrienint		(*outc)();
32959243Sobrien{
33059243Sobrien	if (cp == NULL)
33159243Sobrien		return(1);
33259243Sobrien	/* do any padding interpretation - left null for MINIX just now */
33359243Sobrien	while (*cp)
33459243Sobrien		(*outc)(*cp++);
33559243Sobrien	return(1);
33659243Sobrien}
33769408Sache#endif /* _VMS_POSIX || _OSD_POSIX */
338