vms.termcap.c revision 59243
198943Sluigi/* $Header: /src/pub/tcsh/vms.termcap.c,v 1.5 1997/10/02 16:36:36 christos Exp $ */
298943Sluigi/*
398943Sluigi *	termcap.c	1.1	20/7/87		agc	Joypace Ltd
498943Sluigi *
598943Sluigi *	Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
698943Sluigi *	This file may be freely distributed provided that this notice
798943Sluigi *	remains attached.
898943Sluigi *
998943Sluigi *	A public domain implementation of the termcap(3) routines.
1098943Sluigi */
1198943Sluigi#include "sh.h"
1298943SluigiRCSID("$Id: vms.termcap.c,v 1.5 1997/10/02 16:36:36 christos Exp $")
1398943Sluigi#if defined(_VMS_POSIX) || defined(_OSD_POSIX)
1498943Sluigi/*    efth      1988-Apr-29
1598943Sluigi
1698943Sluigi    - Correct when TERM != name and TERMCAP is defined   [tgetent]
1798943Sluigi    - Correct the comparison for the terminal name       [tgetent]
1898943Sluigi    - Correct the value of ^x escapes                    [tgetstr]
1998943Sluigi    - Added %r to reverse row/column			 [tgoto]
2098943Sluigi
2198943Sluigi     Paul Gillingwater <paul@actrix.gen.nz> July 1992
2298943Sluigi	- Modified to allow terminal aliases in termcap file
2398943Sluigi	- Uses TERMCAP environment variable for file only
2498943Sluigi*/
2598943Sluigi
2698943Sluigi#include	<stdio.h>
2798943Sluigi#include	<string.h>
2898943Sluigi
2998943Sluigi#define CAPABLEN	2
3098943Sluigi
3198943Sluigi#define ISSPACE(c)  ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
3298943Sluigi#define ISDIGIT(x)  ((x) >= '0' && (x) <= '9')
3398943Sluigi
3498943Sluigichar		*capab;		/* the capability itself */
3598943Sluigi
3698943Sluigiextern char	*getenv();	/* new, improved getenv */
3798943Sluigiextern FILE	*fopen();	/* old fopen */
3898943Sluigi
3998943Sluigi/*
4098943Sluigi *	tgetent - get the termcap entry for terminal name, and put it
4198943Sluigi *	in bp (which must be an array of 1024 chars). Returns 1 if
4298943Sluigi *	termcap entry found, 0 if not found, and -1 if file not found.
4399603Sbde */
4498943Sluigi
4598943Sluigiint
4698943Sluigitgetent(bp, name)
4798943Sluigichar	*bp;
4898943Sluigichar	*name;
4998943Sluigi{
5098943Sluigi	FILE	*fp;
5198943Sluigi	char	*termfile;
5298943Sluigi	char	*cp,
5398943Sluigi		*ptr,		/* temporary pointer */
5498943Sluigi		tmp[1024];	/* buffer for terminal name */
5598943Sluigi	short	len = strlen(name);
5698943Sluigi
5798943Sluigi	capab = bp;
5898943Sluigi
5998943Sluigi	/* Use TERMCAP to override default. */
6098943Sluigi
6198943Sluigi	termfile = getenv("TERMCAP");
6298943Sluigi	if (termfile == NULL ) termfile = "/etc/termcap";
6398943Sluigi
6498943Sluigi	if ((fp = fopen(termfile, "r")) == (FILE *) NULL) {
6598943Sluigi		fprintf(stderr, CGETS(31, 1,
6698943Sluigi		        "Can't open TERMCAP: [%s]\n"), termfile);
6798943Sluigi		fprintf(stderr, CGETS(31, 2, "Can't open %s.\n"), termfile);
68102098Sluigi		sleep(1);
69101628Sluigi		return(-1);
7098943Sluigi	}
7198943Sluigi
7298943Sluigi	while (fgets(bp, 1024, fp) != NULL) {
7398943Sluigi		/* Any line starting with # or NL is skipped as a comment */
7498943Sluigi		if ((*bp == '#') || (*bp == '\n')) continue;
7598943Sluigi
7698943Sluigi		/* Look for lines which end with two backslashes,
7798943Sluigi		and then append the next line. */
7898943Sluigi		while (*(cp = &bp[strlen(bp) - 2]) == '\\')
7998943Sluigi			fgets(cp, 1024, fp);
8098943Sluigi
8198943Sluigi		/* Skip over any spaces or tabs */
8298943Sluigi		for (++cp ; ISSPACE(*cp) ; cp++);
8398943Sluigi
8498943Sluigi		/*  Make sure "name" matches exactly  (efth)  */
8598943Sluigi
8698943Sluigi/* Here we might want to look at any aliases as well.  We'll use
8798943Sluigisscanf to look at aliases.  These are delimited by '|'. */
8898943Sluigi
8998943Sluigi		sscanf(bp,"%[^|]",tmp);
9098943Sluigi		if (strncmp(name, tmp, len) == 0) {
9198943Sluigi			fclose(fp);
9298943Sluigi#ifdef DEBUG
9398943Sluigi	fprintf(stderr, CGETS(31, 3, "Found %s in %s.\n"), name, termfile);
9498943Sluigi	sleep(1);
9598943Sluigi#endif /* DEBUG */
9698943Sluigi			return(1);
9798943Sluigi		}
9898943Sluigi		ptr = bp;
9998943Sluigi		while ((ptr = strchr(ptr,'|')) != NULL) {
10098943Sluigi			ptr++;
10198943Sluigi			if (strchr(ptr,'|') == NULL) break;
10298943Sluigi			sscanf(ptr,"%[^|]",tmp);
10398943Sluigi			if (strncmp(name, tmp, len) == 0) {
10498943Sluigi				fclose(fp);
10598943Sluigi#ifdef DEBUG
10698943Sluigi	fprintf(stderr,CGETS(31, 3, "Found %s in %s.\n"), name, termfile);
10798943Sluigi	sleep(1);
10898943Sluigi#endif /* DEBUG */
10998943Sluigi				return(1);
11098943Sluigi			}
11198943Sluigi		}
11298943Sluigi	}
11398943Sluigi	/* If we get here, then we haven't found a match. */
11498943Sluigi	fclose(fp);
11598943Sluigi#ifdef DEBUG
11698943Sluigi	fprintf(stderr,CGETS(31, 4, "No match found for %s in file %s\n"),
11798943Sluigi		name, termfile);
11898943Sluigi	sleep(1);
11998943Sluigi#endif /* DEBUG */
12098943Sluigi	return(0);
12198943Sluigi
12298943Sluigi}
12398943Sluigi
12498943Sluigi/*
12598943Sluigi *	tgetnum - get the numeric terminal capability corresponding
12698943Sluigi *	to id. Returns the value, -1 if invalid.
12798943Sluigi */
12898943Sluigiint
12998943Sluigitgetnum(id)
13098943Sluigichar	*id;
13198943Sluigi{
13298943Sluigi	char	*cp;
13398943Sluigi	int	ret;
13498943Sluigi
13598943Sluigi	if ((cp = capab) == NULL || id == NULL)
13698943Sluigi		return(-1);
13798943Sluigi	while (*++cp != ':')
13898943Sluigi		;
13998943Sluigi	for (++cp ; *cp ; cp++) {
14098943Sluigi		while (ISSPACE(*cp))
14198943Sluigi			cp++;
14298943Sluigi		if (strncmp(cp, id, CAPABLEN) == 0) {
14398943Sluigi			while (*cp && *cp != ':' && *cp != '#')
14498943Sluigi				cp++;
14598943Sluigi			if (*cp != '#')
14698943Sluigi				return(-1);
14798943Sluigi			for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++)
14898943Sluigi				ret = ret * 10 + *cp - '0';
14998943Sluigi			return(ret);
15098943Sluigi		}
15198943Sluigi		while (*cp && *cp != ':')
15298943Sluigi			cp++;
15398943Sluigi	}
15498943Sluigi	return(-1);
15598943Sluigi}
15698943Sluigi
15798943Sluigi/*
15898943Sluigi *	tgetflag - get the boolean flag corresponding to id. Returns -1
15998943Sluigi *	if invalid, 0 if the flag is not in termcap entry, or 1 if it is
16098943Sluigi *	present.
16198943Sluigi */
16298943Sluigiint
16398943Sluigitgetflag(id)
16498943Sluigichar	*id;
16598943Sluigi{
16698943Sluigi	char	*cp;
16798943Sluigi
16898943Sluigi	if ((cp = capab) == NULL || id == NULL)
16998943Sluigi		return(-1);
17098943Sluigi	while (*++cp != ':')
17198943Sluigi		;
17298943Sluigi	for (++cp ; *cp ; cp++) {
17398943Sluigi		while (ISSPACE(*cp))
17498943Sluigi			cp++;
17598943Sluigi		if (strncmp(cp, id, CAPABLEN) == 0)
17698943Sluigi			return(1);
17798943Sluigi		while (*cp && *cp != ':')
17898943Sluigi			cp++;
17998943Sluigi	}
18098943Sluigi	return(0);
18198943Sluigi}
182101641Sluigi
183101641Sluigi/*
18498943Sluigi *	tgetstr - get the string capability corresponding to id and place
18598943Sluigi *	it in area (advancing area at same time). Expand escape sequences
18698943Sluigi *	etc. Returns the string, or NULL if it can't do it.
18798943Sluigi */
18898943Sluigichar *
18998943Sluigitgetstr(id, area)
19098943Sluigichar	*id;
19198943Sluigichar	**area;
19298943Sluigi{
19398943Sluigi	char	*cp;
19498943Sluigi	char	*ret;
19598943Sluigi	int	i;
19698943Sluigi
19798943Sluigi	if ((cp = capab) == NULL || id == NULL)
19898943Sluigi		return(NULL);
19998943Sluigi	while (*++cp != ':')
20098943Sluigi		;
20198943Sluigi	for (++cp ; *cp ; cp++) {
20298943Sluigi		while (ISSPACE(*cp))
20398943Sluigi			cp++;
20498943Sluigi		if (strncmp(cp, id, CAPABLEN) == 0) {
20598943Sluigi			while (*cp && *cp != ':' && *cp != '=')
20698943Sluigi				cp++;
20798943Sluigi			if (*cp != '=')
20898943Sluigi				return(NULL);
20998943Sluigi			for (ret = *area, cp++; *cp && *cp != ':' ;
21098943Sluigi				(*area)++, cp++)
21198943Sluigi				switch(*cp) {
21298943Sluigi				case '^' :
21398943Sluigi					**area = *++cp - '@'; /* fix (efth)*/
21498943Sluigi					break;
21598943Sluigi				case '\\' :
21698943Sluigi					switch(*++cp) {
21798943Sluigi					case 'E' :
21898943Sluigi						**area = CTL_ESC('\033');
21998943Sluigi						break;
22098943Sluigi					case 'n' :
22198943Sluigi						**area = '\n';
22298943Sluigi						break;
22398943Sluigi					case 'r' :
22498943Sluigi						**area = '\r';
225102087Sluigi						break;
226102087Sluigi					case 't' :
22798943Sluigi						**area = '\t';
22898943Sluigi						break;
229101978Sluigi					case 'b' :
23098943Sluigi						**area = '\b';
23198943Sluigi						break;
23298943Sluigi					case 'f' :
23398943Sluigi						**area = '\f';
23498943Sluigi						break;
23598943Sluigi					case '0' :
23698943Sluigi					case '1' :
23798943Sluigi					case '2' :
23898943Sluigi					case '3' :
23998943Sluigi						for (i=0 ; *cp && ISDIGIT(*cp) ;
24098943Sluigi							 cp++)
24198943Sluigi							i = i * 8 + *cp - '0';
24298943Sluigi						**area = i;
24398943Sluigi						cp--;
24498943Sluigi						break;
24598943Sluigi					case '^' :
24698943Sluigi					case '\\' :
24798943Sluigi						**area = *cp;
248101978Sluigi						break;
24998943Sluigi					}
25098943Sluigi					break;
25198943Sluigi				default :
25298943Sluigi					**area = *cp;
25398943Sluigi				}
25498943Sluigi			*(*area)++ = '\0';
25598943Sluigi			return(ret);
25698943Sluigi		}
25798943Sluigi		while (*cp && *cp != ':')
25898943Sluigi			cp++;
25998943Sluigi	}
26098943Sluigi	return(NULL);
26198943Sluigi}
26298943Sluigi
26398943Sluigi/*
26499475Sluigi *	tgoto - given the cursor motion string cm, make up the string
26598943Sluigi *	for the cursor to go to (destcol, destline), and return the string.
26698943Sluigi *	Returns "OOPS" if something's gone wrong, or the string otherwise.
26798943Sluigi */
26898943Sluigichar *
26998943Sluigitgoto(cm, destcol, destline)
27098943Sluigichar	*cm;
27198943Sluigiint	destcol;
27298943Sluigiint	destline;
27398943Sluigi{
27498943Sluigi	register char	*rp;
27598943Sluigi	static char	ret[24];
27698943Sluigi	int		incr = 0;
27798943Sluigi	int 		argno = 0, numval;
27898943Sluigi
27998943Sluigi	for (rp = ret ; *cm ; cm++) {
28098943Sluigi		switch(*cm) {
28198943Sluigi		case '%' :
28298943Sluigi			switch(*++cm) {
28398943Sluigi			case '+' :
28498943Sluigi				numval = (argno == 0 ? destline : destcol);
28598943Sluigi				argno = 1 - argno;
28698943Sluigi				*rp++ = numval + incr + *++cm;
28799475Sluigi				break;
28898943Sluigi
28998943Sluigi			case '%' :
29098943Sluigi				*rp++ = '%';
29198943Sluigi				break;
29298943Sluigi
29398943Sluigi			case 'i' :
29498943Sluigi				incr = 1;
29598943Sluigi				break;
29698943Sluigi
29798943Sluigi			case 'd' :
29898943Sluigi				numval = (argno == 0 ? destline : destcol);
29998943Sluigi				numval += incr;
30098943Sluigi				argno = 1 - argno;
30198943Sluigi				*rp++ = '0' + (numval/10);
30298943Sluigi				*rp++ = '0' + (numval%10);
30398943Sluigi				break;
30498943Sluigi
30598943Sluigi			case 'r' :
30698943Sluigi				argno = 1;
30798943Sluigi				break;
30898943Sluigi			}
30998943Sluigi
31098943Sluigi			break;
31198943Sluigi		default :
31298943Sluigi			*rp++ = *cm;
31398943Sluigi		}
31498943Sluigi	}
31598943Sluigi	*rp = '\0';
31698943Sluigi	return(ret);
31798943Sluigi}
31898943Sluigi
31998943Sluigi/*
32098943Sluigi *	tputs - put the string cp out onto the terminal, using the function
32198943Sluigi *	outc. This should do padding for the terminal, but I can't find a
32298943Sluigi *	terminal that needs padding at the moment...
32398943Sluigi */
32498943Sluigiint
32598943Sluigitputs(cp, affcnt, outc)
32699909Sluigiregister char	*cp;
32798943Sluigiint		affcnt;
328102087Sluigiint		(*outc)();
329102087Sluigi{
330102087Sluigi	if (cp == NULL)
331102087Sluigi		return(1);
332102087Sluigi	/* do any padding interpretation - left null for MINIX just now */
333102087Sluigi	while (*cp)
334102087Sluigi		(*outc)(*cp++);
335102087Sluigi	return(1);
33698943Sluigi}
33798943Sluigi#endif /* _VMS_POSIX */
33898943Sluigi