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