/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* NAME
* captoinfo - convert a termcap description to a terminfo description
*
* SYNOPSIS
* captoinfo [-1vV] [-w width] [ filename ... ]
*
* AUTHOR
* Tony Hansen, January 22, 1984.
*/
#include "curses.h"
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "otermcap.h"
#include "print.h"
/* extra termcap variables no longer in terminfo */
char *oboolcodes[] =
{
"bs", /* Terminal can backspace with "^H" */
"nc", /* No correctly working carriage return (DM2500,H2000) */
"ns", /* Terminal is a CRT but does not scroll. */
"pt", /* Has hardware tabs (may need to be set with "is") */
"MT", /* Has meta key, alternate code. */
"xr", /* Return acts like ce \r \n (Delta Data) */
0
};
char *onumcodes[] =
{
"dB", /* Number of millisec of bs delay needed */
"dC", /* Number of millisec of cr delay needed */
"dF", /* Number of millisec of ff delay needed */
"dN", /* Number of millisec of nl delay needed */
"dT", /* Number of millisec of tab delay needed */
"ug", /* Number of blank chars left by us or ue */
/* Ignore the 'kn' number. It was ill-defined and never used. */
"kn", /* Number of "other" keys */
0
};
char *ostrcodes[] =
{
"bc", /* Backspace if not "^H" */
"ko", /* Termcap entries for other non-function keys */
"ma", /* Arrow key map, used by vi version 2 only */
"nl", /* Newline character (default "\n") */
"rs", /* undocumented reset string, like is (info is2) */
/* Ignore the 'ml' and 'mu' strings. */
"ml", /* Memory lock on above cursor. */
"mu", /* Memory unlock (turn off memory lock). */
0
};
#define numelements(x) (sizeof (x)/sizeof (x[0]))
/* externs from libcurses.a */
/* globals for this file */
/* globals dealing with the environment */
extern char **environ;
#else
#endif /* SYSV || USG */
/* dynamic arrays */
/* data buffers */
/* flags */
static void getlongname(void);
static void handleko(void);
static void handlema(void);
static void print_no_use_entry(void);
static void print_use_entry(char *);
static void captoinfo(void);
static void use_etc_termcap(void);
static void initdirname(void);
static void setfilename(char *);
static void setterm_name(void);
static void use_file(char *);
static void sorttable(char *[], char *[]);
static void inittables(void);
/*
* Verify that the names given in the termcap entry are all valid.
*/
int
{
return (1);
return (1);
return (0);
}
void
{
for (;;) {
tbuf++;
if (*tbuf == 0)
return;
/* commented out entry? */
if (*tbuf == '.') {
if (verbose)
"%s: TERM=%s: commented out code '%.2s' "
tbuf+1);
continue;
}
if (verbose)
"'%.2s'.\n", tbuf);
switch (tbuf[2]) {
default:
"%s: TERM=%s: unknown type given for the "
"termcap code '%.2s'.\n", progname,
}
if (verbose > 1)
/* look for the name in bools */
"%s: TERM=%s: wrong type given for the "
"boolean termcap code '%.2s'.\n", progname,
continue;
}
/* look for the name in nums */
"%s: TERM=%s: wrong type given for the "
"numeric termcap code '%.2s'.\n", progname,
continue;
}
/* look for the name in strs */
"%s: TERM=%s: wrong type given for the "
"string termcap code '%.2s'.\n", progname,
continue;
}
"%s: TERM=%s: the %s termcap code '%.2s' is not a valid "
}
}
/*
* Fill up the termcap tables.
*/
int
filltables(void)
{
int i, tret;
/* Retrieve the termcap entry. */
"%s: TERM=%s: tgetent failed with return code %d (%s).\n",
(tret == 0) ? "non-existent or invalid entry" :
return (0);
}
if (verbose) {
}
if (uselevel == 0)
checktermcap();
/* Retrieve the values that are in terminfo. */
/* booleans */
for (i = 0; boolcodes[i]; i++) {
if (verbose > 1) {
}
}
/* numbers */
for (i = 0; numcodes[i]; i++) {
if (verbose > 1) {
}
}
if (uselevel == 0)
/* strings */
for (i = 0; strcodes[i]; i++) {
if (verbose > 1) {
}
else
}
/* remove zero length strings */
"%s: TERM=%s: cap %s (info %s) is NULL: REMOVED\n",
}
}
/* Retrieve the values not found in terminfo anymore. */
/* booleans */
for (i = 0; oboolcodes[i]; i++) {
if (verbose > 1) {
oboolcodes[i]);
}
}
/* numbers */
for (i = 0; onumcodes[i]; i++) {
if (verbose > 1) {
}
}
/* strings */
for (i = 0; ostrcodes[i]; i++) {
if (verbose > 1) {
}
else
}
/* remove zero length strings */
"%s: TERM=%s: cap %s (no terminfo name) is NULL: "
}
}
return (1);
}
/*
* This routine copies the set of names from the termcap entry into
* a separate buffer, getting rid of the old obsolete two character
* names.
*/
static void
getlongname(void)
{
char *b = &bp[0], *l = buflongname;
/* Skip the two character name */
b = &bp[3];
/* Copy the rest of the names */
while (*b && *b != ':')
*l++ = *b++;
*l = '\0';
if (b != &bp[0]) {
}
}
/*
* Return the value of the termcap string 'capname' as stored in our list.
*/
char *
{
int i;
if (verbose > 1)
capname);
/* Check the old termcap list. */
for (i = 0; ostrcodes[i]; i++)
if (verbose > 1) {
}
}
if (verbose > 1)
"ostrcodes.\n", capname);
/* Check the terminfo list. */
for (i = 0; strcodes[i]; i++)
if (verbose > 1) {
}
}
return ((char *)NULL);
}
/*
* Search for a name in the given table and
* return the index.
* Someday I'll redo this to use bsearch().
*/
/* ARGSUSED */
int
{
#ifndef BSEARCH
int i;
return (i);
return (-1);
#else /* this doesn't work for some reason */
char **bret;
sizeof (char *), strcmp);
return (-1);
else
#endif /* OLD */
}
/*
* return the value of the terminfo string 'infoname'
*/
char *
{
int i;
if (verbose > 1)
infoname);
if (i != -1) {
if (verbose > 1) {
}
}
if (verbose > 1)
infoname);
return ((char *)NULL);
}
/*
* Replace the value stored for the terminfo boolean
* capability 'infoname' with the newvalue.
*/
void
{
int i;
if (verbose > 1)
if (i != -1) {
if (verbose > 1)
return;
}
}
/*
* Replace the value stored for the terminfo number
* capability 'infoname' with the newvalue.
*/
void
{
int i;
if (verbose > 1)
if (i != -1) {
if (verbose > 1)
return;
}
"found!\n",
}
/*
* replace the value stored for the terminfo string capability 'infoname'
* with the newvalue.
*/
void
{
int i;
if (verbose > 1) {
}
if (i != -1) {
if (verbose > 1) {
}
while (*newvalue)
*nextstring++ = *newvalue++;
*nextstring++ = '\0';
return;
}
"found!\n",
}
/*
* Add in extra delays if they are not recorded already.
* This is done before the padding information has been modified by
* changecalculations() below, so the padding information, if there
* already, is still at the beginning of the string in termcap format.
*/
void
{
char *cap;
/* Is there padding to add? */
if (cappadding > 0)
/* Is there a string to add it to? */
/* Is there any padding info already? */
/* EMPTY */;
/* Assume that the padding info that is there is correct. */
} else {
/* Add the padding at the end of the present string. */
} else {
/* Create a new string that only has the padding. */
}
}
struct
{
char *capname;
char *keyedinfoname;
} ko_map[] = {
"al", "kil1",
"bs", "kbs", /* special addition */
"bt", "kcbt",
"cd", "ked",
"ce", "kel",
"cl", "kclr",
"ct", "ktbc",
"dc", "kdch1",
"dl", "kdl1",
"do", "kcud1",
"ei", "krmir",
"ho", "khome",
"ic", "kich1",
"im", "kich1", /* special addition */
"le", "kcub1",
"ll", "kll",
"nd", "kcuf1",
"sf", "kind",
"sr", "kri",
"st", "khts",
"up", "kcuu1",
/* "", "kctab", */
/* "", "knp", */
/* "", "kpp", */
0, 0
};
/*
* Work with the ko string. It is a comma separated list of keys for which
* the keyboard has a key by the same name that emits the same sequence.
* For example, ko = dc, im, ei means that there are keys called
* delete-character, enter-insert-mode and exit-insert-mode on the keyboard,
* and they emit the same sequences as specified in the dc, im and ei
* capabilities.
*/
static void
handleko(void)
{
char *capstr;
int i, j, found;
char *infostr;
if (verbose > 1)
return;
/* isolate the termcap name */
break;
i++;
if (verbose > 1) {
}
/* match it up into our list */
found = 0;
if (verbose > 1)
/* add the value to our database */
(ko_map[j].keyedinfoname);
/* skip any possible padding */
/* information */
capstr++;
} else
"%s: TERM=%s: a function "
"key for '%s' was "
"specified with the "
"value ", progname,
", but it already has the "
"value '");
}
}
found = 1;
}
}
if (!found) {
capname);
"termcap capability.\n");
}
}
}
struct
{
char vichar;
char *keyedinfoname;
} ma_map[] = {
'j', "kcud1",
'k', "kcuu1",
'h', "kcub1", /* left */
' ', "kcuf1", /* right */
'l', "kcuf1",
'H', "khome", /* home */
0, 0
};
/*
* Work with the ma string. This is a list of pairs of characters.
* The first character is the what a function key sends. The second
* character is the equivalent vi function that should be done when
* it receives that character. Note that only function keys that send
* a single character could be defined by this list.
*/
void
{
xbuf[0] = c;
}
static void
handlema(void)
{
char vichar;
int i, j, found;
char *infostr;
if (verbose > 1)
return;
/* isolate the key's value */
if (verbose > 1) {
}
break;
/* isolate the vi key name */
if (verbose > 1) {
}
/* match up the vi name in our list */
found = 0;
if (verbose > 1) {
"character '");
}
"the vi character '", progname,
"' (info '%s') has the value '",
ma_map[j].keyedinfoname);
"gives '");
}
found = 1;
}
}
if (!found) {
progname);
"capability.\n");
}
}
}
/*
* Many capabilities were defaulted in termcap which must now be explicitly
* given. We'll assume that the defaults are in effect for this terminal.
*/
void
adddefaults(void)
{
char *cap;
int sg;
if (verbose > 1)
/* cr was assumed to be ^M, unless nc was given, */
/* which meant it could not be done. */
/* Also, xr meant that ^M acted strangely. */
else
/* cursor down was assumed to be ^J if not specified by nl */
else
/* ind was assumed to be ^J, unless ns was given, */
/* which meant it could not be done. */
else
/* bel was assumed to be ^G */
/* if bs, then could do backspacing, */
/* with value of bc, default of ^H */
else
/* default xon to true */
if (!otgetflag("xo"))
/* if pt, then hardware tabs are allowed, */
/* with value of ta, default of ^I */
else
/* The dX numbers are now stored as padding */
/* in the appropriate terminfo string. */
/* The ug and sg caps were essentially identical, */
/* so ug almost never got used. We set sg from ug */
/* if it hasn't already been set. */
"%s: TERM=%s: Warning: termcap sg and ug had different "
/* The MT boolean was never really part of termcap, */
/* but we can check for it anyways. */
/* the rs string was renamed r2 (info rs2) */
handleko();
handlema();
}
/*
* add the string to the string table
*/
char *
{
while (*str)
return (to);
}
/* If there is no padding info or parmed strings, */
/* then we do not need to copy the string. */
int
{
/* any string at all? */
return (0);
/* any padding info? */
return (1);
/* any parmed info? */
while (*string)
if (*string++ == '%')
return (1);
return (0);
}
/*
* Certain manipulations of the stack require strange manipulations of the
* values that are on the stack. To handle these, we save the values of the
* parameters in registers at the very beginning and make the changes in
* the registers. We don't want to do this in the general case because of the
* potential performance loss.
*/
int
{
int parmset = 0;
while (*string)
if (*string++ == '%') {
switch (*string) {
/* These manipulate just the top value on */
/* the stack, so we only have to do */
/* something strange if a %r follows. */
case '>': case 'B': case 'D':
parmset = 1;
break;
/* If the parm has already been been */
/* pushed onto the stack by %>, then we */
/* can not reverse the parms and must get */
/* them from the registers. */
case 'r':
if (parmset)
return (1);
break;
/* This manipulates both parameters, so we */
/* cannot just do one and leave the value */
/* on the stack like we can with %>, */
/* %B or %D. */
case 'n':
return (1);
}
string++;
}
return (0);
}
/*
* Change old style of doing calculations to the new stack style.
* Note that this will not necessarily produce the most efficient string,
* but it will work.
*/
void
{
int i, currentparm;
int ch;
for (i = 0; strnames[i]; i++)
if (verbose) {
"was:", strnames [i]);
}
currentparm = 1;
parmset = 0;
/* Handle padding information. Save it so that it can be */
/* placed at the end of the string where it should */
/* have been in the first place. */
if (*from == '*')
caddch('>');
caddch('\0');
} else
padding[0] = '\0';
parmsaved = 1;
"%s: TERM=%s: Warning: the string "
"produced for '%s' may be inefficient.\n",
"looked at by hand.\n");
} else
parmsaved = 0;
if (ch != '%')
else
case '.': /* %. -> %p1%c */
case 'd': /* %d -> %p1%d */
case '2': /* %2 -> %p1%2.2d */
case '3': /* %3 -> %p1%3.3d */
case '+':
/* %+x -> %p1%'x'%+%c */
case '>':
/* %>xy -> %p1%Pc%?%'x'%> */
/* %t%gc%'y'%+ */
/* if current value > x, then add y. */
/* No output. */
case 'B':
/* %B: BCD */
/* (16*(x/10))+(x%10) */
/* No output. */
/* (Adds Regent 100) */
case 'D':
/* %D: Reverse coding */
/* (x-2*(x%16)) */
/* No output. */
/* (Delta Data) */
if (!parmset)
if (parmsaved) {
if (currentparm == 1)
caddch('a');
else
caddch('b');
} else {
if (currentparm == 1)
caddch('1');
else
caddch('2');
}
parmset = 0;
switch (ch) {
case '.':
break;
case 'd':
break;
case '2': case '3':
#ifdef USG /* Vr2==USG, Vr3==SYSV. Use %02d for Vr2, %2.2d for Vr3 */
caddch('%');
caddch('0');
#else
caddch('%');
caddch('.');
#endif /* USG vs. SYSV */
caddch('d');
break;
case '+':
"'%+%c");
break;
case '>':
"%Pc%?%'");
"'%>%t%gc%'");
"'%+");
parmset = 1;
break;
case 'B':
"%Pc%gc%{10}%/%{16}%*%gc%{10}%m%+");
parmset = 1;
break;
case 'D':
"%Pc%gc%gc%{16}%m%{2}%*%-");
parmset = 1;
break;
}
break;
/* %r reverses current parameter */
case 'r':
break;
/* %n: exclusive-or row AND column */
/* with 0140, 96 decimal, no output */
/* (Datamedia 2500, Exidy Sorceror) */
case 'n':
"%ga%'`'%^%Pa");
"%gb%'`'%^%Pb");
break;
/* assume %x means %x */
/* this includes %i and %% */
default:
caddch('%');
}
caddch('\0');
if (verbose) {
}
}
nextstring = to;
}
static void
print_no_use_entry(void)
{
int i;
pr_bheading();
for (i = 0; boolcodes[i]; i++)
if (boolval[0][i])
pr_bfooting();
pr_sheading();
for (i = 0; numcodes[i]; i++)
if (numval[0][i] > -1)
numval[0][i]);
pr_nfooting();
pr_sheading();
for (i = 0; strcodes[i]; i++)
if (strval[0][i])
strval[0][i]);
pr_sfooting();
}
static void
{
int i;
pr_bheading();
for (i = 0; boolcodes[i]; i++)
pr_bfooting();
pr_nheading();
for (i = 0; numcodes[i]; i++)
numval[0][i]);
pr_nfooting();
pr_sheading();
for (i = 0; strcodes[i]; i++)
/* print out str[0] if: */
/* str[0] != NULL and str[1] == NULL, or str[0] != str[1] */
strval[0][i]);
/* print out @ if str[0] == NULL and str[1] != NULL */
(char *)0);
pr_sfooting();
}
static void
captoinfo(void)
{
char *sterm_name;
progname);
return;
}
if (verbose)
uselevel = 0;
if (filltables() == 0)
return;
getlongname();
adddefaults();
if (TLHtcfound != 0) {
uselevel = 1;
if (verbose)
if (filltables() == 0)
return;
adddefaults();
} else
}
#include <signal.h> /* use this file to determine if this is SVR4.0 system */
static void
use_etc_termcap(void)
{
if (verbose)
#ifdef SIGSTOP
#else /* SIGSTOP */
#endif /* SIGSTOP */
captoinfo();
}
static void
initdirname(void)
{
#else
#endif /* SYSV || USG */
if (verbose)
}
static void
{
if (capfile [0] == '/')
"TERMCAP=%s", capfile);
else
if (verbose)
TERMCAP);
}
static void
setterm_name(void)
{
if (verbose)
"for TERM=%s.\n", term_name);
}
/* Look at the current line to see if it is a list of names. */
/* If it is, return the first name in the list, else NULL. */
/* As a side-effect, comment lines and blank lines */
/* are copied to standard output. */
char *
{
if (verbose)
/* Copy comment lines out. */
if (*line == '#') {
if (copycomments)
}
/* Blank lines get copied too. */
if (copycomments) {
break;
if (*lineptr == '\0')
(void) printf("\n");
}
}
else
*lineptr = '\0';
if (verbose)
"returning %s.\n", line);
return (line);
}
if (verbose)
return (NULL);
}
static void
{
if (verbose)
return;
}
copycomments++;
setterm_name();
captoinfo();
}
}
}
/*
* Sort a name and code table pair according to the name table.
* Use a simple bubble sort for now. Too bad I can't call qsort(3).
* At least I only have to do it once for each table.
*/
static void
{
int i, j;
char *c;
for (i = 0; nametable[i]; i++)
for (j = 0; j < i; j++)
c = nametable[i];
nametable[j] = c;
c = codetable[i];
codetable[j] = c;
}
}
/*
* Initialize and sort the name and code tables. Allocate space for the
* value tables.
*/
static void
inittables(void)
{
unsigned int i;
for (i = 0; boolnames [i]; i++)
;
boolcount = i;
for (i = 0; numcodes [i]; i++)
;
numcount = i;
for (i = 0; strcodes [i]; i++)
;
strcount = i;
}
int
{
int c;
capbuffer = &_capbuffer[0];
buflongname = &_buflongname[0];
switch (c) {
case '1':
pr_onecolumn(1);
break;
case 'w':
break;
case 'v':
verbose++;
break;
case 'V':
"@(#)curses:screen/captoinfo.c 1.12");
exit(0);
/* FALLTHROUGH (not really) */
case '?':
"usage: %s [-1Vv] [-w width] "
"[filename ...]\n", progname);
"output\n");
"\t-v\tverbose debugging output\n");
"\t-V\tprint program version\n");
exit(-1);
}
/* initialize */
inittables();
else {
initdirname();
}
return (0);
}
/* fake out the modules in print.c so we don't have to load in */
/* cexpand.c and infotocap.c */
/* ARGSUSED */
int
{
return (0);
}