captoinfo.c revision 381:1a7f0e46092a
1251881Speter/*
2251881Speter * CDDL HEADER START
3251881Speter *
4251881Speter * The contents of this file are subject to the terms of the
5251881Speter * Common Development and Distribution License, Version 1.0 only
6251881Speter * (the "License").  You may not use this file except in compliance
7251881Speter * with the License.
8251881Speter *
9251881Speter * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10251881Speter * or http://www.opensolaris.org/os/licensing.
11251881Speter * See the License for the specific language governing permissions
12251881Speter * and limitations under the License.
13251881Speter *
14251881Speter * When distributing Covered Code, include this CDDL HEADER in each
15251881Speter * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16251881Speter * If applicable, add the following below this CDDL HEADER, with the
17251881Speter * fields enclosed by brackets "[]" replaced with your own identifying
18251881Speter * information: Portions Copyright [yyyy] [name of copyright owner]
19251881Speter *
20251881Speter * CDDL HEADER END
21251881Speter */
22251881Speter/*
23251881Speter * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24251881Speter * Use is subject to license terms.
25251881Speter */
26251881Speter
27251881Speter/*	Copyright (c) 1988 AT&T	*/
28251881Speter/*	  All Rights Reserved  	*/
29251881Speter
30251881Speter#pragma ident	"%Z%%M%	%I%	%E% SMI"
31251881Speter
32251881Speter/*
33251881Speter *  NAME
34251881Speter *	captoinfo - convert a termcap description to a terminfo description
35251881Speter *
36251881Speter *  SYNOPSIS
37251881Speter *	captoinfo [-1vV] [-w width] [ filename ... ]
38251881Speter *
39251881Speter *  AUTHOR
40251881Speter *	Tony Hansen, January 22, 1984.
41251881Speter */
42251881Speter
43251881Speter#include "curses.h"
44251881Speter#include <ctype.h>
45251881Speter#include <stdlib.h>
46251881Speter#include <unistd.h>
47251881Speter#include <string.h>
48251881Speter#include "otermcap.h"
49251881Speter#include "print.h"
50251881Speter
51251881Speter#define	trace stderr			/* send trace messages to stderr */
52251881Speter
53251881Speter/* extra termcap variables no longer in terminfo */
54251881Speterchar *oboolcodes[] =
55251881Speter	{
56251881Speter	"bs",	/* Terminal can backspace with "^H" */
57251881Speter	"nc",	/* No correctly working carriage return (DM2500,H2000) */
58251881Speter	"ns",	/* Terminal is a CRT but does not scroll. */
59251881Speter	"pt",	/* Has hardware tabs (may need to be set with "is") */
60251881Speter	"MT",	/* Has meta key, alternate code. */
61251881Speter	"xr",	/* Return acts like ce \r \n (Delta Data) */
62251881Speter	0
63251881Speter};
64251881Speterint cap_bs = 0, cap_nc = 1, cap_ns = 2, cap_pt = 3, cap_MT = 4, cap_xr = 5;
65251881Speterchar *onumcodes[] =
66251881Speter	{
67251881Speter	"dB",	/* Number of millisec of bs delay needed */
68251881Speter	"dC",	/* Number of millisec of cr delay needed */
69251881Speter	"dF",	/* Number of millisec of ff delay needed */
70251881Speter	"dN",	/* Number of millisec of nl delay needed */
71251881Speter	"dT",	/* Number of millisec of tab delay needed */
72251881Speter	"ug",	/* Number of blank chars left by us or ue */
73251881Speter/* Ignore the 'kn' number. It was ill-defined and never used. */
74251881Speter	"kn",	/* Number of "other" keys */
75251881Speter	0
76251881Speter};
77251881Speterint cap_dB = 0, cap_dC = 1, cap_dF = 2, cap_dN = 3, cap_dT = 4, cap_ug = 5;
78251881Speter
79251881Speterchar *ostrcodes[] =
80251881Speter	{
81251881Speter	"bc",	/* Backspace if not "^H" */
82251881Speter	"ko",	/* Termcap entries for other non-function keys */
83251881Speter	"ma",	/* Arrow key map, used by vi version 2 only */
84251881Speter	"nl",	/* Newline character (default "\n") */
85251881Speter	"rs",	/* undocumented reset string, like is (info is2) */
86251881Speter/* Ignore the 'ml' and 'mu' strings. */
87251881Speter	"ml",	/* Memory lock on above cursor. */
88251881Speter	"mu",	/* Memory unlock (turn off memory lock). */
89251881Speter	0
90251881Speter};
91251881Speterint cap_bc = 0, cap_ko = 1, cap_ma = 2, cap_nl = 3, cap_rs = 4;
92251881Speter
93251881Speter#define	numelements(x)	(sizeof (x)/sizeof (x[0]))
94251881Speterchar oboolval[2][numelements(oboolcodes)];
95251881Spetershort onumval[2][numelements(onumcodes)];
96251881Speterchar *ostrval[2][numelements(ostrcodes)];
97251881Speter
98251881Speter/* externs from libcurses.a */
99251881Speterextern char *boolnames[], *boolcodes[];
100251881Speterextern char *numnames[], *numcodes[];
101251881Speterextern char *strnames[], *strcodes[];
102251881Speter
103251881Speter/* globals for this file */
104251881Speterchar *progname;			/* argv [0], the name of the program */
105251881Speterstatic char *term_name;		/* the name of the terminal being worked on */
106251881Speterstatic int uselevel;		/* whether we're dealing with use= info */
107251881Speterstatic int boolcount,		/* the maximum numbers of each name array */
108251881Speter	    numcount,
109251881Speter	    strcount;
110251881Speter
111251881Speter/* globals dealing with the environment */
112251881Speterextern char **environ;
113251881Speterstatic char TERM[100];
114251881Speter#if defined(SYSV) || defined(USG)  /* handle both Sys Vr2 and Vr3 curses */
115251881Speterstatic char dirname[BUFSIZ];
116251881Speter#else
117251881Speter#include <sys/param.h>
118251881Speterstatic char dirname[MAXPATHLEN];
119251881Speter#endif /* SYSV || USG */
120251881Speterstatic char TERMCAP[BUFSIZ+15];
121251881Speterstatic char *newenviron[] = { &TERM[0], &TERMCAP[0], 0 };
122251881Speter
123251881Speter/* dynamic arrays */
124251881Speterstatic char *boolval[2];	/* dynamic array of boolean values */
125251881Speterstatic short *numval[2];	/* dynamic array of numeric values */
126251881Speterstatic char **strval[2];	/* dynamic array of string pointers */
127251881Speter
128251881Speter/* data buffers */
129251881Speterstatic char *capbuffer;		/* string table, pointed at by strval */
130251881Speterstatic char *nextstring;	/* pointer into string table */
131251881Speterstatic char *bp;		/* termcap raw string table */
132251881Speterstatic char *buflongname;	/* place to copy the long names */
133251881Speter
134251881Speter/* flags */
135251881Speterstatic int verbose = 0;		/* debugging printing level */
136251881Speterstatic int copycomments = 0;	/* copy comments from tercap source */
137251881Speter
138251881Speter#define	ispadchar(c)	(isdigit(c) || (c) == '.' || (c) == '*')
139251881Speter
140251881Speterstatic void getlongname(void);
141251881Speterstatic void handleko(void);
142251881Speterstatic void handlema(void);
143251881Speterstatic void print_no_use_entry(void);
144251881Speterstatic void print_use_entry(char *);
145251881Speterstatic void captoinfo(void);
146251881Speterstatic void use_etc_termcap(void);
147251881Speterstatic void initdirname(void);
148251881Speterstatic void setfilename(char *);
149251881Speterstatic void setterm_name(void);
150251881Speterstatic void use_file(char *);
151251881Speterstatic void sorttable(char *[], char *[]);
152251881Speterstatic void inittables(void);
153251881Speter
154251881Speter/*
155251881Speter *  Verify that the names given in the termcap entry are all valid.
156251881Speter */
157251881Speter
158251881Speterint
159251881Spetercapsearch(char *codes[], char *ocodes[], char *cap)
160251881Speter{
161251881Speter	for (; *codes; codes++)
162251881Speter		if (((*codes)[0] == cap[0]) && ((*codes)[1] == cap[1]))
163251881Speter			return (1);
164251881Speter
165251881Speter	for (; *ocodes; ocodes++)
166251881Speter		if (((*ocodes)[0] == cap[0]) && ((*ocodes)[1] == cap[1]))
167251881Speter			return (1);
168251881Speter
169251881Speter	return (0);
170251881Speter}
171251881Speter
172251881Spetervoid
173251881Speterchecktermcap()
174251881Speter{
175251881Speter	char *tbuf = bp;
176251881Speter	enum { tbool, tnum, tstr, tcancel, tunknown } type;
177251881Speter
178251881Speter	for (;;) {
179251881Speter		tbuf = tskip(tbuf);
180251881Speter		while (*tbuf == '\t' || *tbuf == ' ' || *tbuf == ':')
181251881Speter			tbuf++;
182251881Speter
183251881Speter		if (*tbuf == 0)
184251881Speter			return;
185251881Speter
186251881Speter		/* commented out entry? */
187251881Speter		if (*tbuf == '.') {
188251881Speter			if (verbose)
189251881Speter				(void) fprintf(trace, "termcap string '%c%c' "
190251881Speter				    "commented out.\n", tbuf[1], tbuf[2]);
191251881Speter			if (!capsearch(boolcodes, oboolcodes, tbuf + 1) &&
192251881Speter			    !capsearch(numcodes, onumcodes, tbuf + 1) &&
193251881Speter			    !capsearch(strcodes, ostrcodes, tbuf + 1))
194251881Speter				(void) fprintf(stderr,
195251881Speter				    "%s: TERM=%s: commented out code '%.2s' "
196251881Speter				    "is unknown.\n", progname, term_name,
197251881Speter				    tbuf+1);
198251881Speter			continue;
199251881Speter		}
200251881Speter
201251881Speter		if (verbose)
202251881Speter			(void) fprintf(trace, "looking at termcap string "
203251881Speter			    "'%.2s'.\n", tbuf);
204251881Speter
205251881Speter		switch (tbuf[2]) {
206251881Speter			case ':': case '\0':	type = tbool;	break;
207251881Speter			case '#':			type = tnum;	break;
208251881Speter			case '=':			type = tstr;	break;
209251881Speter			case '@':			type = tcancel;	break;
210251881Speter			default:
211251881Speter				(void) fprintf(stderr,
212251881Speter				    "%s: TERM=%s: unknown type given for the "
213251881Speter				    "termcap code '%.2s'.\n", progname,
214251881Speter				    term_name, tbuf);
215251881Speter				type = tunknown;
216251881Speter		}
217251881Speter
218251881Speter		if (verbose > 1)
219251881Speter			(void) fprintf(trace, "type of '%.2s' is %s.\n", tbuf,
220251881Speter			    (type == tbool) ? "boolean" :
221251881Speter			    (type == tnum) ? "numeric" :
222251881Speter			    (type = tstr) ? "string" :
223251881Speter			    (type = tcancel) ? "canceled" : "unknown");
224251881Speter
225251881Speter		/* look for the name in bools */
226251881Speter		if (capsearch(boolcodes, oboolcodes, tbuf)) {
227251881Speter			if (type != tbool && type != tcancel)
228251881Speter				(void) fprintf(stderr,
229251881Speter				    "%s: TERM=%s: wrong type given for the "
230251881Speter				    "boolean termcap code '%.2s'.\n", progname,
231251881Speter				    term_name, tbuf);
232251881Speter				continue;
233251881Speter		}
234251881Speter
235251881Speter		/* look for the name in nums */
236251881Speter		if (capsearch(numcodes, onumcodes, tbuf)) {
237251881Speter			if (type != tnum && type != tcancel)
238251881Speter				(void) fprintf(stderr,
239251881Speter				    "%s: TERM=%s: wrong type given for the "
240251881Speter				    "numeric termcap code '%.2s'.\n", progname,
241251881Speter				    term_name, tbuf);
242251881Speter				continue;
243251881Speter		}
244251881Speter
245251881Speter		/* look for the name in strs */
246251881Speter		if (capsearch(strcodes, ostrcodes, tbuf)) {
247251881Speter			if (type != tstr && type != tcancel)
248251881Speter				(void) fprintf(stderr,
249251881Speter				    "%s: TERM=%s: wrong type given for the "
250251881Speter				    "string termcap code '%.2s'.\n", progname,
251251881Speter				    term_name, tbuf);
252251881Speter				continue;
253251881Speter		}
254251881Speter
255251881Speter		(void) fprintf(stderr,
256251881Speter		    "%s: TERM=%s: the %s termcap code '%.2s' is not a valid "
257251881Speter		    "name.\n", progname, term_name,
258251881Speter		    (type == tbool) ? "boolean" :
259251881Speter		    (type == tnum) ? "numeric" :
260251881Speter		    (type = tstr) ? "string" :
261251881Speter		    (type = tcancel) ? "canceled" : "(unknown type)", tbuf);
262251881Speter	}
263251881Speter}
264251881Speter
265251881Speter/*
266251881Speter *  Fill up the termcap tables.
267251881Speter */
268251881Speterint
269251881Speterfilltables(void)
270251881Speter{
271251881Speter	int i, tret;
272251881Speter
273251881Speter	/* Retrieve the termcap entry. */
274251881Speter	if ((tret = otgetent(bp, term_name)) != 1) {
275251881Speter		(void) fprintf(stderr,
276251881Speter		    "%s: TERM=%s: tgetent failed with return code %d (%s).\n",
277251881Speter		    progname, term_name, tret,
278251881Speter		    (tret == 0) ? "non-existent or invalid entry" :
279251881Speter		    (tret == -1) ? "cannot open $TERMCAP" : "unknown reason");
280251881Speter		return (0);
281251881Speter	}
282251881Speter
283251881Speter	if (verbose) {
284251881Speter		(void) fprintf(trace, "bp=");
285251881Speter		(void) cpr(trace, bp);
286251881Speter		(void) fprintf(trace, ".\n");
287251881Speter	}
288251881Speter
289251881Speter	if (uselevel == 0)
290251881Speter		checktermcap();
291251881Speter
292251881Speter	/* Retrieve the values that are in terminfo. */
293251881Speter
294251881Speter	/* booleans */
295251881Speter	for (i = 0; boolcodes[i]; i++) {
296251881Speter		boolval[uselevel][i] = otgetflag(boolcodes[i]);
297251881Speter		if (verbose > 1) {
298251881Speter			(void) fprintf(trace, "boolcodes=%s, ", boolcodes[i]);
299251881Speter			(void) fprintf(trace, "boolnames=%s, ", boolnames[i]);
300251881Speter			(void) fprintf(trace,
301251881Speter			    "flag=%d.\n", boolval[uselevel][i]);
302251881Speter		}
303251881Speter	}
304251881Speter
305251881Speter	/* numbers */
306251881Speter	for (i = 0; numcodes[i]; i++) {
307251881Speter		numval[uselevel][i] = otgetnum(numcodes[i]);
308251881Speter		if (verbose > 1) {
309251881Speter			(void) fprintf(trace, "numcodes=%s, ", numcodes[i]);
310251881Speter			(void) fprintf(trace, "numnames=%s, ", numnames[i]);
311251881Speter			(void) fprintf(trace, "num=%d.\n", numval[uselevel][i]);
312251881Speter		}
313251881Speter	}
314251881Speter
315251881Speter	if (uselevel == 0)
316251881Speter		nextstring = capbuffer;
317251881Speter
318251881Speter	/* strings */
319251881Speter	for (i = 0; strcodes[i]; i++) {
320251881Speter		strval[uselevel][i] = otgetstr(strcodes[i], &nextstring);
321251881Speter		if (verbose > 1) {
322251881Speter			(void) fprintf(trace, "strcodes=%s, ", strcodes [i]);
323251881Speter			(void) fprintf(trace, "strnames=%s, ", strnames [i]);
324251881Speter			if (strval[uselevel][i]) {
325251881Speter				(void) fprintf(trace, "str=");
326251881Speter				tpr(trace, strval[uselevel][i]);
327251881Speter				(void) fprintf(trace, ".\n");
328251881Speter			}
329251881Speter		else
330251881Speter			(void) fprintf(trace, "str=NULL.\n");
331251881Speter		}
332251881Speter		/* remove zero length strings */
333251881Speter		if (strval[uselevel][i] && (strval[uselevel][i][0] == '\0')) {
334251881Speter			(void) fprintf(stderr,
335251881Speter			    "%s: TERM=%s: cap %s (info %s) is NULL: REMOVED\n",
336251881Speter			    progname, term_name, strcodes[i], strnames[i]);
337251881Speter			strval[uselevel][i] = NULL;
338251881Speter		}
339251881Speter	}
340251881Speter
341251881Speter	/* Retrieve the values not found in terminfo anymore. */
342251881Speter
343251881Speter	/* booleans */
344251881Speter	for (i = 0; oboolcodes[i]; i++) {
345251881Speter		oboolval[uselevel][i] = otgetflag(oboolcodes[i]);
346251881Speter		if (verbose > 1) {
347251881Speter			(void) fprintf(trace, "oboolcodes=%s, ",
348251881Speter			    oboolcodes[i]);
349251881Speter			(void) fprintf(trace, "flag=%d.\n",
350251881Speter			    oboolval[uselevel][i]);
351251881Speter		}
352251881Speter	}
353251881Speter
354251881Speter	/* numbers */
355251881Speter	for (i = 0; onumcodes[i]; i++) {
356251881Speter		onumval[uselevel][i] = otgetnum(onumcodes[i]);
357251881Speter		if (verbose > 1) {
358251881Speter			(void) fprintf(trace, "onumcodes=%s, ", onumcodes[i]);
359251881Speter			(void) fprintf(trace, "num=%d.\n",
360251881Speter			    onumval[uselevel][i]);
361251881Speter		}
362251881Speter	}
363251881Speter
364251881Speter	/* strings */
365251881Speter	for (i = 0; ostrcodes[i]; i++) {
366251881Speter		ostrval[uselevel][i] = otgetstr(ostrcodes[i], &nextstring);
367251881Speter		if (verbose > 1) {
368251881Speter			(void) fprintf(trace, "ostrcodes=%s, ", ostrcodes[i]);
369251881Speter			if (ostrval[uselevel][i]) {
370251881Speter				(void) fprintf(trace, "ostr=");
371251881Speter				tpr(trace, ostrval[uselevel][i]);
372251881Speter				(void) fprintf(trace, ".\n");
373251881Speter			}
374251881Speter			else
375251881Speter				(void) fprintf(trace, "ostr=NULL.\n");
376251881Speter		}
377251881Speter		/* remove zero length strings */
378251881Speter		if (ostrval[uselevel][i] && (ostrval[uselevel][i][0] == '\0')) {
379251881Speter			(void) fprintf(stderr,
380251881Speter			    "%s: TERM=%s: cap %s (no terminfo name) is NULL: "
381251881Speter			    "REMOVED\n", progname, term_name, ostrcodes[i]);
382251881Speter			ostrval[uselevel][i] = NULL;
383251881Speter		}
384251881Speter	}
385251881Speter	return (1);
386251881Speter}
387251881Speter
388251881Speter/*
389251881Speter *  This routine copies the set of names from the termcap entry into
390251881Speter *  a separate buffer, getting rid of the old obsolete two character
391251881Speter *  names.
392251881Speter */
393251881Speterstatic void
394251881Spetergetlongname(void)
395251881Speter{
396251881Speter	char *b = &bp[0],  *l = buflongname;
397251881Speter
398251881Speter	/* Skip the two character name */
399251881Speter	if (bp[2] == '|')
400251881Speter		b = &bp[3];
401251881Speter
402251881Speter	/* Copy the rest of the names */
403251881Speter	while (*b && *b != ':')
404251881Speter		*l++ = *b++;
405251881Speter	*l = '\0';
406251881Speter
407251881Speter	if (b != &bp[0]) {
408251881Speter		(void) fprintf(stderr, "%s: obsolete 2 character name "
409251881Speter		    "'%2.2s' removed.\n", progname, bp);
410251881Speter		(void) fprintf(stderr, "\tsynonyms are: '%s'\n", buflongname);
411251881Speter	}
412251881Speter}
413251881Speter
414251881Speter/*
415251881Speter *  Return the value of the termcap string 'capname' as stored in our list.
416251881Speter */
417251881Speterchar *
418251881Spetergetcapstr(char *capname)
419251881Speter{
420251881Speter	int i;
421251881Speter
422251881Speter	if (verbose > 1)
423251881Speter		(void) fprintf(trace, "looking for termcap value of %s.\n",
424251881Speter		    capname);
425251881Speter
426251881Speter	/* Check the old termcap list. */
427251881Speter	for (i = 0; ostrcodes[i]; i++)
428251881Speter		if (strcmp(ostrcodes[i], capname) == 0) {
429251881Speter			if (verbose > 1) {
430251881Speter				(void) fprintf(trace, "\tvalue is:");
431251881Speter				tpr(trace, ostrval[uselevel][i]);
432251881Speter				(void) fprintf(trace, ".\n");
433251881Speter			}
434251881Speter			return (ostrval[uselevel][i]);
435251881Speter		}
436251881Speter
437251881Speter	if (verbose > 1)
438251881Speter		(void) fprintf(trace, "termcap name '%s' not found in "
439251881Speter		    "ostrcodes.\n", capname);
440251881Speter
441251881Speter	/* Check the terminfo list. */
442251881Speter	for (i = 0; strcodes[i]; i++)
443251881Speter		if (strcmp(strcodes[i], capname) == 0) {
444251881Speter			if (verbose > 1) {
445251881Speter				(void) fprintf(trace, "\tvalue is:");
446251881Speter				tpr(trace, strval[uselevel][i]);
447251881Speter				(void) fprintf(trace, ".\n");
448251881Speter			}
449251881Speter			return (strval[uselevel][i]);
450251881Speter		}
451251881Speter
452251881Speter	(void) fprintf(stderr, "%s: TERM=%s: termcap name '%s' not found.\n",
453251881Speter	    progname, term_name, capname);
454251881Speter
455251881Speter	return ((char *)NULL);
456251881Speter}
457251881Speter
458251881Speter/*
459251881Speter *  Search for a name in the given table and
460251881Speter *  return the index.
461251881Speter *  Someday I'll redo this to use bsearch().
462251881Speter */
463251881Speter/* ARGSUSED */
464251881Speterint
465251881Spetersearch(char *names[], int max, char *infoname)
466251881Speter{
467251881Speter#ifndef BSEARCH
468251881Speter	int i;
469251881Speter	for (i = 0; names [i] != NULL; i++)
470251881Speter		if (strcmp(names [i], infoname) == 0)
471251881Speter			return (i);
472251881Speter		return (-1);
473251881Speter#else				/* this doesn't work for some reason */
474251881Speter	char **bret;
475251881Speter
476251881Speter	bret = (char **)bsearch(infoname, (char *)names, max,
477251881Speter	    sizeof (char *), strcmp);
478251881Speter	(void) fprintf(trace, "search looking for %s.\n", infoname);
479251881Speter	(void) fprintf(trace, "base=%#x, bret=%#x, nel=%d.\n", names,
480251881Speter	    bret, max);
481251881Speter	(void) fprintf(trace, "returning %d.\n", bret == NULL ? -1 :
482251881Speter	    bret - names);
483251881Speter	if (bret == NULL)
484251881Speter		return (-1);
485251881Speter	else
486251881Speter		return (bret - names);
487251881Speter#endif /* OLD */
488251881Speter}
489251881Speter
490251881Speter/*
491251881Speter *  return the value of the terminfo string 'infoname'
492251881Speter */
493251881Speterchar *
494251881Spetergetinfostr(char *infoname)
495251881Speter{
496251881Speter	int i;
497251881Speter
498251881Speter	if (verbose > 1)
499251881Speter		(void) fprintf(trace, "looking for terminfo value of %s.\n",
500251881Speter		    infoname);
501251881Speter
502251881Speter	i = search(strnames, strcount, infoname);
503251881Speter	if (i != -1) {
504251881Speter		if (verbose > 1) {
505251881Speter			(void) fprintf(trace, "\tvalue is:");
506251881Speter			tpr(trace, strval[uselevel][i]);
507251881Speter			(void) fprintf(trace, ".\n");
508251881Speter		}
509251881Speter		return (strval[uselevel][i]);
510251881Speter	}
511251881Speter
512251881Speter	if (verbose > 1)
513251881Speter		(void) fprintf(trace, "terminfo name '%s' not found.\n",
514251881Speter		    infoname);
515251881Speter
516251881Speter	return ((char *)NULL);
517251881Speter}
518251881Speter
519251881Speter/*
520251881Speter *  Replace the value stored for the terminfo boolean
521251881Speter *  capability 'infoname' with the newvalue.
522251881Speter */
523251881Spetervoid
524251881Speterputbool(char *infoname, int newvalue)
525251881Speter{
526251881Speter	int i;
527251881Speter
528251881Speter	if (verbose > 1)
529251881Speter		(void) fprintf(trace, "changing value for %s to %d.\n",
530251881Speter		    infoname, newvalue);
531251881Speter
532251881Speter	i = search(boolnames, boolcount, infoname);
533251881Speter	if (i != -1) {
534251881Speter		if (verbose > 1)
535251881Speter			(void) fprintf(trace, "value was: %d.\n",
536251881Speter			    boolval[uselevel][i]);
537251881Speter
538251881Speter		boolval[uselevel][i] = newvalue;
539251881Speter		return;
540251881Speter	}
541251881Speter
542251881Speter	(void) fprintf(stderr, "%s: TERM=%s: the boolean name '%s' was not "
543251881Speter	    "found!\n", progname, term_name, infoname);
544251881Speter}
545251881Speter
546251881Speter/*
547251881Speter *  Replace the value stored for the terminfo number
548251881Speter *  capability 'infoname' with the newvalue.
549251881Speter */
550251881Spetervoid
551251881Speterputnum(char *infoname, int newvalue)
552251881Speter{
553251881Speter	int i;
554251881Speter
555251881Speter	if (verbose > 1)
556251881Speter		(void) fprintf(trace, "changing value for %s to %d.\n",
557251881Speter		    infoname, newvalue);
558251881Speter
559251881Speter	i = search(numnames, numcount, infoname);
560251881Speter	if (i != -1) {
561251881Speter		if (verbose > 1)
562251881Speter			(void) fprintf(trace, "value was: %d.\n",
563251881Speter			    numval[uselevel][i]);
564251881Speter
565251881Speter		numval[uselevel][i] = newvalue;
566251881Speter		return;
567251881Speter	}
568251881Speter
569251881Speter	(void) fprintf(stderr, "%s: TERM=%s: the numeric name '%s' was not "
570251881Speter	    "found!\n",
571251881Speter	    progname, term_name, infoname);
572251881Speter}
573251881Speter
574251881Speter/*
575251881Speter *  replace the value stored for the terminfo string capability 'infoname'
576251881Speter *  with the newvalue.
577251881Speter */
578251881Spetervoid
579251881Speterputstr(char *infoname, char *newvalue)
580251881Speter{
581251881Speter	int i;
582251881Speter
583251881Speter	if (verbose > 1) {
584251881Speter		(void) fprintf(trace, "changing value for %s to ", infoname);
585251881Speter		tpr(trace, newvalue);
586251881Speter		(void) fprintf(trace, ".\n");
587251881Speter	}
588251881Speter
589251881Speter	i = search(strnames, strcount, infoname);
590251881Speter	if (i != -1) {
591251881Speter		if (verbose > 1) {
592251881Speter			(void) fprintf(trace, "value was:");
593251881Speter			tpr(trace, strval[uselevel][i]);
594251881Speter			(void) fprintf(trace, ".\n");
595251881Speter		}
596251881Speter		strval[uselevel][i] = nextstring;
597251881Speter		while (*newvalue)
598251881Speter			*nextstring++ = *newvalue++;
599251881Speter		*nextstring++ = '\0';
600251881Speter		return;
601251881Speter	}
602251881Speter
603251881Speter	(void) fprintf(stderr, "%s: TERM=%s: the string name '%s' was not "
604251881Speter	    "found!\n",
605251881Speter	    progname, term_name, infoname);
606251881Speter}
607251881Speter
608251881Speter/*
609251881Speter *  Add in extra delays if they are not recorded already.
610251881Speter *  This is done before the padding information has been modified by
611251881Speter *  changecalculations() below, so the padding information, if there
612251881Speter *  already, is still at the beginning of the string in termcap format.
613251881Speter */
614251881Spetervoid
615251881Speteraddpadding(int cappadding, char *infostr)
616251881Speter{
617251881Speter	char *cap;
618251881Speter	char tempbuffer [100];
619251881Speter
620251881Speter	/* Is there padding to add? */
621251881Speter	if (cappadding > 0)
622251881Speter	/* Is there a string to add it to? */
623251881Speter		if (cap = getinfostr(infostr))
624251881Speter		/* Is there any padding info already? */
625251881Speter			if (ispadchar(*cap)) {
626251881Speter				/* EMPTY */;
627251881Speter		/* Assume that the padding info that is there is correct. */
628251881Speter			} else {
629251881Speter		/* Add the padding at the end of the present string. */
630251881Speter				(void) snprintf(tempbuffer, sizeof (tempbuffer),
631251881Speter				    "%s$<%d>", cap, cappadding);
632251881Speter				putstr(infostr, tempbuffer);
633251881Speter		} else {
634251881Speter			/* Create a new string that only has the padding. */
635251881Speter			(void) sprintf(tempbuffer, "$<%d>", cappadding);
636251881Speter			putstr(infostr, tempbuffer);
637251881Speter		}
638251881Speter}
639251881Speter
640251881Speterstruct
641251881Speter	{
642251881Speter	char *capname;
643251881Speter	char *keyedinfoname;
644251881Speter	} ko_map[] = {
645251881Speter	"al",		"kil1",
646251881Speter	"bs",		"kbs",		/* special addition */
647251881Speter	"bt",		"kcbt",
648251881Speter	"cd",		"ked",
649251881Speter	"ce",		"kel",
650251881Speter	"cl",		"kclr",
651251881Speter	"ct",		"ktbc",
652251881Speter	"dc",		"kdch1",
653251881Speter	"dl",		"kdl1",
654251881Speter	"do",		"kcud1",
655251881Speter	"ei",		"krmir",
656251881Speter	"ho",		"khome",
657251881Speter	"ic",		"kich1",
658251881Speter	"im",		"kich1",	/* special addition */
659251881Speter	"le",		"kcub1",
660251881Speter	"ll",		"kll",
661251881Speter	"nd",		"kcuf1",
662251881Speter	"sf",		"kind",
663251881Speter	"sr",		"kri",
664251881Speter	"st",		"khts",
665251881Speter	"up",		"kcuu1",
666251881Speter/*	"",		"kctab",	*/
667251881Speter/*	"",		"knp",		*/
668251881Speter/*	"",		"kpp",		*/
669251881Speter	0,		0
670251881Speter	};
671251881Speter
672251881Speter/*
673251881Speter *  Work with the ko string. It is a comma separated list of keys for which
674251881Speter *  the keyboard has a key by the same name that emits the same sequence.
675251881Speter *  For example, ko = dc, im, ei means that there are keys called
676251881Speter *  delete-character, enter-insert-mode and exit-insert-mode on the keyboard,
677251881Speter *  and they emit the same sequences as specified in the dc, im and ei
678251881Speter *  capabilities.
679251881Speter */
680251881Speterstatic void
681251881Speterhandleko(void)
682251881Speter{
683251881Speter	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)
759struct
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
786void
787prchar(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
795static void
796handlema(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 */
876void
877adddefaults(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 */
973char *
974caddstr(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. */
983int
984needscopying(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 */
1009int
1010fancycap(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 */
1048void
1049changecalculations()
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
1229static void
1230print_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
1260static void
1261print_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
1304static void
1305captoinfo(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
1347static void
1348use_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
1360static void
1361initdirname(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
1373static void
1374setfilename(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
1387static void
1388setterm_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
1401char *
1402getterm_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
1438static void
1439use_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 */
1469static void
1470sorttable(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 */
1491static void
1492inittables(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
1518int
1519main(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 */
1579int
1580cpr(FILE *stream, char *string)
1581{
1582	return (0);
1583}
1584