Home | History | Annotate | Download | only in captoinfo
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*	Copyright (c) 1988 AT&T	*/
     28 /*	  All Rights Reserved  	*/
     29 
     30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     31 
     32 /*
     33  *  NAME
     34  *	captoinfo - convert a termcap description to a terminfo description
     35  *
     36  *  SYNOPSIS
     37  *	captoinfo [-1vV] [-w width] [ filename ... ]
     38  *
     39  *  AUTHOR
     40  *	Tony Hansen, January 22, 1984.
     41  */
     42 
     43 #include "curses.h"
     44 #include <ctype.h>
     45 #include <stdlib.h>
     46 #include <unistd.h>
     47 #include <string.h>
     48 #include "otermcap.h"
     49 #include "print.h"
     50 
     51 #define	trace stderr			/* send trace messages to stderr */
     52 
     53 /* extra termcap variables no longer in terminfo */
     54 char *oboolcodes[] =
     55 	{
     56 	"bs",	/* Terminal can backspace with "^H" */
     57 	"nc",	/* No correctly working carriage return (DM2500,H2000) */
     58 	"ns",	/* Terminal is a CRT but does not scroll. */
     59 	"pt",	/* Has hardware tabs (may need to be set with "is") */
     60 	"MT",	/* Has meta key, alternate code. */
     61 	"xr",	/* Return acts like ce \r \n (Delta Data) */
     62 	0
     63 };
     64 int cap_bs = 0, cap_nc = 1, cap_ns = 2, cap_pt = 3, cap_MT = 4, cap_xr = 5;
     65 char *onumcodes[] =
     66 	{
     67 	"dB",	/* Number of millisec of bs delay needed */
     68 	"dC",	/* Number of millisec of cr delay needed */
     69 	"dF",	/* Number of millisec of ff delay needed */
     70 	"dN",	/* Number of millisec of nl delay needed */
     71 	"dT",	/* Number of millisec of tab delay needed */
     72 	"ug",	/* Number of blank chars left by us or ue */
     73 /* Ignore the 'kn' number. It was ill-defined and never used. */
     74 	"kn",	/* Number of "other" keys */
     75 	0
     76 };
     77 int cap_dB = 0, cap_dC = 1, cap_dF = 2, cap_dN = 3, cap_dT = 4, cap_ug = 5;
     78 
     79 char *ostrcodes[] =
     80 	{
     81 	"bc",	/* Backspace if not "^H" */
     82 	"ko",	/* Termcap entries for other non-function keys */
     83 	"ma",	/* Arrow key map, used by vi version 2 only */
     84 	"nl",	/* Newline character (default "\n") */
     85 	"rs",	/* undocumented reset string, like is (info is2) */
     86 /* Ignore the 'ml' and 'mu' strings. */
     87 	"ml",	/* Memory lock on above cursor. */
     88 	"mu",	/* Memory unlock (turn off memory lock). */
     89 	0
     90 };
     91 int cap_bc = 0, cap_ko = 1, cap_ma = 2, cap_nl = 3, cap_rs = 4;
     92 
     93 #define	numelements(x)	(sizeof (x)/sizeof (x[0]))
     94 char oboolval[2][numelements(oboolcodes)];
     95 short onumval[2][numelements(onumcodes)];
     96 char *ostrval[2][numelements(ostrcodes)];
     97 
     98 /* externs from libcurses.a */
     99 extern char *boolnames[], *boolcodes[];
    100 extern char *numnames[], *numcodes[];
    101 extern char *strnames[], *strcodes[];
    102 
    103 /* globals for this file */
    104 char *progname;			/* argv [0], the name of the program */
    105 static char *term_name;		/* the name of the terminal being worked on */
    106 static int uselevel;		/* whether we're dealing with use= info */
    107 static int boolcount,		/* the maximum numbers of each name array */
    108 	    numcount,
    109 	    strcount;
    110 
    111 /* globals dealing with the environment */
    112 extern char **environ;
    113 static char TERM[100];
    114 #if defined(SYSV) || defined(USG)  /* handle both Sys Vr2 and Vr3 curses */
    115 static char dirname[BUFSIZ];
    116 #else
    117 #include <sys/param.h>
    118 static char dirname[MAXPATHLEN];
    119 #endif /* SYSV || USG */
    120 static char TERMCAP[BUFSIZ+15];
    121 static char *newenviron[] = { &TERM[0], &TERMCAP[0], 0 };
    122 
    123 /* dynamic arrays */
    124 static char *boolval[2];	/* dynamic array of boolean values */
    125 static short *numval[2];	/* dynamic array of numeric values */
    126 static char **strval[2];	/* dynamic array of string pointers */
    127 
    128 /* data buffers */
    129 static char *capbuffer;		/* string table, pointed at by strval */
    130 static char *nextstring;	/* pointer into string table */
    131 static char *bp;		/* termcap raw string table */
    132 static char *buflongname;	/* place to copy the long names */
    133 
    134 /* flags */
    135 static int verbose = 0;		/* debugging printing level */
    136 static int copycomments = 0;	/* copy comments from tercap source */
    137 
    138 #define	ispadchar(c)	(isdigit(c) || (c) == '.' || (c) == '*')
    139 
    140 static void getlongname(void);
    141 static void handleko(void);
    142 static void handlema(void);
    143 static void print_no_use_entry(void);
    144 static void print_use_entry(char *);
    145 static void captoinfo(void);
    146 static void use_etc_termcap(void);
    147 static void initdirname(void);
    148 static void setfilename(char *);
    149 static void setterm_name(void);
    150 static void use_file(char *);
    151 static void sorttable(char *[], char *[]);
    152 static void inittables(void);
    153 
    154 /*
    155  *  Verify that the names given in the termcap entry are all valid.
    156  */
    157 
    158 int
    159 capsearch(char *codes[], char *ocodes[], char *cap)
    160 {
    161 	for (; *codes; codes++)
    162 		if (((*codes)[0] == cap[0]) && ((*codes)[1] == cap[1]))
    163 			return (1);
    164 
    165 	for (; *ocodes; ocodes++)
    166 		if (((*ocodes)[0] == cap[0]) && ((*ocodes)[1] == cap[1]))
    167 			return (1);
    168 
    169 	return (0);
    170 }
    171 
    172 void
    173 checktermcap()
    174 {
    175 	char *tbuf = bp;
    176 	enum { tbool, tnum, tstr, tcancel, tunknown } type;
    177 
    178 	for (;;) {
    179 		tbuf = tskip(tbuf);
    180 		while (*tbuf == '\t' || *tbuf == ' ' || *tbuf == ':')
    181 			tbuf++;
    182 
    183 		if (*tbuf == 0)
    184 			return;
    185 
    186 		/* commented out entry? */
    187 		if (*tbuf == '.') {
    188 			if (verbose)
    189 				(void) fprintf(trace, "termcap string '%c%c' "
    190 				    "commented out.\n", tbuf[1], tbuf[2]);
    191 			if (!capsearch(boolcodes, oboolcodes, tbuf + 1) &&
    192 			    !capsearch(numcodes, onumcodes, tbuf + 1) &&
    193 			    !capsearch(strcodes, ostrcodes, tbuf + 1))
    194 				(void) fprintf(stderr,
    195 				    "%s: TERM=%s: commented out code '%.2s' "
    196 				    "is unknown.\n", progname, term_name,
    197 				    tbuf+1);
    198 			continue;
    199 		}
    200 
    201 		if (verbose)
    202 			(void) fprintf(trace, "looking at termcap string "
    203 			    "'%.2s'.\n", tbuf);
    204 
    205 		switch (tbuf[2]) {
    206 			case ':': case '\0':	type = tbool;	break;
    207 			case '#':			type = tnum;	break;
    208 			case '=':			type = tstr;	break;
    209 			case '@':			type = tcancel;	break;
    210 			default:
    211 				(void) fprintf(stderr,
    212 				    "%s: TERM=%s: unknown type given for the "
    213 				    "termcap code '%.2s'.\n", progname,
    214 				    term_name, tbuf);
    215 				type = tunknown;
    216 		}
    217 
    218 		if (verbose > 1)
    219 			(void) fprintf(trace, "type of '%.2s' is %s.\n", tbuf,
    220 			    (type == tbool) ? "boolean" :
    221 			    (type == tnum) ? "numeric" :
    222 			    (type = tstr) ? "string" :
    223 			    (type = tcancel) ? "canceled" : "unknown");
    224 
    225 		/* look for the name in bools */
    226 		if (capsearch(boolcodes, oboolcodes, tbuf)) {
    227 			if (type != tbool && type != tcancel)
    228 				(void) fprintf(stderr,
    229 				    "%s: TERM=%s: wrong type given for the "
    230 				    "boolean termcap code '%.2s'.\n", progname,
    231 				    term_name, tbuf);
    232 				continue;
    233 		}
    234 
    235 		/* look for the name in nums */
    236 		if (capsearch(numcodes, onumcodes, tbuf)) {
    237 			if (type != tnum && type != tcancel)
    238 				(void) fprintf(stderr,
    239 				    "%s: TERM=%s: wrong type given for the "
    240 				    "numeric termcap code '%.2s'.\n", progname,
    241 				    term_name, tbuf);
    242 				continue;
    243 		}
    244 
    245 		/* look for the name in strs */
    246 		if (capsearch(strcodes, ostrcodes, tbuf)) {
    247 			if (type != tstr && type != tcancel)
    248 				(void) fprintf(stderr,
    249 				    "%s: TERM=%s: wrong type given for the "
    250 				    "string termcap code '%.2s'.\n", progname,
    251 				    term_name, tbuf);
    252 				continue;
    253 		}
    254 
    255 		(void) fprintf(stderr,
    256 		    "%s: TERM=%s: the %s termcap code '%.2s' is not a valid "
    257 		    "name.\n", progname, term_name,
    258 		    (type == tbool) ? "boolean" :
    259 		    (type == tnum) ? "numeric" :
    260 		    (type = tstr) ? "string" :
    261 		    (type = tcancel) ? "canceled" : "(unknown type)", tbuf);
    262 	}
    263 }
    264 
    265 /*
    266  *  Fill up the termcap tables.
    267  */
    268 int
    269 filltables(void)
    270 {
    271 	int i, tret;
    272 
    273 	/* Retrieve the termcap entry. */
    274 	if ((tret = otgetent(bp, term_name)) != 1) {
    275 		(void) fprintf(stderr,
    276 		    "%s: TERM=%s: tgetent failed with return code %d (%s).\n",
    277 		    progname, term_name, tret,
    278 		    (tret == 0) ? "non-existent or invalid entry" :
    279 		    (tret == -1) ? "cannot open $TERMCAP" : "unknown reason");
    280 		return (0);
    281 	}
    282 
    283 	if (verbose) {
    284 		(void) fprintf(trace, "bp=");
    285 		(void) cpr(trace, bp);
    286 		(void) fprintf(trace, ".\n");
    287 	}
    288 
    289 	if (uselevel == 0)
    290 		checktermcap();
    291 
    292 	/* Retrieve the values that are in terminfo. */
    293 
    294 	/* booleans */
    295 	for (i = 0; boolcodes[i]; i++) {
    296 		boolval[uselevel][i] = otgetflag(boolcodes[i]);
    297 		if (verbose > 1) {
    298 			(void) fprintf(trace, "boolcodes=%s, ", boolcodes[i]);
    299 			(void) fprintf(trace, "boolnames=%s, ", boolnames[i]);
    300 			(void) fprintf(trace,
    301 			    "flag=%d.\n", boolval[uselevel][i]);
    302 		}
    303 	}
    304 
    305 	/* numbers */
    306 	for (i = 0; numcodes[i]; i++) {
    307 		numval[uselevel][i] = otgetnum(numcodes[i]);
    308 		if (verbose > 1) {
    309 			(void) fprintf(trace, "numcodes=%s, ", numcodes[i]);
    310 			(void) fprintf(trace, "numnames=%s, ", numnames[i]);
    311 			(void) fprintf(trace, "num=%d.\n", numval[uselevel][i]);
    312 		}
    313 	}
    314 
    315 	if (uselevel == 0)
    316 		nextstring = capbuffer;
    317 
    318 	/* strings */
    319 	for (i = 0; strcodes[i]; i++) {
    320 		strval[uselevel][i] = otgetstr(strcodes[i], &nextstring);
    321 		if (verbose > 1) {
    322 			(void) fprintf(trace, "strcodes=%s, ", strcodes [i]);
    323 			(void) fprintf(trace, "strnames=%s, ", strnames [i]);
    324 			if (strval[uselevel][i]) {
    325 				(void) fprintf(trace, "str=");
    326 				tpr(trace, strval[uselevel][i]);
    327 				(void) fprintf(trace, ".\n");
    328 			}
    329 		else
    330 			(void) fprintf(trace, "str=NULL.\n");
    331 		}
    332 		/* remove zero length strings */
    333 		if (strval[uselevel][i] && (strval[uselevel][i][0] == '\0')) {
    334 			(void) fprintf(stderr,
    335 			    "%s: TERM=%s: cap %s (info %s) is NULL: REMOVED\n",
    336 			    progname, term_name, strcodes[i], strnames[i]);
    337 			strval[uselevel][i] = NULL;
    338 		}
    339 	}
    340 
    341 	/* Retrieve the values not found in terminfo anymore. */
    342 
    343 	/* booleans */
    344 	for (i = 0; oboolcodes[i]; i++) {
    345 		oboolval[uselevel][i] = otgetflag(oboolcodes[i]);
    346 		if (verbose > 1) {
    347 			(void) fprintf(trace, "oboolcodes=%s, ",
    348 			    oboolcodes[i]);
    349 			(void) fprintf(trace, "flag=%d.\n",
    350 			    oboolval[uselevel][i]);
    351 		}
    352 	}
    353 
    354 	/* numbers */
    355 	for (i = 0; onumcodes[i]; i++) {
    356 		onumval[uselevel][i] = otgetnum(onumcodes[i]);
    357 		if (verbose > 1) {
    358 			(void) fprintf(trace, "onumcodes=%s, ", onumcodes[i]);
    359 			(void) fprintf(trace, "num=%d.\n",
    360 			    onumval[uselevel][i]);
    361 		}
    362 	}
    363 
    364 	/* strings */
    365 	for (i = 0; ostrcodes[i]; i++) {
    366 		ostrval[uselevel][i] = otgetstr(ostrcodes[i], &nextstring);
    367 		if (verbose > 1) {
    368 			(void) fprintf(trace, "ostrcodes=%s, ", ostrcodes[i]);
    369 			if (ostrval[uselevel][i]) {
    370 				(void) fprintf(trace, "ostr=");
    371 				tpr(trace, ostrval[uselevel][i]);
    372 				(void) fprintf(trace, ".\n");
    373 			}
    374 			else
    375 				(void) fprintf(trace, "ostr=NULL.\n");
    376 		}
    377 		/* remove zero length strings */
    378 		if (ostrval[uselevel][i] && (ostrval[uselevel][i][0] == '\0')) {
    379 			(void) fprintf(stderr,
    380 			    "%s: TERM=%s: cap %s (no terminfo name) is NULL: "
    381 			    "REMOVED\n", progname, term_name, ostrcodes[i]);
    382 			ostrval[uselevel][i] = NULL;
    383 		}
    384 	}
    385 	return (1);
    386 }
    387 
    388 /*
    389  *  This routine copies the set of names from the termcap entry into
    390  *  a separate buffer, getting rid of the old obsolete two character
    391  *  names.
    392  */
    393 static void
    394 getlongname(void)
    395 {
    396 	char *b = &bp[0],  *l = buflongname;
    397 
    398 	/* Skip the two character name */
    399 	if (bp[2] == '|')
    400 		b = &bp[3];
    401 
    402 	/* Copy the rest of the names */
    403 	while (*b && *b != ':')
    404 		*l++ = *b++;
    405 	*l = '\0';
    406 
    407 	if (b != &bp[0]) {
    408 		(void) fprintf(stderr, "%s: obsolete 2 character name "
    409 		    "'%2.2s' removed.\n", progname, bp);
    410 		(void) fprintf(stderr, "\tsynonyms are: '%s'\n", buflongname);
    411 	}
    412 }
    413 
    414 /*
    415  *  Return the value of the termcap string 'capname' as stored in our list.
    416  */
    417 char *
    418 getcapstr(char *capname)
    419 {
    420 	int i;
    421 
    422 	if (verbose > 1)
    423 		(void) fprintf(trace, "looking for termcap value of %s.\n",
    424 		    capname);
    425 
    426 	/* Check the old termcap list. */
    427 	for (i = 0; ostrcodes[i]; i++)
    428 		if (strcmp(ostrcodes[i], capname) == 0) {
    429 			if (verbose > 1) {
    430 				(void) fprintf(trace, "\tvalue is:");
    431 				tpr(trace, ostrval[uselevel][i]);
    432 				(void) fprintf(trace, ".\n");
    433 			}
    434 			return (ostrval[uselevel][i]);
    435 		}
    436 
    437 	if (verbose > 1)
    438 		(void) fprintf(trace, "termcap name '%s' not found in "
    439 		    "ostrcodes.\n", capname);
    440 
    441 	/* Check the terminfo list. */
    442 	for (i = 0; strcodes[i]; i++)
    443 		if (strcmp(strcodes[i], capname) == 0) {
    444 			if (verbose > 1) {
    445 				(void) fprintf(trace, "\tvalue is:");
    446 				tpr(trace, strval[uselevel][i]);
    447 				(void) fprintf(trace, ".\n");
    448 			}
    449 			return (strval[uselevel][i]);
    450 		}
    451 
    452 	(void) fprintf(stderr, "%s: TERM=%s: termcap name '%s' not found.\n",
    453 	    progname, term_name, capname);
    454 
    455 	return ((char *)NULL);
    456 }
    457 
    458 /*
    459  *  Search for a name in the given table and
    460  *  return the index.
    461  *  Someday I'll redo this to use bsearch().
    462  */
    463 /* ARGSUSED */
    464 int
    465 search(char *names[], int max, char *infoname)
    466 {
    467 #ifndef BSEARCH
    468 	int i;
    469 	for (i = 0; names [i] != NULL; i++)
    470 		if (strcmp(names [i], infoname) == 0)
    471 			return (i);
    472 		return (-1);
    473 #else				/* this doesn't work for some reason */
    474 	char **bret;
    475 
    476 	bret = (char **)bsearch(infoname, (char *)names, max,
    477 	    sizeof (char *), strcmp);
    478 	(void) fprintf(trace, "search looking for %s.\n", infoname);
    479 	(void) fprintf(trace, "base=%#x, bret=%#x, nel=%d.\n", names,
    480 	    bret, max);
    481 	(void) fprintf(trace, "returning %d.\n", bret == NULL ? -1 :
    482 	    bret - names);
    483 	if (bret == NULL)
    484 		return (-1);
    485 	else
    486 		return (bret - names);
    487 #endif /* OLD */
    488 }
    489 
    490 /*
    491  *  return the value of the terminfo string 'infoname'
    492  */
    493 char *
    494 getinfostr(char *infoname)
    495 {
    496 	int i;
    497 
    498 	if (verbose > 1)
    499 		(void) fprintf(trace, "looking for terminfo value of %s.\n",
    500 		    infoname);
    501 
    502 	i = search(strnames, strcount, infoname);
    503 	if (i != -1) {
    504 		if (verbose > 1) {
    505 			(void) fprintf(trace, "\tvalue is:");
    506 			tpr(trace, strval[uselevel][i]);
    507 			(void) fprintf(trace, ".\n");
    508 		}
    509 		return (strval[uselevel][i]);
    510 	}
    511 
    512 	if (verbose > 1)
    513 		(void) fprintf(trace, "terminfo name '%s' not found.\n",
    514 		    infoname);
    515 
    516 	return ((char *)NULL);
    517 }
    518 
    519 /*
    520  *  Replace the value stored for the terminfo boolean
    521  *  capability 'infoname' with the newvalue.
    522  */
    523 void
    524 putbool(char *infoname, int newvalue)
    525 {
    526 	int i;
    527 
    528 	if (verbose > 1)
    529 		(void) fprintf(trace, "changing value for %s to %d.\n",
    530 		    infoname, newvalue);
    531 
    532 	i = search(boolnames, boolcount, infoname);
    533 	if (i != -1) {
    534 		if (verbose > 1)
    535 			(void) fprintf(trace, "value was: %d.\n",
    536 			    boolval[uselevel][i]);
    537 
    538 		boolval[uselevel][i] = newvalue;
    539 		return;
    540 	}
    541 
    542 	(void) fprintf(stderr, "%s: TERM=%s: the boolean name '%s' was not "
    543 	    "found!\n", progname, term_name, infoname);
    544 }
    545 
    546 /*
    547  *  Replace the value stored for the terminfo number
    548  *  capability 'infoname' with the newvalue.
    549  */
    550 void
    551 putnum(char *infoname, int newvalue)
    552 {
    553 	int i;
    554 
    555 	if (verbose > 1)
    556 		(void) fprintf(trace, "changing value for %s to %d.\n",
    557 		    infoname, newvalue);
    558 
    559 	i = search(numnames, numcount, infoname);
    560 	if (i != -1) {
    561 		if (verbose > 1)
    562 			(void) fprintf(trace, "value was: %d.\n",
    563 			    numval[uselevel][i]);
    564 
    565 		numval[uselevel][i] = newvalue;
    566 		return;
    567 	}
    568 
    569 	(void) fprintf(stderr, "%s: TERM=%s: the numeric name '%s' was not "
    570 	    "found!\n",
    571 	    progname, term_name, infoname);
    572 }
    573 
    574 /*
    575  *  replace the value stored for the terminfo string capability 'infoname'
    576  *  with the newvalue.
    577  */
    578 void
    579 putstr(char *infoname, char *newvalue)
    580 {
    581 	int i;
    582 
    583 	if (verbose > 1) {
    584 		(void) fprintf(trace, "changing value for %s to ", infoname);
    585 		tpr(trace, newvalue);
    586 		(void) fprintf(trace, ".\n");
    587 	}
    588 
    589 	i = search(strnames, strcount, infoname);
    590 	if (i != -1) {
    591 		if (verbose > 1) {
    592 			(void) fprintf(trace, "value was:");
    593 			tpr(trace, strval[uselevel][i]);
    594 			(void) fprintf(trace, ".\n");
    595 		}
    596 		strval[uselevel][i] = nextstring;
    597 		while (*newvalue)
    598 			*nextstring++ = *newvalue++;
    599 		*nextstring++ = '\0';
    600 		return;
    601 	}
    602 
    603 	(void) fprintf(stderr, "%s: TERM=%s: the string name '%s' was not "
    604 	    "found!\n",
    605 	    progname, term_name, infoname);
    606 }
    607 
    608 /*
    609  *  Add in extra delays if they are not recorded already.
    610  *  This is done before the padding information has been modified by
    611  *  changecalculations() below, so the padding information, if there
    612  *  already, is still at the beginning of the string in termcap format.
    613  */
    614 void
    615 addpadding(int cappadding, char *infostr)
    616 {
    617 	char *cap;
    618 	char tempbuffer [100];
    619 
    620 	/* Is there padding to add? */
    621 	if (cappadding > 0)
    622 	/* Is there a string to add it to? */
    623 		if (cap = getinfostr(infostr))
    624 		/* Is there any padding info already? */
    625 			if (ispadchar(*cap)) {
    626 				/* EMPTY */;
    627 		/* Assume that the padding info that is there is correct. */
    628 			} else {
    629 		/* Add the padding at the end of the present string. */
    630 				(void) snprintf(tempbuffer, sizeof (tempbuffer),
    631 				    "%s$<%d>", cap, cappadding);
    632 				putstr(infostr, tempbuffer);
    633 		} else {
    634 			/* Create a new string that only has the padding. */
    635 			(void) sprintf(tempbuffer, "$<%d>", cappadding);
    636 			putstr(infostr, tempbuffer);
    637 		}
    638 }
    639 
    640 struct
    641 	{
    642 	char *capname;
    643 	char *keyedinfoname;
    644 	} ko_map[] = {
    645 	"al",		"kil1",
    646 	"bs",		"kbs",		/* special addition */
    647 	"bt",		"kcbt",
    648 	"cd",		"ked",
    649 	"ce",		"kel",
    650 	"cl",		"kclr",
    651 	"ct",		"ktbc",
    652 	"dc",		"kdch1",
    653 	"dl",		"kdl1",
    654 	"do",		"kcud1",
    655 	"ei",		"krmir",
    656 	"ho",		"khome",
    657 	"ic",		"kich1",
    658 	"im",		"kich1",	/* special addition */
    659 	"le",		"kcub1",
    660 	"ll",		"kll",
    661 	"nd",		"kcuf1",
    662 	"sf",		"kind",
    663 	"sr",		"kri",
    664 	"st",		"khts",
    665 	"up",		"kcuu1",
    666 /*	"",		"kctab",	*/
    667 /*	"",		"knp",		*/
    668 /*	"",		"kpp",		*/
    669 	0,		0
    670 	};
    671 
    672 /*
    673  *  Work with the ko string. It is a comma separated list of keys for which
    674  *  the keyboard has a key by the same name that emits the same sequence.
    675  *  For example, ko = dc, im, ei means that there are keys called
    676  *  delete-character, enter-insert-mode and exit-insert-mode on the keyboard,
    677  *  and they emit the same sequences as specified in the dc, im and ei
    678  *  capabilities.
    679  */
    680 static void
    681 handleko(void)
    682 {
    683 	char capname[3];
    684 	char *capstr;
    685 	int i, j, found;
    686 	char *infostr;
    687 
    688 	if (verbose > 1)
    689 		(void) fprintf(trace, "working on termcap ko string.\n");
    690 
    691 	if (ostrval[uselevel][cap_ko] == NULL)
    692 		return;
    693 
    694 	capname[2] = '\0';
    695 	for (i = 0; ostrval[uselevel][cap_ko][i] != '\0'; ) {
    696 		/* isolate the termcap name */
    697 		capname[0] = ostrval[uselevel][cap_ko][i++];
    698 		if (ostrval[uselevel][cap_ko][i] == '\0')
    699 			break;
    700 		capname[1] = ostrval[uselevel][cap_ko][i++];
    701 		if (ostrval[uselevel][cap_ko][i] == ',')
    702 			i++;
    703 
    704 		if (verbose > 1) {
    705 			(void) fprintf(trace, "key termcap name is '");
    706 			tpr(trace, capname);
    707 			(void) fprintf(trace, "'.\n");
    708 		}
    709 
    710 		/* match it up into our list */
    711 		found = 0;
    712 		for (j = 0; !found && ko_map[j].keyedinfoname != NULL; j++) {
    713 			if (verbose > 1)
    714 			(void) fprintf(trace, "looking at termcap name %s.\n",
    715 			    ko_map[j].capname);
    716 			if (capname[0] == ko_map[j].capname[0] &&
    717 			    capname[1] == ko_map[j].capname[1]) {
    718 				/* add the value to our database */
    719 				if ((capstr = getcapstr(capname)) != NULL) {
    720 					infostr = getinfostr
    721 					    (ko_map[j].keyedinfoname);
    722 				if (infostr == NULL) {
    723 					/* skip any possible padding */
    724 					/* information */
    725 					while (ispadchar(*capstr))
    726 						capstr++;
    727 					putstr(ko_map[j].keyedinfoname, capstr);
    728 				} else
    729 					if (strcmp(capstr, infostr) != 0) {
    730 						(void) fprintf(stderr,
    731 						    "%s: TERM=%s: a function "
    732 						    "key for '%s' was "
    733 						    "specified with the "
    734 						    "value ", progname,
    735 						    term_name, capname);
    736 						tpr(stderr, capstr);
    737 						(void) fprintf(stderr,
    738 						    ", but it already has the "
    739 						    "value '");
    740 						tpr(stderr, infostr);
    741 						(void) fprintf(stderr, "'.\n");
    742 					}
    743 				}
    744 				found = 1;
    745 			}
    746 		}
    747 
    748 		if (!found) {
    749 			(void) fprintf(stderr, "%s: TERM=%s: the unknown "
    750 			    "termcap name '%s' was\n", progname, term_name,
    751 			    capname);
    752 			(void) fprintf(stderr, "specified in the 'ko' "
    753 			    "termcap capability.\n");
    754 		}
    755 	}
    756 }
    757 
    758 #define	CONTROL(x)		((x) & 037)
    759 struct
    760 	{
    761 	char vichar;
    762 	char *keyedinfoname;
    763 	} ma_map[] = {
    764 		CONTROL('J'),	"kcud1",	/* down */
    765 		CONTROL('N'),	"kcud1",
    766 		'j',		"kcud1",
    767 		CONTROL('P'),	"kcuu1",	/* up */
    768 		'k',		"kcuu1",
    769 		'h',		"kcub1",	/* left */
    770 		CONTROL('H'),	"kcub1",
    771 		' ',		"kcuf1",	/* right */
    772 		'l',		"kcuf1",
    773 		'H',		"khome",	/* home */
    774 		CONTROL('L'),	"kclr",		/* clear */
    775 		0,		0
    776 	};
    777 
    778 /*
    779  *  Work with the ma string. This is a list of pairs of characters.
    780  *  The first character is the what a function key sends. The second
    781  *  character is the equivalent vi function that should be done when
    782  *  it receives that character. Note that only function keys that send
    783  *  a single character could be defined by this list.
    784  */
    785 
    786 void
    787 prchar(FILE *stream, int c)
    788 {
    789 	char xbuf[2];
    790 	xbuf[0] = c;
    791 	xbuf[1] = '\0';
    792 	(void) fprintf(stream, "%s", iexpand(xbuf));
    793 }
    794 
    795 static void
    796 handlema(void)
    797 {
    798 	char vichar;
    799 	char cap[2];
    800 	int i, j, found;
    801 	char *infostr;
    802 
    803 	if (verbose > 1)
    804 		(void) fprintf(trace, "working on termcap ma string.\n");
    805 
    806 	if (ostrval[uselevel][cap_ma] == NULL)
    807 		return;
    808 
    809 	cap[1] = '\0';
    810 	for (i = 0; ostrval[uselevel][cap_ma][i] != '\0'; ) {
    811 		/* isolate the key's value */
    812 		cap[0] = ostrval[uselevel][cap_ma][i++];
    813 		if (verbose > 1) {
    814 			(void) fprintf(trace, "key value is '");
    815 			tpr(trace, cap);
    816 			(void) fprintf(trace, "'.\n");
    817 		}
    818 
    819 		if (ostrval[uselevel][cap_ma][i] == '\0')
    820 			break;
    821 
    822 		/* isolate the vi key name */
    823 		vichar = ostrval[uselevel][cap_ma][i++];
    824 		if (verbose > 1) {
    825 			(void) fprintf(trace, "the vi key is '");
    826 			prchar(trace, vichar);
    827 			(void) fprintf(trace, "'.\n");
    828 		}
    829 
    830 		/* match up the vi name in our list */
    831 		found = 0;
    832 		for (j = 0; !found && ma_map[j].keyedinfoname != NULL; j++) {
    833 			if (verbose > 1) {
    834 				(void) fprintf(trace, "looking at vi "
    835 				    "character '");
    836 				prchar(trace, ma_map[j].vichar);
    837 				(void) fprintf(trace, "'\n");
    838 			}
    839 			if (vichar == ma_map[j].vichar) {
    840 				infostr = getinfostr(ma_map[j].keyedinfoname);
    841 				if (infostr == NULL)
    842 					putstr(ma_map[j].keyedinfoname, cap);
    843 				else if (strcmp(cap, infostr) != 0) {
    844 					(void) fprintf(stderr, "%s: TERM=%s: "
    845 					    "the vi character '", progname,
    846 					    term_name);
    847 					prchar(stderr, vichar);
    848 					(void) fprintf(stderr,
    849 					    "' (info '%s') has the value '",
    850 					    ma_map[j].keyedinfoname);
    851 					tpr(stderr, infostr);
    852 					(void) fprintf(stderr, "', but 'ma' "
    853 					    "gives '");
    854 					prchar(stderr, cap[0]);
    855 					(void) fprintf(stderr, "'.\n");
    856 				}
    857 				found = 1;
    858 			}
    859 		}
    860 
    861 		if (!found) {
    862 			(void) fprintf(stderr, "%s: the unknown vi key '",
    863 			    progname);
    864 			prchar(stderr, vichar);
    865 			(void) fprintf(stderr, "' was\n");
    866 			(void) fprintf(stderr, "specified in the 'ma' termcap "
    867 			    "capability.\n");
    868 		}
    869 	}
    870 }
    871 
    872 /*
    873  *  Many capabilities were defaulted in termcap which must now be explicitly
    874  *  given. We'll assume that the defaults are in effect for this terminal.
    875  */
    876 void
    877 adddefaults(void)
    878 {
    879 	char *cap;
    880 	int sg;
    881 
    882 	if (verbose > 1)
    883 		(void) fprintf(trace, "assigning defaults.\n");
    884 
    885 	/* cr was assumed to be ^M, unless nc was given, */
    886 	/* which meant it could not be done. */
    887 	/* Also, xr meant that ^M acted strangely. */
    888 	if ((getinfostr("cr") == NULL) && !oboolval[uselevel][cap_nc] &&
    889 	    !oboolval[uselevel][cap_xr])
    890 		if ((cap = getcapstr("cr")) == NULL)
    891 			putstr("cr", "\r");
    892 		else
    893 			putstr("cr", cap);
    894 
    895 	/* cursor down was assumed to be ^J if not specified by nl */
    896 	if (getinfostr("cud1") == NULL)
    897 		if (ostrval[uselevel][cap_nl] != NULL)
    898 			putstr("cud1", ostrval[uselevel][cap_nl]);
    899 		else
    900 			putstr("cud1", "\n");
    901 
    902 	/* ind was assumed to be ^J, unless ns was given, */
    903 	/* which meant it could not be done. */
    904 	if ((getinfostr("ind") == NULL) && !oboolval[uselevel][cap_ns])
    905 		if (ostrval[uselevel][cap_nl] == NULL)
    906 			putstr("ind", "\n");
    907 		else
    908 			putstr("ind", ostrval[uselevel][cap_nl]);
    909 
    910 	/* bel was assumed to be ^G */
    911 	if (getinfostr("bel") == NULL)
    912 		putstr("bel", "\07");
    913 
    914 	/* if bs, then could do backspacing, */
    915 	/* with value of bc, default of ^H */
    916 	if ((getinfostr("cub1") == NULL) && oboolval[uselevel][cap_bs])
    917 		if (ostrval[uselevel][cap_bc] != NULL)
    918 			putstr("cub1", ostrval[uselevel][cap_bc]);
    919 		else
    920 			putstr("cub1", "\b");
    921 
    922 	/* default xon to true */
    923 	if (!otgetflag("xo"))
    924 		putbool("xon", 1);
    925 
    926 	/* if pt, then hardware tabs are allowed, */
    927 	/* with value of ta, default of ^I */
    928 	if ((getinfostr("ht") == NULL) && oboolval[uselevel][cap_pt])
    929 		if ((cap = getcapstr("ta")) == NULL)
    930 			putstr("ht", "\t");
    931 		else
    932 			putstr("ht", cap);
    933 
    934 	/* The dX numbers are now stored as padding */
    935 	/* in the appropriate terminfo string. */
    936 	addpadding(onumval[uselevel][cap_dB], "cub1");
    937 	addpadding(onumval[uselevel][cap_dC], "cr");
    938 	addpadding(onumval[uselevel][cap_dF], "ff");
    939 	addpadding(onumval[uselevel][cap_dN], "cud1");
    940 	addpadding(onumval[uselevel][cap_dT], "ht");
    941 
    942 	/* The ug and sg caps were essentially identical, */
    943 	/* so ug almost never got used. We set sg from ug */
    944 	/* if it hasn't already been set. */
    945 	if (onumval[uselevel][cap_ug] >= 0 && (sg = otgetnum("sg")) < 0)
    946 		putnum("xmc", onumval[uselevel][cap_ug]);
    947 	else if ((onumval[uselevel][cap_ug] >= 0) &&
    948 	    (sg >= 0) && (onumval[uselevel][cap_ug] != sg))
    949 		(void) fprintf(stderr,
    950 		    "%s: TERM=%s: Warning: termcap sg and ug had different "
    951 		    "values (%d<->%d).\n", progname, term_name, sg,
    952 		    onumval[uselevel][cap_ug]);
    953 
    954 	/* The MT boolean was never really part of termcap, */
    955 	/* but we can check for it anyways. */
    956 	if (oboolval[uselevel][cap_MT] && !otgetflag("km"))
    957 		putbool("km", 1);
    958 
    959 	/* the rs string was renamed r2 (info rs2) */
    960 	if ((ostrval[uselevel][cap_rs] != NULL) &&
    961 	    (ostrval[uselevel][cap_rs][0] != NULL))
    962 		putstr("rs2", ostrval[uselevel][cap_rs]);
    963 
    964 	handleko();
    965 	handlema();
    966 }
    967 
    968 #define	caddch(x) *to++ = (x)
    969 
    970 /*
    971  *  add the string to the string table
    972  */
    973 char *
    974 caddstr(char *to, char *str)
    975 {
    976 	while (*str)
    977 		*to++ = *str++;
    978 	return (to);
    979 }
    980 
    981 /* If there is no padding info or parmed strings, */
    982 /* then we do not need to copy the string. */
    983 int
    984 needscopying(char *string)
    985 {
    986 	/* any string at all? */
    987 	if (string == NULL)
    988 		return (0);
    989 
    990 	/* any padding info? */
    991 	if (ispadchar(*string))
    992 		return (1);
    993 
    994 	/* any parmed info? */
    995 	while (*string)
    996 		if (*string++ == '%')
    997 			return (1);
    998 
    999 	return (0);
   1000 }
   1001 
   1002 /*
   1003  *  Certain manipulations of the stack require strange manipulations of the
   1004  *  values that are on the stack. To handle these, we save the values of the
   1005  *  parameters in registers at the very beginning and make the changes in
   1006  *  the registers. We don't want to do this in the general case because of the
   1007  *  potential performance loss.
   1008  */
   1009 int
   1010 fancycap(char *string)
   1011 {
   1012 	int parmset = 0;
   1013 
   1014 	while (*string)
   1015 		if (*string++ == '%') {
   1016 			switch (*string) {
   1017 				/* These manipulate just the top value on */
   1018 				/* the stack, so we only have to do */
   1019 				/* something strange if a %r follows. */
   1020 				case '>': case 'B': case 'D':
   1021 					parmset = 1;
   1022 					break;
   1023 				/* If the parm has already been been */
   1024 				/* pushed onto the stack by %>, then we */
   1025 				/* can not reverse the parms and must get */
   1026 				/* them from the registers. */
   1027 				case 'r':
   1028 					if (parmset)
   1029 						return (1);
   1030 					break;
   1031 				/* This manipulates both parameters, so we */
   1032 				/* cannot just do one and leave the value */
   1033 				/* on the stack like we can with %>, */
   1034 				/* %B or %D. */
   1035 				case 'n':
   1036 					return (1);
   1037 			}
   1038 			string++;
   1039 		}
   1040 		return (0);
   1041 }
   1042 
   1043 /*
   1044  *  Change old style of doing calculations to the new stack style.
   1045  *  Note that this will not necessarily produce the most efficient string,
   1046  *  but it will work.
   1047  */
   1048 void
   1049 changecalculations()
   1050 {
   1051 	int i, currentparm;
   1052 	char *from, *to = nextstring;
   1053 	int ch;
   1054 	int parmset, parmsaved;
   1055 	char padding[100], *saveto;
   1056 
   1057 	for (i = 0; strnames[i]; i++)
   1058 		if (needscopying(strval[uselevel][i])) {
   1059 			if (verbose) {
   1060 				(void) fprintf(trace, "%s needs copying, "
   1061 				    "was:", strnames [i]);
   1062 				tpr(trace, strval[uselevel][i]);
   1063 				(void) fprintf(trace, ".\n");
   1064 			}
   1065 
   1066 			from = strval[uselevel][i];
   1067 			strval[uselevel][i] = to;
   1068 			currentparm = 1;
   1069 			parmset = 0;
   1070 
   1071 	    /* Handle padding information. Save it so that it can be */
   1072 	    /* placed at the end of the string where it should */
   1073 	    /* have been in the first place. */
   1074 			if (ispadchar(*from)) {
   1075 				saveto = to;
   1076 				to = padding;
   1077 				to = caddstr(to, "$<");
   1078 				while (isdigit(*from) || *from == '.')
   1079 					caddch(*from++);
   1080 				if (*from == '*')
   1081 					caddch(*from++);
   1082 				caddch('>');
   1083 				caddch('\0');
   1084 				to = saveto;
   1085 			} else
   1086 				padding[0] = '\0';
   1087 
   1088 			if (fancycap(from)) {
   1089 				to = caddstr(to, "%p1%Pa%p2%Pb");
   1090 				parmsaved = 1;
   1091 				(void) fprintf(stderr,
   1092 				    "%s: TERM=%s: Warning: the string "
   1093 				    "produced for '%s' may be inefficient.\n",
   1094 				    progname, term_name, strnames[i]);
   1095 				(void) fprintf(stderr, "It should be "
   1096 				    "looked at by hand.\n");
   1097 			} else
   1098 				parmsaved = 0;
   1099 
   1100 			while ((ch = *from++) != '\0')
   1101 				if (ch != '%')
   1102 					caddch(ch);
   1103 				else
   1104 				switch (ch = *from++) {
   1105 					case '.':	/* %.  -> %p1%c */
   1106 					case 'd':	/* %d  -> %p1%d */
   1107 					case '2':	/* %2  -> %p1%2.2d */
   1108 					case '3':	/* %3  -> %p1%3.3d */
   1109 					case '+':
   1110 					/* %+x -> %p1%'x'%+%c */
   1111 
   1112 					case '>':
   1113 					/* %>xy -> %p1%Pc%?%'x'%> */
   1114 					/* %t%gc%'y'%+ */
   1115 					/* if current value > x, then add y. */
   1116 					/* No output. */
   1117 
   1118 					case 'B':
   1119 					/* %B: BCD */
   1120 					/* (16*(x/10))+(x%10) */
   1121 					/* No output. */
   1122 					/* (Adds Regent 100) */
   1123 
   1124 					case 'D':
   1125 					/* %D: Reverse coding */
   1126 					/* (x-2*(x%16)) */
   1127 					/* No output. */
   1128 					/* (Delta Data) */
   1129 
   1130 					if (!parmset)
   1131 						if (parmsaved) {
   1132 							to = caddstr(to, "%g");
   1133 							if (currentparm == 1)
   1134 								caddch('a');
   1135 							else
   1136 								caddch('b');
   1137 						} else {
   1138 							to = caddstr(to, "%p");
   1139 							if (currentparm == 1)
   1140 								caddch('1');
   1141 							else
   1142 								caddch('2');
   1143 						}
   1144 					currentparm = 3 - currentparm;
   1145 					parmset = 0;
   1146 					switch (ch) {
   1147 						case '.':
   1148 							to = caddstr(to, "%c");
   1149 							break;
   1150 						case 'd':
   1151 							to = caddstr(to, "%d");
   1152 							break;
   1153 						case '2': case '3':
   1154 #ifdef USG	/* Vr2==USG, Vr3==SYSV. Use %02d for Vr2, %2.2d for Vr3 */
   1155 							caddch('%');
   1156 							caddch('0');
   1157 #else
   1158 							caddch('%');
   1159 							caddch(ch);
   1160 							caddch('.');
   1161 #endif /* USG vs. SYSV */
   1162 							caddch(ch);
   1163 							caddch('d');
   1164 							break;
   1165 						case '+':
   1166 							to = caddstr(to, "%'");
   1167 							caddch(*from++);
   1168 							to = caddstr(to,
   1169 							    "'%+%c");
   1170 							break;
   1171 						case '>':
   1172 							to = caddstr(to,
   1173 							    "%Pc%?%'");
   1174 							caddch(*from++);
   1175 							to = caddstr(to,
   1176 							    "'%>%t%gc%'");
   1177 							caddch(*from++);
   1178 							to = caddstr(to,
   1179 							    "'%+");
   1180 							parmset = 1;
   1181 							break;
   1182 						case 'B':
   1183 							to = caddstr(to,
   1184 "%Pc%gc%{10}%/%{16}%*%gc%{10}%m%+");
   1185 						parmset = 1;
   1186 						break;
   1187 
   1188 						case 'D':
   1189 							to = caddstr(to,
   1190 "%Pc%gc%gc%{16}%m%{2}%*%-");
   1191 							parmset = 1;
   1192 							break;
   1193 					}
   1194 					break;
   1195 
   1196 					/* %r reverses current parameter */
   1197 					case 'r':
   1198 						currentparm = 3 - currentparm;
   1199 						break;
   1200 
   1201 					/* %n: exclusive-or row AND column */
   1202 					/* with 0140, 96 decimal, no output */
   1203 					/* (Datamedia 2500, Exidy Sorceror) */
   1204 					case 'n':
   1205 						to = caddstr(to,
   1206 						    "%ga%'`'%^%Pa");
   1207 						to = caddstr(to,
   1208 						    "%gb%'`'%^%Pb");
   1209 						break;
   1210 
   1211 					/* assume %x means %x */
   1212 					/* this includes %i and %% */
   1213 					default:
   1214 						caddch('%');
   1215 						caddch(ch);
   1216 				}
   1217 		to = caddstr(to, padding);
   1218 		caddch('\0');
   1219 
   1220 		if (verbose) {
   1221 			(void) fprintf(trace, "and has become:");
   1222 			tpr(trace, strval[uselevel][i]);
   1223 			(void) fprintf(trace, ".\n");
   1224 		}
   1225 	}
   1226 	nextstring = to;
   1227 }
   1228 
   1229 static void
   1230 print_no_use_entry(void)
   1231 {
   1232 	int i;
   1233 
   1234 	pr_heading("", buflongname);
   1235 	pr_bheading();
   1236 
   1237 	for (i = 0; boolcodes[i]; i++)
   1238 		if (boolval[0][i])
   1239 			pr_boolean(boolnames[i], (char *)0, (char *)0, 1);
   1240 
   1241 	pr_bfooting();
   1242 	pr_sheading();
   1243 
   1244 	for (i = 0; numcodes[i]; i++)
   1245 		if (numval[0][i] > -1)
   1246 			pr_number(numnames[i], (char *)0, (char *)0,
   1247 			    numval[0][i]);
   1248 
   1249 	pr_nfooting();
   1250 	pr_sheading();
   1251 
   1252 	for (i = 0; strcodes[i]; i++)
   1253 		if (strval[0][i])
   1254 			pr_string(strnames[i], (char *)0, (char *)0,
   1255 			    strval[0][i]);
   1256 
   1257 	pr_sfooting();
   1258 }
   1259 
   1260 static void
   1261 print_use_entry(char *usename)
   1262 {
   1263 	int i;
   1264 
   1265 	pr_heading("", buflongname);
   1266 	pr_bheading();
   1267 
   1268 	for (i = 0; boolcodes[i]; i++)
   1269 		if (boolval[0][i] && !boolval[1][i])
   1270 			pr_boolean(boolnames[i], (char *)0, (char *)0, 1);
   1271 		else if (!boolval[0][i] && boolval[1][i])
   1272 			pr_boolean(boolnames[i], (char *)0, (char *)0, -1);
   1273 
   1274 	pr_bfooting();
   1275 	pr_nheading();
   1276 
   1277 	for (i = 0; numcodes[i]; i++)
   1278 		if ((numval[0][i] > -1) && (numval[0][i] != numval[1][i]))
   1279 			pr_number(numnames[i], (char *)0, (char *)0,
   1280 			    numval[0][i]);
   1281 		else if ((numval [0] [i] == -1) && (numval [1] [i] > -1))
   1282 			pr_number(numnames[i], (char *)0, (char *)0, -1);
   1283 
   1284 	pr_nfooting();
   1285 	pr_sheading();
   1286 
   1287 	for (i = 0; strcodes[i]; i++)
   1288 		/* print out str[0] if: */
   1289 		/* str[0] != NULL and str[1] == NULL, or str[0] != str[1] */
   1290 		if (strval[0][i] && ((strval[1][i] == NULL) ||
   1291 		    (strcmp(strval[0][i], strval[1][i]) != 0)))
   1292 				pr_string(strnames[i], (char *)0, (char *)0,
   1293 				    strval[0][i]);
   1294 		/* print out @ if str[0] == NULL and str[1] != NULL */
   1295 		else if (strval[0][i] == NULL && strval[1][i] != NULL)
   1296 			pr_string(strnames[i], (char *)0, (char *)0,
   1297 			    (char *)0);
   1298 
   1299 	pr_sfooting();
   1300 
   1301 	(void) printf("\tuse=%s,\n", usename);
   1302 }
   1303 
   1304 static void
   1305 captoinfo(void)
   1306 {
   1307 	char usename[512];
   1308 	char *sterm_name;
   1309 
   1310 	if (term_name == NULL) {
   1311 		(void) fprintf(stderr, "%s: Null term_name given.\n",
   1312 		    progname);
   1313 		return;
   1314 	}
   1315 
   1316 	if (verbose)
   1317 		(void) fprintf(trace, "changing cap to info, TERM=%s.\n",
   1318 		    term_name);
   1319 
   1320 	uselevel = 0;
   1321 	if (filltables() == 0)
   1322 		return;
   1323 	getlongname();
   1324 	adddefaults();
   1325 	changecalculations();
   1326 	if (TLHtcfound != 0) {
   1327 		uselevel = 1;
   1328 		if (verbose)
   1329 			(void) fprintf(trace, "use= found, %s uses %s.\n",
   1330 			    term_name, TLHtcname);
   1331 		(void) strcpy(usename, TLHtcname);
   1332 		sterm_name = term_name;
   1333 		term_name = usename;
   1334 		if (filltables() == 0)
   1335 			return;
   1336 		adddefaults();
   1337 		changecalculations();
   1338 		term_name = sterm_name;
   1339 		print_use_entry(usename);
   1340 	} else
   1341 		print_no_use_entry();
   1342 }
   1343 
   1344 
   1345 #include <signal.h>   /* use this file to determine if this is SVR4.0 system */
   1346 
   1347 static void
   1348 use_etc_termcap(void)
   1349 {
   1350 	if (verbose)
   1351 #ifdef  SIGSTOP
   1352 		(void) fprintf(trace, "reading from /usr/share/lib/termcap\n");
   1353 #else   /* SIGSTOP */
   1354 		(void) fprintf(trace, "reading from /etc/termcap\n");
   1355 #endif  /* SIGSTOP */
   1356 		term_name = getenv("TERM");
   1357 		captoinfo();
   1358 }
   1359 
   1360 static void
   1361 initdirname(void)
   1362 {
   1363 #if defined(SYSV) || defined(USG)  /* handle both Sys Vr2 and Vr3 curses */
   1364 	(void) getcwd(dirname, BUFSIZ-2);
   1365 #else
   1366 	(void) getwd(dirname);
   1367 #endif /* SYSV || USG */
   1368 	if (verbose)
   1369 		(void) fprintf(trace, "current directory name=%s.\n", dirname);
   1370 		environ = newenviron;
   1371 }
   1372 
   1373 static void
   1374 setfilename(char *capfile)
   1375 {
   1376 	if (capfile [0] == '/')
   1377 		(void) snprintf(TERMCAP, sizeof (TERMCAP),
   1378 		    "TERMCAP=%s", capfile);
   1379 	else
   1380 		(void) snprintf(TERMCAP, sizeof (TERMCAP),
   1381 		    "TERMCAP=%s/%s", dirname, capfile);
   1382 	if (verbose)
   1383 		(void) fprintf(trace, "setting the environment for %s.\n",
   1384 		    TERMCAP);
   1385 }
   1386 
   1387 static void
   1388 setterm_name(void)
   1389 {
   1390 	if (verbose)
   1391 		(void) fprintf(trace, "setting the environment "
   1392 		    "for TERM=%s.\n", term_name);
   1393 	(void) snprintf(TERM, sizeof (TERM), "TERM=%s", term_name);
   1394 }
   1395 
   1396 /* Look at the current line to see if it is a list of names. */
   1397 /* If it is, return the first name in the list, else NULL. */
   1398 /* As a side-effect, comment lines and blank lines */
   1399 /* are copied to standard output. */
   1400 
   1401 char *
   1402 getterm_name(char *line)
   1403 {
   1404 	char *lineptr = line;
   1405 
   1406 	if (verbose)
   1407 		(void) fprintf(trace, "extracting name from '%s'.\n", line);
   1408 
   1409 	/* Copy comment lines out. */
   1410 	if (*line == '#') {
   1411 		if (copycomments)
   1412 			(void) printf("%s", line);
   1413 	}
   1414 	/* Blank lines get copied too. */
   1415 	else if (isspace (*line)) {
   1416 		if (copycomments) {
   1417 			for (; *lineptr; lineptr++)
   1418 				if (!isspace(*lineptr))
   1419 					break;
   1420 			if (*lineptr == '\0')
   1421 			(void) printf("\n");
   1422 		}
   1423 	}
   1424 	else
   1425 		for (; *lineptr; lineptr++)
   1426 			if (*lineptr == '|' || *lineptr == ':') {
   1427 				*lineptr = '\0';
   1428 				if (verbose)
   1429 					(void) fprintf(trace,
   1430 					    "returning %s.\n", line);
   1431 				return (line);
   1432 			}
   1433 	if (verbose)
   1434 		(void) fprintf(trace, "returning NULL.\n");
   1435 	return (NULL);
   1436 }
   1437 
   1438 static void
   1439 use_file(char *filename)
   1440 {
   1441 	FILE *termfile;
   1442 	char buffer[BUFSIZ];
   1443 
   1444 	if (verbose)
   1445 		(void) fprintf(trace, "reading from %s.\n", filename);
   1446 
   1447 	if ((termfile = fopen(filename, "r")) == NULL) {
   1448 		(void) fprintf(stderr, "%s: cannot open %s for reading.\n",
   1449 		    progname, filename);
   1450 		return;
   1451 	}
   1452 
   1453 	copycomments++;
   1454 	setfilename(filename);
   1455 
   1456 	while (fgets(buffer, BUFSIZ, termfile) != NULL) {
   1457 		if ((term_name = getterm_name(buffer)) != NULL) {
   1458 			setterm_name();
   1459 			captoinfo();
   1460 		}
   1461 	}
   1462 }
   1463 
   1464 /*
   1465  *  Sort a name and code table pair according to the name table.
   1466  *  Use a simple bubble sort for now. Too bad I can't call qsort(3).
   1467  *  At least I only have to do it once for each table.
   1468  */
   1469 static void
   1470 sorttable(char *nametable[], char *codetable[])
   1471 {
   1472 	int i, j;
   1473 	char *c;
   1474 
   1475 	for (i = 0; nametable[i]; i++)
   1476 		for (j = 0; j < i; j++)
   1477 			if (strcmp(nametable[i], nametable[j]) < 0) {
   1478 				c = nametable[i];
   1479 				nametable[i] = nametable[j];
   1480 				nametable[j] = c;
   1481 				c = codetable[i];
   1482 				codetable[i] = codetable[j];
   1483 				codetable[j] = c;
   1484 			}
   1485 }
   1486 
   1487 /*
   1488  *  Initialize and sort the name and code tables. Allocate space for the
   1489  *  value tables.
   1490  */
   1491 static void
   1492 inittables(void)
   1493 {
   1494 	unsigned int i;
   1495 
   1496 	for (i = 0; boolnames [i]; i++)
   1497 		;
   1498 	boolval[0] = (char *)malloc(i * sizeof (char));
   1499 	boolval[1] = (char *)malloc(i * sizeof (char));
   1500 	boolcount = i;
   1501 	sorttable(boolnames, boolcodes);
   1502 
   1503 	for (i = 0; numcodes [i]; i++)
   1504 		;
   1505 	numval[0] = (short *)malloc(i * sizeof (short));
   1506 	numval[1] = (short *)malloc(i * sizeof (short));
   1507 	numcount = i;
   1508 	sorttable(numnames, numcodes);
   1509 
   1510 	for (i = 0; strcodes [i]; i++)
   1511 		;
   1512 	strval[0] = (char **)malloc(i * sizeof (char *));
   1513 	strval[1] = (char **)malloc(i * sizeof (char *));
   1514 	strcount = i;
   1515 	sorttable(strnames, strcodes);
   1516 }
   1517 
   1518 int
   1519 main(int argc, char **argv)
   1520 {
   1521 	int c;
   1522 	char _capbuffer [8192];
   1523 	char _bp [TBUFSIZE];
   1524 	char _buflongname [128];
   1525 
   1526 	capbuffer = &_capbuffer[0];
   1527 	bp = &_bp[0];
   1528 	buflongname = &_buflongname[0];
   1529 	progname = argv[0];
   1530 
   1531 	while ((c = getopt(argc, argv, "1vVw:")) != EOF)
   1532 		switch (c) {
   1533 			case '1':
   1534 				pr_onecolumn(1);
   1535 				break;
   1536 			case 'w':
   1537 				pr_width(atoi(optarg));
   1538 				break;
   1539 			case 'v':
   1540 				verbose++;
   1541 				break;
   1542 			case 'V':
   1543 				(void) printf("%s: version %s\n", progname,
   1544 				    "@(#)curses:screen/captoinfo.c	1.12");
   1545 				(void) fflush(stdout);
   1546 				exit(0);
   1547 				/* FALLTHROUGH (not really) */
   1548 			case '?':
   1549 				(void) fprintf(stderr,
   1550 				    "usage: %s [-1Vv] [-w width] "
   1551 				    "[filename ...]\n", progname);
   1552 				(void) fprintf(stderr, "\t-1\tsingle column "
   1553 				    "output\n");
   1554 				(void) fprintf(stderr,
   1555 				    "\t-v\tverbose debugging output\n");
   1556 				(void) fprintf(stderr,
   1557 				    "\t-V\tprint program version\n");
   1558 				exit(-1);
   1559 		}
   1560 
   1561 	/* initialize */
   1562 	pr_init(pr_terminfo);
   1563 	inittables();
   1564 
   1565 	if (optind >= argc)
   1566 		use_etc_termcap();
   1567 	else {
   1568 		initdirname();
   1569 	for (; optind < argc; optind++)
   1570 		use_file(argv [optind]);
   1571 	}
   1572 
   1573 	return (0);
   1574 }
   1575 
   1576 /* fake out the modules in print.c so we don't have to load in */
   1577 /* cexpand.c and infotocap.c */
   1578 /* ARGSUSED */
   1579 int
   1580 cpr(FILE *stream, char *string)
   1581 {
   1582 	return (0);
   1583 }
   1584