352 lines
10 KiB
C
352 lines
10 KiB
C
/*
|
|
* $QNXLicenseC:
|
|
* Copyright 2007, QNX Software Systems. All Rights Reserved.
|
|
*
|
|
* You must obtain a written license from and pay applicable license fees to QNX
|
|
* Software Systems before you may reproduce, modify or distribute this software,
|
|
* or any work that includes all or part of this software. Free development
|
|
* licenses are available for evaluation and non-commercial purposes. For more
|
|
* information visit http://licensing.qnx.com or email licensing@qnx.com.
|
|
*
|
|
* This file may contain contributions from others. Please review this entire
|
|
* file for other proprietary rights or license notices, as well as the QNX
|
|
* Development Suite License Guide at http://licensing.qnx.com/license-guide/
|
|
* for other information.
|
|
* $
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <process.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/wait.h>
|
|
#ifdef __QNXNTO__
|
|
#include <spawn.h>
|
|
#include <termios.h>
|
|
#else
|
|
#include <sys/qnx_glob.h>
|
|
#endif
|
|
|
|
static char *tent; /* pointer to termcap buffer */
|
|
|
|
/* Build in the most common terminals */
|
|
char *ansi_termcap =
|
|
"ansi|generic ansi standard terminal:"
|
|
" :am:xo:"
|
|
" :co#80:li#33:"
|
|
" :bt=\\E[Z:bl=^g:cr=\\r:ct=\\E[2g:cl=\\E[H\\E[J:ce=\\E[K:cd=\\E[J:"
|
|
" :ch=\\E[%p1%{1}%+%dG:cm=\\E[%i%d;%dH:ho=\\E[H:le=\\b:nd=\\E[C:"
|
|
" :up=\\E[A:dc=\\E[P:dl=\\E[M:mb=\\E[5m:md=\\E[1m:mk=\\E[8m:mr=\\E[7m:"
|
|
" :so=\\E[7m:us=\\E[4m:me=\\E[0m:se=\\E[m:ue=\\E[m:ic=\\E[@:al=\\E[L:"
|
|
" :kb=\\b:kd=\\E[B:kh=\\E[H:kl=\\E[D:kr=\\E[C:ku=\\E[A:DL=\\E[%dM:"
|
|
" :DO=\\E[%dB:IC=\\E[%d@:AL=\\E[%dL:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:"
|
|
" :rp=%.\\E[%p2%{1}%-%db:cv=\\E[%p1%{1}%+%dd:"
|
|
" :sa=\\E[%?%p1%t7;%;%?%p2%t4;%;%?%p3%t7;%;%?%p4%t5;%;%?%p6%t1;%;m:"
|
|
" :st=\\EH:ta=\\t:"
|
|
" :kN=\\E[U:kP=\\E[V:";
|
|
|
|
#ifndef __QNXNTO__
|
|
char *qnx_termcap =
|
|
"qnx|qnx4|qnx console:"
|
|
" :km:mi:ms:xt:YA:YC:"
|
|
" :co#80:it#4:li#33:Co#8:pa#64:NC#3:"
|
|
" :bl=^g:cr=\\r:cl=\\EH\\EJ:ce=\\EK:cd=\\EJ:cm=\\EY%+ %+ :do=\\l:"
|
|
" :ho=\\EH:vi=\\Ey0:le=\\b:ve=\\Ey1:nd=\\EC:up=\\EA:vs=\\Ey2:dc=\\Ef:"
|
|
" :dl=\\EF:mb=\\E{:md=\\E<:ti=\\Ei:mr=\\E(:so=\\E(:us=\\E[:"
|
|
" :me=\\E}\\E]\\E>\\E):te=\\Eh\\ER:se=\\E):ue=\\E]:ic=\\Ee:al=\\EE:"
|
|
" :ka=\\377\\344:kC=\\377\\341:kt=\\377\\237:kD=\\377\\254:kL=\\377\\274:"
|
|
" :kd=\\377\\251:kM=\\377\\313:kE=\\377\\310:kS=\\377\\314:"
|
|
" :kh=\\377\\240:"
|
|
" :kI=\\377\\253:kA=\\377\\273:kl=\\377\\244:kN=\\377\\252:kP=\\377\\242:"
|
|
" :kr=\\377\\246:kF=\\377\\261:kR=\\377\\271:kT=\\377\\342:ku=\\377\\241:"
|
|
" :rp=\\Eg%+ %.:r1=\\ER:sf=\\l:sr=\\EI:"
|
|
" :sa=%?%p1%t\\E<%;%p2%t\\E[%;%p3%t\\E(%;%p4%t\\E{%;%p6%t\\E<%;:"
|
|
" :ta=\\t:"
|
|
" :ac=l\\332m\\300k\\277j\\331q\\304x\\263u\\264t\\303n\\305v\\301w\\302O\\333a\\261o\\337s\\334:"
|
|
" :kB=\\377\\200:"
|
|
" :F1=\\377\\256:F2=\\377\\257:F3=\\377\\213:"
|
|
" :F4=\\377\\214:F5=\\377\\215:F6=\\377\\216:F7=\\377\\217:F8=\\377\\220:"
|
|
" :F9=\\377\\221:FA=\\377\\222:" \
|
|
" :op=\\ER:Sf=\\E@%p1%Pf%gb%gf%d%d:Sb=\\E@%p1%Pb%gb%gf%d%d:"
|
|
" :Zc=\\E!%d:";
|
|
#else
|
|
char *qansi_termcap =
|
|
"qansi|qansi-m|qansi-8859m|QNX ANSI:am:G0:co#80:it#8:li#25:ti=\\E[?7h:"
|
|
" :AL=\\E[%dL:DC=\\E[%dP:DL=\\E[%dM:DO=\\E[%dB:IC=\\E[%d@:LE=\\E[%dD:"
|
|
" :RA=\\E[?7l:RI=\\E[%dC:SA=\\E[?7h:SF=\\E[%dS:SR=\\E[%dT:UP=\\E[%dA:"
|
|
" :ae=^O:al=\\E[L:as=^N:bt=\\E[Z:cb=\\E[K\\E[X:cd=\\E[J:ce=\\E[K:ch=\\E[%i%dG:"
|
|
" :cl=\\E[2J\\E[H:cm=\\E[%i%d;%dH:cs=\\E[%i%d;%dr:ct=\\E[2g:dc=\\E[P:dl=\E[M:\"o=\\E[B:"
|
|
" :ec=\\E[%dX:ho=\\E[H:ic=\\E[@:is=\\E[?7h\\E[0;10;39;49m:"
|
|
" :k1=\\EOP:k2=\\EOQ:k3=\\EOR:k4=\\EOS:k5=\\EOT:k6=\\EOU:k7=\\EOV:k8=\\EOW:k9=\\EOX:"
|
|
" :k;=\\EOY:kB=\\E[Z:kC=\\ENa:kD=\\E[P:kF=\\E[a:kI=\\E[@:kN=\\E[U:kP=\\E[V:kR=\\E[b:kT=\\ENb:"
|
|
" :ka=\\ENd:kb=\\177:kd=\\E[B:kh=\\E[H:kl=\\E[D:kr=\\E[C:ku=\\E[A:"
|
|
" :le=\\E[D:ll=\\E[99H:mb=\\E[5m:md=\\E[1m:me=\\E[m^O:mh=\\E[2m:mk=\\E[9m:mr=\\E[7m:"
|
|
" :nd=\\E[C:nw=\\EE:op=\\E[39;49m:rp=%.\\E[%p2%{1}%-%db:"
|
|
" :se=\\E[27m:sf=\\E[S:so=\\E[7m:sr=\\E[T:st=\\EH:ue=\\E[24m:up=\\E[A:us=\\E[4m:"
|
|
" :ac=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~:"
|
|
" :vb=\\E[?5h\\E[?5l:ve=\\E[?25h\\E[?12l:vi=\\E[?25l:"
|
|
" :ws=\\E[5m:we=\\E[m:bo=\\E[1m:be=\\E[m:";
|
|
#endif
|
|
|
|
/* search for capability within terminal entry */
|
|
static char *getcap(const char *cp) {
|
|
char *tp;
|
|
|
|
/* assert we did tgetent(), and that cp is a two-character capability */
|
|
if ((tp = tent) == 0 || cp == 0 || cp[0] == 0 || cp[1] == 0)
|
|
return 0;
|
|
for (;;) {
|
|
while (*tp && *tp++ != ':');
|
|
if (*tp == 0) break;
|
|
#if defined(__ARM__)
|
|
if (tp[0] == cp[0] && tp[1] == cp[1])
|
|
#else
|
|
if (*(short *) tp == *(short *) cp)
|
|
#endif
|
|
return tp;
|
|
}
|
|
return 0; /* capability not found */
|
|
}
|
|
|
|
/*
|
|
* tgetent - get the termcap entry for terminal name, and put it
|
|
* in bp (which must be an array of 1024 chars). Returns 1 if
|
|
* termcap entry found, 0 if not found, and -1 if file not found.
|
|
*/
|
|
int tgetent(char *bp, const char *term) {
|
|
char *tc, *cp;
|
|
char tn[16];
|
|
FILE *fp;
|
|
|
|
if (term == 0) return 0;
|
|
|
|
/*
|
|
* If $TERMCAP does not begin with / it is assumed to
|
|
* already contain the terminal capability description
|
|
*
|
|
* What happens if this contains a tc reference?
|
|
*/
|
|
tent = bp; /* point to termcap buffer */
|
|
if (tc = getenv("TERMCAP")) {
|
|
if (*tc != '/' && (cp = getenv("TERM")) && strcmp(term, cp) == 0) {
|
|
(void) strcpy(bp, tc);
|
|
return 1;
|
|
}
|
|
}
|
|
#ifndef __QNXNTO__
|
|
else if((cp = getenv("TERM")) && strstr(cp, "ansi")) {
|
|
(void) strcpy(bp, ansi_termcap);
|
|
return 1;
|
|
}
|
|
else if(cp && strstr(cp, "qnx")) {
|
|
(void) strcpy(bp, qnx_termcap);
|
|
return 1;
|
|
}
|
|
#else
|
|
else if((cp = getenv("TERM")) && strstr(cp, "qansi")) {
|
|
(void) strcpy(bp, qansi_termcap);
|
|
return 1;
|
|
}
|
|
else if(cp && strstr(cp, "ansi")) {
|
|
(void) strcpy(bp, ansi_termcap);
|
|
return 1;
|
|
}
|
|
#endif
|
|
else
|
|
tc = "/etc/termcap";
|
|
|
|
strcpy(tn, term);
|
|
/* open the termcap database */
|
|
if (fp = fopen(tc, "r")) {
|
|
int c, last = 0;
|
|
|
|
for (bp = (tc = tent) - 1; (c = fgetc(fp)) != EOF; *++bp = last = c)
|
|
if (c == '\n')
|
|
if (last == '\\') {
|
|
/* skip leading whitespace after escaped newline */
|
|
while ((c = fgetc(fp)) != EOF && (c == ' ' || c == '\t'));
|
|
--bp;
|
|
} else {
|
|
/* nul terminate completed terminal description */
|
|
*++bp = 0, cp = tc;
|
|
do { /* check if any terminal names match */
|
|
for (c = 0; tn[c] && tn[c] == *cp; cp++, c++);
|
|
if (tn[c] == 0 && (*cp == '|' || *cp == ':')) {
|
|
/* return if no terminal continuation */
|
|
if ((cp = getcap("tc")) == 0 || cp[2] != '=') {
|
|
fclose(fp);
|
|
return 1;
|
|
}
|
|
tc = cp, cp += 3; /* skip tc= */
|
|
/* copy new terminal name into tn */
|
|
for (c = 0; cp[c] != ':' && (tn[c] = cp[c]); c++);
|
|
tn[c] = 0;
|
|
rewind(fp);
|
|
break; /* terminal continuation */
|
|
}
|
|
/* skip to next terminal name */
|
|
while (*cp && *cp != '|' && *cp != ':') cp++;
|
|
} while (*cp++ == '|');
|
|
c = fgetc(fp);
|
|
bp = tc - 1;
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
{
|
|
pid_t kid;
|
|
int fd[2];
|
|
int n;
|
|
|
|
if (pipe(fd) == 0) {
|
|
static char *argv[] = { "infocmp", "-C", 0, 0 };
|
|
argv[2] = (char *) term;
|
|
fcntl(fd[0], F_SETFD, FD_CLOEXEC);
|
|
fcntl(fd[1], F_SETFD, FD_CLOEXEC);
|
|
{
|
|
#ifdef __QNXNTO__
|
|
struct inheritance inherit;
|
|
memset(&inherit, 0, sizeof(inherit));
|
|
kid = spawnp(argv[0], 3, fd, &inherit, argv, environ);
|
|
#else
|
|
qnx_spawn_options.iov[1] = fd[1];
|
|
kid = spawnvp(P_NOWAIT, argv[0], argv);
|
|
#endif
|
|
}
|
|
if (kid != -1 && waitpid(kid, &n, 0) != -1 && n == 0) {
|
|
n = read(fd[0], tent, 1024);
|
|
close(fd[0]), close(fd[1]);
|
|
for (bp = tent + n; bp >= tent && *--bp != ':';);
|
|
*++bp = '\0';
|
|
return 1;
|
|
}
|
|
close(fd[0]), close(fd[1]);
|
|
}
|
|
}
|
|
|
|
tent = 0; /* no valid termcap */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* tgetflag - get the boolean flag corresponding to id. Returns -1
|
|
* if invalid, 0 if the flag is not in termcap entry, or 1 if it is
|
|
* present.
|
|
*/
|
|
int tgetflag(const char *id) {
|
|
char *cp = getcap(id);
|
|
|
|
return cp && cp[2] != '@' ? 1 : 0;
|
|
}
|
|
|
|
|
|
static int num_cols() {
|
|
int col;
|
|
|
|
#ifdef __QNXNTO__
|
|
if ( tcgetsize( 1, NULL, &col ) == 0 && col )
|
|
return col;
|
|
#else
|
|
int dev_size();
|
|
if (dev_size(1, -1, -1, (int *) 0, &col) == 0 && col)
|
|
return col;
|
|
#endif
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
static int num_lines() {
|
|
int lin;
|
|
|
|
#ifdef __QNXNTO__
|
|
if ( tcgetsize( 1, &lin, NULL ) == 0 && lin )
|
|
return lin;
|
|
#else
|
|
int dev_size();
|
|
if (dev_size(1, -1, -1, &lin, (int *) 0) == 0 && lin)
|
|
return lin;
|
|
#endif
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* tgetnum - get the numeric terminal capability corresponding
|
|
* to id. Returns the value, -1 if invalid.
|
|
*/
|
|
int tgetnum(const char *id) {
|
|
char *cp;
|
|
|
|
if (id[0] == 'l' && id[1] == 'i') {
|
|
int lines;
|
|
|
|
if (cp = getenv("LINES"))
|
|
return atoi(cp);
|
|
else if (lines = num_lines())
|
|
return lines;
|
|
} else if (id[0] == 'c' && id[1] == 'o') {
|
|
int columns;
|
|
|
|
if (cp = getenv("COLUMNS"))
|
|
return atoi(cp);
|
|
else if (columns = num_cols())
|
|
return columns;
|
|
}
|
|
cp = getcap(id);
|
|
return cp && cp[2] == '#' ? atoi(cp + 3) : -1;
|
|
}
|
|
|
|
/*
|
|
* tgetstr - get the string capability corresponding to id and place
|
|
* it in area (advancing area at same time). Expand escape sequences
|
|
* etc. Returns the string, or NULL if it can't do it.
|
|
*/
|
|
char *tgetstr(const char *id, char **area) {
|
|
char *cp = getcap(id);
|
|
char *wsp, *ret;
|
|
int c;
|
|
|
|
if (cp == 0 || cp[2] != '=') return 0;
|
|
|
|
cp += 3, ret = wsp = *area;
|
|
while ((c = *cp++) && c != ':') {
|
|
switch (c) {
|
|
default: *wsp = c; break;
|
|
case '^':
|
|
switch (c = *cp++) {
|
|
case '?': *wsp = '\177'; break;
|
|
default: *wsp = c & 037; break;
|
|
} break;
|
|
case '\\':
|
|
switch (c = *cp++) {
|
|
default: *wsp = c; break;
|
|
case 'E': *wsp = '\033'; break;
|
|
case 'a': *wsp = '\a'; break;
|
|
case 'b': *wsp = '\b'; break;
|
|
case 'f': *wsp = '\f'; break;
|
|
case 'l': *wsp = 0x0a; break;
|
|
case 'n': *wsp = '\n'; break;
|
|
case 'r': *wsp = '\r'; break;
|
|
case 't': *wsp = '\t'; break;
|
|
case '0': case '1': case '2': case '3':
|
|
case '4': case '5': case '6': case '7':
|
|
*wsp = c - '0';
|
|
while ((c = *cp) && '0' <= c && c <= '7')
|
|
*wsp = *wsp * 8 + *cp++ - '0';
|
|
break;
|
|
}
|
|
}
|
|
wsp++;
|
|
}
|
|
*wsp++ = 0;
|
|
*area = wsp;
|
|
return ret;
|
|
}
|