vms.termcap.c revision 167465
1167465Smp/* $Header: /p/tcsh/cvsroot/tcsh/vms.termcap.c,v 1.11 2006/03/02 18:46:45 christos 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"
12167465SmpRCSID("$tcsh: vms.termcap.c,v 1.11 2006/03/02 18:46:45 christos 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 */
37145479Smp#ifndef fopen
3859243Sobrienextern FILE	*fopen();	/* old fopen */
39145479Smp#endif
4059243Sobrien
4159243Sobrien/*
4259243Sobrien *	tgetent - get the termcap entry for terminal name, and put it
4359243Sobrien *	in bp (which must be an array of 1024 chars). Returns 1 if
4459243Sobrien *	termcap entry found, 0 if not found, and -1 if file not found.
4559243Sobrien */
4659243Sobrien
4759243Sobrienint
48167465Smptgetent(char *bp, char *name)
4959243Sobrien{
5059243Sobrien	FILE	*fp;
5159243Sobrien	char	*termfile;
5259243Sobrien	char	*cp,
5359243Sobrien		*ptr,		/* temporary pointer */
54167465Smp		tmp[1024];	/* buffer for terminal name *//*FIXBUF*/
55167465Smp	size_t	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);
80167465Smp
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 *	tgetnum - get the numeric terminal capability corresponding
12559243Sobrien *	to id. Returns the value, -1 if invalid.
12659243Sobrien */
12759243Sobrienint
128167465Smptgetnum(char *id)
12959243Sobrien{
13059243Sobrien	char	*cp;
13159243Sobrien	int	ret;
13259243Sobrien
13359243Sobrien	if ((cp = capab) == NULL || id == NULL)
13459243Sobrien		return(-1);
13559243Sobrien	while (*++cp != ':')
13659243Sobrien		;
13759243Sobrien	for (++cp ; *cp ; cp++) {
13859243Sobrien		while (ISSPACE(*cp))
13959243Sobrien			cp++;
14059243Sobrien		if (strncmp(cp, id, CAPABLEN) == 0) {
14159243Sobrien			while (*cp && *cp != ':' && *cp != '#')
14259243Sobrien				cp++;
14359243Sobrien			if (*cp != '#')
14459243Sobrien				return(-1);
14559243Sobrien			for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++)
14659243Sobrien				ret = ret * 10 + *cp - '0';
14759243Sobrien			return(ret);
14859243Sobrien		}
14959243Sobrien		while (*cp && *cp != ':')
15059243Sobrien			cp++;
15159243Sobrien	}
15259243Sobrien	return(-1);
15359243Sobrien}
15459243Sobrien
15559243Sobrien/*
15659243Sobrien *	tgetflag - get the boolean flag corresponding to id. Returns -1
15759243Sobrien *	if invalid, 0 if the flag is not in termcap entry, or 1 if it is
15859243Sobrien *	present.
15959243Sobrien */
16059243Sobrienint
161167465Smptgetflag(char *id)
16259243Sobrien{
16359243Sobrien	char	*cp;
16459243Sobrien
16559243Sobrien	if ((cp = capab) == NULL || id == NULL)
16659243Sobrien		return(-1);
16759243Sobrien	while (*++cp != ':')
16859243Sobrien		;
16959243Sobrien	for (++cp ; *cp ; cp++) {
17059243Sobrien		while (ISSPACE(*cp))
17159243Sobrien			cp++;
17259243Sobrien		if (strncmp(cp, id, CAPABLEN) == 0)
17359243Sobrien			return(1);
17459243Sobrien		while (*cp && *cp != ':')
17559243Sobrien			cp++;
17659243Sobrien	}
17759243Sobrien	return(0);
17859243Sobrien}
17959243Sobrien
18059243Sobrien/*
18159243Sobrien *	tgetstr - get the string capability corresponding to id and place
18259243Sobrien *	it in area (advancing area at same time). Expand escape sequences
18359243Sobrien *	etc. Returns the string, or NULL if it can't do it.
18459243Sobrien */
18559243Sobrienchar *
186167465Smptgetstr(char *id, char **area)
18759243Sobrien{
18859243Sobrien	char	*cp;
18959243Sobrien	char	*ret;
19059243Sobrien	int	i;
19159243Sobrien
19259243Sobrien	if ((cp = capab) == NULL || id == NULL)
19359243Sobrien		return(NULL);
19459243Sobrien	while (*++cp != ':')
19559243Sobrien		;
19659243Sobrien	for (++cp ; *cp ; cp++) {
19759243Sobrien		while (ISSPACE(*cp))
19859243Sobrien			cp++;
19959243Sobrien		if (strncmp(cp, id, CAPABLEN) == 0) {
20059243Sobrien			while (*cp && *cp != ':' && *cp != '=')
20159243Sobrien				cp++;
20259243Sobrien			if (*cp != '=')
20359243Sobrien				return(NULL);
20459243Sobrien			for (ret = *area, cp++; *cp && *cp != ':' ;
20559243Sobrien				(*area)++, cp++)
20659243Sobrien				switch(*cp) {
20759243Sobrien				case '^' :
20859243Sobrien					**area = *++cp - '@'; /* fix (efth)*/
20959243Sobrien					break;
21059243Sobrien				case '\\' :
21159243Sobrien					switch(*++cp) {
21259243Sobrien					case 'E' :
21359243Sobrien						**area = CTL_ESC('\033');
21459243Sobrien						break;
21559243Sobrien					case 'n' :
21659243Sobrien						**area = '\n';
21759243Sobrien						break;
21859243Sobrien					case 'r' :
21959243Sobrien						**area = '\r';
22059243Sobrien						break;
22159243Sobrien					case 't' :
22259243Sobrien						**area = '\t';
22359243Sobrien						break;
22459243Sobrien					case 'b' :
22559243Sobrien						**area = '\b';
22659243Sobrien						break;
22759243Sobrien					case 'f' :
22859243Sobrien						**area = '\f';
22959243Sobrien						break;
23059243Sobrien					case '0' :
23159243Sobrien					case '1' :
23259243Sobrien					case '2' :
23359243Sobrien					case '3' :
23459243Sobrien						for (i=0 ; *cp && ISDIGIT(*cp) ;
23559243Sobrien							 cp++)
23659243Sobrien							i = i * 8 + *cp - '0';
23759243Sobrien						**area = i;
23859243Sobrien						cp--;
23959243Sobrien						break;
24059243Sobrien					case '^' :
24159243Sobrien					case '\\' :
24259243Sobrien						**area = *cp;
24359243Sobrien						break;
24459243Sobrien					}
24559243Sobrien					break;
24659243Sobrien				default :
24759243Sobrien					**area = *cp;
24859243Sobrien				}
24959243Sobrien			*(*area)++ = '\0';
25059243Sobrien			return(ret);
25159243Sobrien		}
25259243Sobrien		while (*cp && *cp != ':')
25359243Sobrien			cp++;
25459243Sobrien	}
25559243Sobrien	return(NULL);
25659243Sobrien}
25759243Sobrien
25859243Sobrien/*
25959243Sobrien *	tgoto - given the cursor motion string cm, make up the string
26059243Sobrien *	for the cursor to go to (destcol, destline), and return the string.
26159243Sobrien *	Returns "OOPS" if something's gone wrong, or the string otherwise.
26259243Sobrien */
26359243Sobrienchar *
264167465Smptgoto(char *cm, int destcol, int destline)
26559243Sobrien{
266145479Smp	char	*rp;
26759243Sobrien	static char	ret[24];
26859243Sobrien	int		incr = 0;
26959243Sobrien	int 		argno = 0, numval;
27059243Sobrien
27159243Sobrien	for (rp = ret ; *cm ; cm++) {
27259243Sobrien		switch(*cm) {
27359243Sobrien		case '%' :
27459243Sobrien			switch(*++cm) {
27559243Sobrien			case '+' :
27659243Sobrien				numval = (argno == 0 ? destline : destcol);
27759243Sobrien				argno = 1 - argno;
27859243Sobrien				*rp++ = numval + incr + *++cm;
27959243Sobrien				break;
28059243Sobrien
28159243Sobrien			case '%' :
28259243Sobrien				*rp++ = '%';
28359243Sobrien				break;
28459243Sobrien
28559243Sobrien			case 'i' :
28659243Sobrien				incr = 1;
28759243Sobrien				break;
28859243Sobrien
28959243Sobrien			case 'd' :
29059243Sobrien				numval = (argno == 0 ? destline : destcol);
29159243Sobrien				numval += incr;
29259243Sobrien				argno = 1 - argno;
29359243Sobrien				*rp++ = '0' + (numval/10);
29459243Sobrien				*rp++ = '0' + (numval%10);
29559243Sobrien				break;
29659243Sobrien
29759243Sobrien			case 'r' :
29859243Sobrien				argno = 1;
29959243Sobrien				break;
30059243Sobrien			}
30159243Sobrien
30259243Sobrien			break;
30359243Sobrien		default :
30459243Sobrien			*rp++ = *cm;
30559243Sobrien		}
30659243Sobrien	}
30759243Sobrien	*rp = '\0';
30859243Sobrien	return(ret);
30959243Sobrien}
31059243Sobrien
31159243Sobrien/*
31259243Sobrien *	tputs - put the string cp out onto the terminal, using the function
31359243Sobrien *	outc. This should do padding for the terminal, but I can't find a
31459243Sobrien *	terminal that needs padding at the moment...
31559243Sobrien */
31659243Sobrienint
317167465Smptputs(char *cp, int affcnt, int (*outc)())
31859243Sobrien{
319145479Smp	unsigned long delay = 0;
320145479Smp
32159243Sobrien	if (cp == NULL)
32259243Sobrien		return(1);
32359243Sobrien	/* do any padding interpretation - left null for MINIX just now */
324145479Smp	for (delay = 0; *cp && ISDIGIT(*cp) ; cp++)
325145479Smp		delay = delay * 10 + *cp - '0';
32659243Sobrien	while (*cp)
32759243Sobrien		(*outc)(*cp++);
328145479Smp#ifdef _OSD_POSIX
329145479Smp	usleep(delay*100); /* strictly spoken, it should be *1000 */
330145479Smp#endif
33159243Sobrien	return(1);
33259243Sobrien}
33369408Sache#endif /* _VMS_POSIX || _OSD_POSIX */
334