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