xref: /csrg-svn/local/local.cmd/showtc.c (revision 25326)
1*25326Sserge #ifndef lint
2*25326Sserge static char *sccsid="@(#)showtc.c	1.8	(Berkeley) 10/28/85";
312044Slayer #endif
412044Slayer 
512031Slayer /*
612031Slayer ** show termcap entries
712031Slayer **
812031Slayer ** where:
912458Slayer **	-D	look for duplicate names and print termcap file
1012031Slayer **	-S	sort entries before display
1112458Slayer **	-T	trace (-DDEBUG only)
1213250Slayer **	-U	print unknown capabilities
1312044Slayer **	-b	show bare entries
1412458Slayer **	-d	-D and stop
1512044Slayer **	-f	following arg is FULL PATHNAME of termcap file
1612044Slayer **	-g	sort on generic names
1712044Slayer **	-s	don't print two char name at the front of every line
1812044Slayer **	-x	expand tc= capabilities
1912031Slayer **	[ent]	display specific entry. tc= will be expanded.
2012031Slayer **
2112031Slayer ** David L. Wasley, U.C.Berkeley
2212446Slayer ** Kevin Layer: modified for 4.1c and misc changes.
2312446Slayer ** Kevin Layer: added the printing of terminal capabilities
2412446Slayer **	in `human' readable form (like that in "man 5 termcap").
2512031Slayer */
2612031Slayer 
2712031Slayer #include <stdio.h>
2812031Slayer #include <sys/file.h>
2912031Slayer #include <ctype.h>
3012031Slayer #include <sys/types.h>
3112031Slayer #include <sys/stat.h>
3212031Slayer 
3312031Slayer #define NO		0
3412031Slayer #define YES		1
3512031Slayer #define CNULL		'\0'
3612031Slayer #define NOENTRIES	1024
3712044Slayer #define USAGE		"usage: %s [-Sxdngb] [-f termcapfile] [entry] ...\n"
3812031Slayer 
3912031Slayer struct TcName {
4012031Slayer 	char	name_buf[124];
4112031Slayer 	long	file_pos;
4212031Slayer } tcNames[NOENTRIES];
4312031Slayer 
4412446Slayer struct Caps {
4512446Slayer 	char	*cap;
4612446Slayer 	char	*desc;
47*25326Sserge } capList[] =
4812446Slayer {
49*25326Sserge 	"AL",	"Add N new blank lines",
50*25326Sserge 	"CC",	"Command char in prototype if settable",
51*25326Sserge 	"DC",	"Delete N characters",
52*25326Sserge 	"DL",	"Delete N lines",
53*25326Sserge 	"DO",	"Move cursor down N lines",
54*25326Sserge 	"IC",	"Insert N blank characters",
55*25326Sserge 	"LE",	"Move cursor left N positions",
56*25326Sserge 	"RI",	"Move cursor right N positions",
57*25326Sserge 	"UP",	"Move cursor up N lines",
5812446Slayer 	"ae",	"End alternate character set",
5912446Slayer 	"al",	"Add new blank line",
6012446Slayer 	"am",	"Has automatic margins",
6112446Slayer 	"as",	"Start alternate character set",
6212446Slayer 	"bc",	"Backspace if not ^H",
63*25326Sserge 	"bl",	"Audible Bell (default ^G)",
6412446Slayer 	"bs",	"Can backspace with ^H",
6512446Slayer 	"bt",	"Back tab",
6612446Slayer 	"bw",	"Backspace wraps from col 0 to last col",
6712446Slayer 	"cd",	"Clear to end of display",
6812446Slayer 	"ce",	"Clear to end of line",
6912446Slayer 	"ch",	"Like cm, but horizontal motion only",
7012446Slayer 	"cl",	"Clear screen",
7112446Slayer 	"cm",	"Cursor motion",
7212446Slayer 	"co",	"Number of columns in a line",
73*25326Sserge 	"cr",	"Carriage return (default ^M)",
7412446Slayer 	"cs",	"Change scrolling region (vt100), like cm",
75*25326Sserge 	"ct",	"Clear all tab stops",
7612446Slayer 	"cv",	"Like ch but vertical only.",
77*25326Sserge 	"dB",	"Number of millisec of bs delay needed",
78*25326Sserge 	"dC",	"Number of millisec of cr delay needed",
79*25326Sserge 	"dF",	"Number of millisec of ff delay needed",
80*25326Sserge 	"dN",	"Number of millisec of nl delay needed",
81*25326Sserge 	"dT",	"Number of millisec of tab delay needed",
8212446Slayer 	"da",	"Display may be retained above",
8312446Slayer 	"db",	"Display may be retained below",
8412446Slayer 	"dc",	"Delete character",
8512446Slayer 	"dl",	"Delete line",
8612446Slayer 	"dm",	"Start Delete mode",
8712446Slayer 	"do",	"Down one line",
8812461Slayer 	"ds",	"Disable status display",
8912446Slayer 	"ed",	"End delete mode",
9012446Slayer 	"ei",	"End insert mode;give \":ei=:\" if ic",
9112446Slayer 	"eo",	"Can erase overstrikes with a blank",
9212461Slayer 	"es",	"Escape seq's ok on status line",
9312446Slayer 	"ff",	"Hardcopy page eject (default ^L)",
9412446Slayer 	"fs",	"From status line sequence",
9512446Slayer 	"hc",	"Hardcopy terminal",
9612446Slayer 	"hd",	"Half-line down (forward 1/2 lf)",
9712446Slayer 	"ho",	"Home cursor (if no cm)",
98*25326Sserge 	"hs",	"Has status line",
9912446Slayer 	"hu",	"Half-line up (reverse 1/2 lf)",
10012446Slayer 	"hz",	"Hazeltine; can't print ~'s",
101*25326Sserge 	"i2",	"Initialization string (used by sysline(1))",
10212446Slayer 	"ic",	"Insert character",
10312446Slayer 	"if",	"Name of file containing is",
10412446Slayer 	"im",	"Start insert mode;give \":im=:\" if ic",
10512446Slayer 	"in",	"Insert mode distinguishes nulls on display",
10612446Slayer 	"ip",	"Insert pad after character inserted",
10712446Slayer 	"is",	"Initialization string",
108*25326Sserge 	"k0",	"Sent by function key 0",
109*25326Sserge 	"k1",	"Sent by function key 1",
110*25326Sserge 	"k2",	"Sent by function key 2",
111*25326Sserge 	"k3",	"Sent by function key 3",
112*25326Sserge 	"k4",	"Sent by function key 4",
113*25326Sserge 	"k5",	"Sent by function key 5",
114*25326Sserge 	"k6",	"Sent by function key 6",
115*25326Sserge 	"k7",	"Sent by function key 7",
116*25326Sserge 	"k8",	"Sent by function key 8",
117*25326Sserge 	"k9",	"Sent by function key 9",
11812446Slayer 	"kb",	"Sent by backspace key",
119*25326Sserge 	"kd",	"Sent by down arrow key",
12012446Slayer 	"ke",	"Out of \"keypad transmit\" mode",
12112446Slayer 	"kh",	"Sent by home key",
12212446Slayer 	"kl",	"Sent by left arrow key",
123*25326Sserge 	"km",	"Has a \"meta\" key (shift, sets parity bit)",
12412446Slayer 	"kn",	"Number of \"other\" keys",
12512446Slayer 	"ko",	"Tc entries for other non-function keys",
12612446Slayer 	"kr",	"Sent by right arrow key",
12712446Slayer 	"ks",	"Put in \"keypad transmit\" mode",
12812446Slayer 	"ku",	"Sent by up arrow key",
129*25326Sserge 	"l0",	"Label on function key 0 (if not \"0\")",
130*25326Sserge 	"l1",	"Label on function key 1 (if not \"1\")",
131*25326Sserge 	"l2",	"Label on function key 2 (if not \"2\")",
132*25326Sserge 	"l3",	"Label on function key 3 (if not \"3\")",
133*25326Sserge 	"l4",	"Label on function key 4 (if not \"4\")",
134*25326Sserge 	"l5",	"Label on function key 5 (if not \"5\")",
135*25326Sserge 	"l6",	"Label on function key 6 (if not \"6\")",
136*25326Sserge 	"l7",	"Label on function key 7 (if not \"7\")",
137*25326Sserge 	"l8",	"Label on function key 8 (if not \"8\")",
138*25326Sserge 	"l9",	"Label on function key 9 (if not \"9\")",
13913250Slayer 	"le",	"Move left",
14012446Slayer 	"li",	"Number of lines on screen or page",
14112446Slayer 	"ll",	"Last line, first column (if no cm)",
14212446Slayer 	"ma",	"Arrow key map, used by vi V2 only",
14313250Slayer 	"mb",	"Enter blinking mode",
14413250Slayer 	"md",	"Enter bold mode",
14513250Slayer 	"me",	"Reset video attributes",
14613250Slayer 	"mh",	"Enter halfbright mode",
14712446Slayer 	"mi",	"Safe to move while in insert mode",
14813250Slayer 	"mk",	"Enter protected mode",
14912446Slayer 	"ml",	"Memory lock on above cursor.",
150*25326Sserge 	"mp",	"Turn on protected attribute",
15113250Slayer 	"mr",	"Enter reverse video mode",
15212446Slayer 	"ms",	"Ok to move while in standout/underline mode",
15312446Slayer 	"mu",	"Memory unlock (turn off memory lock).",
15412446Slayer 	"nc",	"No working CR (DM2500,H2000)",
15512446Slayer 	"nd",	"Non-destructive space (cursor right)",
15612446Slayer 	"nl",	"Newline character (default \\n)",
15712446Slayer 	"ns",	"Is a CRT but doesn't scroll.",
15812446Slayer 	"os",	"Terminal overstrikes",
159*25326Sserge 	"pb",	"Lowest baud where delays are required",
16012446Slayer 	"pc",	"Pad character (rather than null)",
161*25326Sserge 	"pl",	"Program function key N to execute string S (terminfo only)",
16212446Slayer 	"pt",	"Has hardware tabs (may need to use is)",
163*25326Sserge 	"rc",	"Restore cursor to position of last sc",
164*25326Sserge 	"rf",	"Name of file containing reset codes",
165*25326Sserge 	"rs",	"Reset terminal completely to sane modes",
166*25326Sserge 	"sc",	"Save cursor position",
16712446Slayer 	"se",	"End stand out mode",
16812446Slayer 	"sf",	"Scroll forwards",
16912446Slayer 	"sg",	"Number of blank chars left by so/se",
17012446Slayer 	"so",	"Begin stand out mode",
17112446Slayer 	"sr",	"Scroll reverse (backwards)",
172*25326Sserge 	"st",	"Set a tab in all rows, current column",
17312446Slayer 	"ta",	"Tab (other than ^I or with padding)",
17412446Slayer 	"tc",	"Entry of similar terminal - must be last",
17512446Slayer 	"te",	"String to end programs that use cm",
17612446Slayer 	"ti",	"String to begin programs that use cm",
17712446Slayer 	"ts",	"To status line sequence",
17812446Slayer 	"uc",	"Underscore one char and move past it",
17912446Slayer 	"ue",	"End underscore mode",
18012446Slayer 	"ug",	"Number of blank chars left by us or ue",
18112446Slayer 	"ul",	"Underlines, though no overstrike",
18212446Slayer 	"up",	"Upline (cursor up)",
18312446Slayer 	"us",	"Start underscore mode",
18412446Slayer 	"vb",	"Visible bell (may not move cursor)",
18512446Slayer 	"ve",	"Sequence to end open/visual mode",
18612446Slayer 	"vs",	"Sequence to start open/visual mode",
187*25326Sserge 	"vt",	"Virtual terminal number (not supported on all systems)",
18812446Slayer 	"xb",	"Beehive (f1=escape, f2=ctrl C)",
18912446Slayer 	"xn",	"A newline is ignored after a wrap (Concept)",
19012446Slayer 	"xr",	"Return acts like ce \\r \\n (Delta Data)",
19112446Slayer 	"xs",	"Standout not erased by writing over it (HP 264?)",
19212446Slayer 	"xt",	"Destructive tabs, magic so char (Teleray 1061)"
19312446Slayer };
19412446Slayer 
195*25326Sserge #define NOCAPS	(sizeof capList / sizeof *capList)
196*25326Sserge 
19712031Slayer #ifdef DEBUG
19812031Slayer int		Dflag = NO;
19912031Slayer #endif
20012031Slayer int		xflag = NO;
20112044Slayer int		Sflag = YES;
20212044Slayer int		sflag = NO;
20312031Slayer int		dflag = NO;
20412031Slayer int		nflag = NO;
20512031Slayer int		gflag = NO;
20612031Slayer int		bflag = NO;
20713250Slayer int		Uflag = NO;
20812031Slayer int		tc_loopc;		/* loop counter */
20912031Slayer char		*tcfile;		/* termcap database pathname */
21015192Slayer char		tcbuf[2048];		/* buffer for termcap description */
21112031Slayer char		*lastchar();
21212031Slayer int		name_cmp();
21312031Slayer int		ent_cmp();
21412031Slayer struct TcName	*find_name();
21512031Slayer char		*getenv();
21612031Slayer char		*ctime();
21712031Slayer char		*strncpy();
21812031Slayer long		ftell();
21912031Slayer 
22012031Slayer main(argc, argv, envp)
22112031Slayer 	int		argc;
22212031Slayer 	char		**argv;
22312031Slayer 	char		**envp;
22412031Slayer {
22512031Slayer 	char		*av;
22612031Slayer 	struct TcName	*tn;
22712031Slayer 	register char	*bp;
22812031Slayer 	long		pos;
22912031Slayer 	int		n;
23012031Slayer 	struct stat	st;
23112031Slayer 	char		envbuf[256];
23212031Slayer 	FILE		*tcfp;
23312031Slayer 
23412031Slayer 	if ((bp = getenv("TERMCAP")) && *bp == '/')
23512031Slayer 		tcfile = bp;
23612031Slayer 	else
23712031Slayer 		tcfile = "/etc/termcap";
23812031Slayer 
23912031Slayer 	while (--argc > 0)
24012031Slayer 	{
24112031Slayer 		if (*(av = *++argv) == '-')
24212031Slayer 		{
24312031Slayer 			while (*++av)
24412031Slayer 			{
24512031Slayer 				switch (*av)
24612031Slayer 				{
24712031Slayer 				/* use alternate termcap file */
24812031Slayer 				case 'f':
24912031Slayer 					if (argc-- <= 0)
25012031Slayer 					{
25112031Slayer 						fprintf(stderr,
25212031Slayer 						    "-f needs a filename\n");
25312031Slayer 						exit(1);
25412031Slayer 					}
25512031Slayer 					tcfile = *++argv;
25612031Slayer 					break;
25712031Slayer 
25812031Slayer 				/* only check for dup names */
25912458Slayer 				case 'd':
26012031Slayer 					nflag = YES;
26112031Slayer 					/* fall thru */
26212031Slayer 
26312031Slayer 				/* look for duplicated names */
26412458Slayer 				case 'D':
26512031Slayer 					dflag = YES;
26612031Slayer 					continue;
26712031Slayer 
26813250Slayer 				case 'U':
26913250Slayer 					Uflag = YES;
27013250Slayer 					continue;
27113250Slayer 
27212044Slayer 				/* strip the two name off */
27312044Slayer 				case 's':
27412044Slayer 					sflag = YES;
27512044Slayer 					continue;
27612044Slayer 
27712031Slayer 				/* sort the name array */
27812031Slayer 				case 'S':
27912044Slayer 					Sflag = NO;
28012031Slayer 					continue;
28112031Slayer 
28212031Slayer #ifdef DEBUG
28312458Slayer 				case 'T':
28412031Slayer 					Dflag = YES;
28512031Slayer 					continue;
28612031Slayer #endif
28712031Slayer 
28812031Slayer 				/* sort on generic names */
28912031Slayer 				case 'g':
29012031Slayer 					gflag = YES;
29112031Slayer 					continue;
29212031Slayer 
29312031Slayer 				/* expand entries in 'full mode' */
29412031Slayer 				case 'x':
29512031Slayer 					xflag = YES;
29612031Slayer 					continue;
29712031Slayer 
29812031Slayer 				/* show bare entry */
29912031Slayer 				case 'b':
30012031Slayer 					bflag = YES;
30112031Slayer 					continue;
30212031Slayer 
30312031Slayer 				default:
30412031Slayer 					fprintf(stderr, "showtc: unknown flag: -%c\n", *av);
30512031Slayer 					fprintf(stderr, USAGE, argv[0]);
30612031Slayer 					exit(1);
30712031Slayer 				}
30812031Slayer 			}
30912031Slayer 		}
31012031Slayer 		else
31112031Slayer 			break;
31212031Slayer 	}
31312031Slayer 
31412031Slayer 	/*
31512031Slayer 	 * insert the specified TERMCAP file into the environment
31612031Slayer 	 */
31712031Slayer 	(void) sprintf(envbuf, "TERMCAP=%s", tcfile);
31812031Slayer 	while (*envp)
31912031Slayer 	{
32012031Slayer 		if (strncmp(*envp, "TERMCAP=", 8) == 0)
32112031Slayer 		{
32212031Slayer 			*envp = envbuf;
32312031Slayer 			break;
32412031Slayer 		}
32512031Slayer 		envp++;
32612031Slayer 	}
32712031Slayer 	if (! *envp)
32812031Slayer 		*envp = envbuf;	/* this may be dangerous */
32912031Slayer 
33012031Slayer 	/*
33112031Slayer 	** if user specified type(s), do only those
33212031Slayer 	*/
33312031Slayer 	if (argc > 0)
33412031Slayer 	{
33512031Slayer 		/*
33612031Slayer 		** look for the users specified term types
33712031Slayer 		*/
33812031Slayer 		while (argc > 0)
33912031Slayer 		{
34012031Slayer 			switch (n = tgetent(tcbuf, *argv))
34112031Slayer 			{
34212031Slayer 				case 1:
34312031Slayer 					if (bflag)
34412031Slayer 						(void) prnt_raw(tcbuf);
34512031Slayer 					else
34612031Slayer 						(void) prnt_ent(tcbuf);
34712031Slayer 					break;
34812031Slayer 
34912031Slayer 				case 0:
35012031Slayer 					fprintf(stderr,
35112031Slayer 					   "showtc: bad entry: %s\n", *argv);
35212031Slayer 					break;
35312031Slayer 
35412031Slayer 				case -1:
35512031Slayer 					fputs("showtc: ", stderr);
35612031Slayer 					perror(tcfile);
35712031Slayer 					exit(1);
35812031Slayer 
35912031Slayer 				default:
36012031Slayer 					fprintf(stderr, "bad return from tgetent: %d\n", n);
36112031Slayer 					exit(1);
36212031Slayer 			}
36312031Slayer 			argc--;
36412031Slayer 			argv++;
36512031Slayer 		}
36612031Slayer 		exit(0);
36712031Slayer 	}
36812031Slayer 
36912031Slayer 	if (bflag)
37012031Slayer 	{
37112031Slayer  		fprintf(stderr, "showtc: -b flag with no entries makes no sense.\n");
37212031Slayer 		exit(1);
37312031Slayer 	}
37412031Slayer 
37512031Slayer 
37612031Slayer 	/*
37712031Slayer 	** if no type was specified, do the whole file
37812031Slayer 	*/
37912031Slayer 	if ((tcfp = fopen(tcfile, "r")) == NULL)
38012031Slayer 	{
38112031Slayer 		perror(tcfile);
38212031Slayer 		exit(1);
38312031Slayer 	}
38412031Slayer 
38512031Slayer 	/*
38612031Slayer 	** identify database, for the record
38712031Slayer 	*/
38812031Slayer 	if (stat(tcfile, &st))
38912031Slayer 	{
39012031Slayer 		perror(tcfile);
39112031Slayer 		exit(1);
39212031Slayer 	}
39312031Slayer 	printf("File: %s, last modified: %s\n", tcfile, ctime(&st.st_mtime));
39412031Slayer 
39512031Slayer 
39612031Slayer 	/*
39712031Slayer 	** build termcap entry table
39812031Slayer 	*/
39912031Slayer 	tn = tcNames;
40012031Slayer 	pos = ftell(tcfp);
40112031Slayer 	bp = tcbuf;
40212031Slayer 	while (fgets(bp, sizeof (tcbuf), tcfp) != NULL)
40312031Slayer 	{
40412031Slayer 		if (tcbuf[0] == '#')
40512031Slayer 		{
40612031Slayer 			pos = ftell(tcfp);
40712031Slayer 			bp = tcbuf;
40812031Slayer 			continue;
40912031Slayer 		}
41012031Slayer 
41112031Slayer 		tn->file_pos = pos;
41212031Slayer 
41312031Slayer 		/*
41412031Slayer 		** get full entry
41512031Slayer 		*/
41612031Slayer 		while (*(bp = lastchar(bp)) == '\\' && fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp))
41712031Slayer 			;
41812031Slayer 		/*
41912031Slayer 		** save the names
42012031Slayer 		*/
42112031Slayer 		for (bp = tcbuf; *bp && *bp != ':'; bp++)
42212031Slayer 			;
42312031Slayer 		*bp = '\0';
42412031Slayer 		(void) strncpy(tn->name_buf, tcbuf,
42512031Slayer 				sizeof tcNames[0].name_buf);
42612031Slayer 
42712031Slayer 		pos = ftell(tcfp);
42812031Slayer 		bp = tcbuf;
42912031Slayer 		tn++;
43012031Slayer 	}
43112031Slayer 	tn->file_pos = -1;
43212031Slayer 
43312031Slayer 	/*
43412031Slayer 	** Look for duplicate names
43512031Slayer 	*/
43612031Slayer 	if (dflag)
43712031Slayer 		check_dup();
43812031Slayer 	if (nflag)
43912031Slayer 		exit(0);
44012031Slayer 
44112031Slayer #ifdef DEBUG
44212031Slayer 	if (Dflag)
44312031Slayer 	{
44412031Slayer 		for (tn = tcNames; tn->file_pos >= 0; tn++)
44512031Slayer 		{
44612031Slayer 			printf("Entry #%d:\n\t%s\n\tfile_pos = %ld\n",
44712031Slayer 			tn - tcNames, tn->name_buf, tn->file_pos);
44812031Slayer 		}
44912031Slayer 		exit(0);
45012031Slayer 	}
45112031Slayer #endif
45212031Slayer 
45312031Slayer 	/*
45412031Slayer 	** Order the list
45512031Slayer 	*/
45612044Slayer 	if (Sflag)
45712031Slayer 		qsort((char *)tcNames, tn - tcNames,
45812031Slayer 			sizeof (struct TcName), name_cmp);
45912031Slayer 
46012031Slayer 	/*
46112031Slayer 	** List termcap entry for each name in table
46212031Slayer 	*/
46312031Slayer 	for (tn = tcNames; tn->file_pos >= 0; tn++)
46412031Slayer 	{
46512031Slayer 		tc_loopc = 0;
46612031Slayer 		/*** working toward this ...
46712031Slayer 		(void) prnt_ent(tn);
46812031Slayer 		***/
46912031Slayer 		(void) fseek(tcfp, tn->file_pos, 0);
47012031Slayer 		bp = tcbuf;
47112031Slayer 		while (fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp)
47212031Slayer 			&& *(bp = lastchar(bp)) == '\\')
47312031Slayer 			;
47412031Slayer 		(void) prnt_ent(tcbuf);
47512031Slayer 	}
47612031Slayer }
47712031Slayer 
47812031Slayer char *
47912031Slayer lastchar(b)
48012031Slayer 	char	*b;
48112031Slayer {
48212031Slayer 	register char	*p;
48312031Slayer 
48412031Slayer 	p = b + strlen(b) - 1;
48512031Slayer 	while (*p == '\n' || *p == ' ')
48612031Slayer 		p--;
48712031Slayer 	return(p);
48812031Slayer }
48912031Slayer 
49012031Slayer name_cmp(a, b)
49112031Slayer 	char	*a, *b;
49212031Slayer {
49312031Slayer 	if (gflag)	/* sort on generic names */
49412031Slayer 	{
49512031Slayer 		a += 3;
49612031Slayer 		b += 3;
49712031Slayer 		while (*a && *b && *a != '|' && *a == *b)
49812031Slayer 		{
49912031Slayer 			a++;
50012031Slayer 			b++;
50112031Slayer 		}
50212031Slayer 		if (*a == '|' || *a == CNULL)
50312031Slayer 			return((*b == '|' || *b == CNULL)? 0:-1);
50412031Slayer 		if (*b == '|' || *b == CNULL)
50512031Slayer 			return(1);
50612031Slayer 		return(*a - *b);
50712031Slayer 	}
50812031Slayer 	return(strncmp(a, b, 2));
50912031Slayer }
51012031Slayer 
51112031Slayer prnt_ent(buf)
51212031Slayer 	register char	*buf;
51312031Slayer {
51412031Slayer 	register char	*name;
51512446Slayer 	char		*getdesc();
51612031Slayer 	char		*caps[256];
51712031Slayer 	register char	**cp;
51812031Slayer 	register char	**tp;
51912031Slayer 	char		tname[3];
52012031Slayer 
52112031Slayer 	cp = caps;
52212031Slayer 	name = buf;
52312031Slayer 	tname[3] = '\0';
52412031Slayer 
52512031Slayer 	while (*buf)
52612031Slayer 	{
52712031Slayer 		switch (*buf)
52812031Slayer 		{
52912031Slayer 		case ':':
53012031Slayer 			*buf++ = '\0';
53112031Slayer 			while (*buf && !isalnum(*buf))
53212031Slayer 				buf++;
53312031Slayer 			if (*buf)
53412031Slayer 			{
53512031Slayer 				/*
53612031Slayer 				 * ignore duplicate cap entries
53712031Slayer 				 */
53812031Slayer 				for (tp = caps; tp < cp; tp++)
53912031Slayer 					if (strncmp(buf, *tp, 2) == 0)
54012031Slayer 						goto skip;
54112031Slayer 				*cp++ = buf;
54212031Slayer 			skip:
54312031Slayer 				/*
54412031Slayer 				 * does user want tc= expanded?
54512031Slayer 				 */
54612031Slayer 				if (xflag && strncmp(buf, "tc=", 3) == 0)
54712031Slayer 				{
54812031Slayer 					/*
54912031Slayer 					 * find end of tc=
55012031Slayer 					 */
55112031Slayer 					while (*buf != ':')
55212031Slayer 						buf++;
55312031Slayer 					*buf = '\0';
55412031Slayer 					/*
55512031Slayer 					 * save term name
55612031Slayer 					 */
55712031Slayer 					tname[0] = name[0];
55812031Slayer 					tname[1] = name[1];
55912031Slayer 					printf("%s: expanding %s\n",
56012031Slayer 						tname, cp[-1]);
56112031Slayer 					/*
56212031Slayer 					 * let tgetent do the work
56312031Slayer 					 */
56412031Slayer 					tgetent(tcbuf, tname);
56512031Slayer 					prnt_ent(tcbuf);
56612031Slayer 					return;
56712031Slayer 				}
56812031Slayer 			}
56912031Slayer 			continue;
57012031Slayer 
57112031Slayer 		case '|':
57212031Slayer 			*buf++ = ',';
57312031Slayer 			continue;
57412031Slayer 
57512031Slayer 		default:
57612031Slayer 			buf++;
57712031Slayer 		}
57812031Slayer 	}
57912031Slayer 	*cp = CNULL;		/* was (char *)0 */
58012031Slayer 
58112044Slayer 	if (Sflag)
58212031Slayer 		qsort((char *) caps, cp - caps, sizeof (char *), ent_cmp);
58312031Slayer 
58412031Slayer 	printf("%s\n", name);
58512031Slayer 	for (cp = caps; *cp; cp++)
58613250Slayer 		if (Uflag) {
58713250Slayer 			if (unknowncap(*cp)) {
58813250Slayer 				printf("%3.3s\n", *cp);
58913250Slayer 			}
59013250Slayer 		} else if (sflag) {
59112446Slayer 			printf("%-45s %s\n", getdesc(*cp), *cp);
59213250Slayer 		} else {
59312446Slayer 			printf("%2.2s  %-45s %s\n", name, getdesc(*cp), *cp);
59412446Slayer 		}
59512031Slayer 	(void) putchar('\n');
59612031Slayer }
59712031Slayer 
59812031Slayer prnt_raw(buf)
59912031Slayer 	char		*buf;
60012031Slayer {
60112031Slayer 	register char	*b;
60212031Slayer 	register int	len;
60312031Slayer 	register int	n;
60412031Slayer 	char		*index();
60512031Slayer 
60612031Slayer 	len = 0;
60712031Slayer 	b = buf;
60812031Slayer 	while (*b)
60912031Slayer 	{
61012031Slayer 		if ((n = index(b, ':') - b + 1) <= 0)
61112031Slayer 			n = strlen(b);
61212031Slayer 		if (len == 0)			/* first part */
61312031Slayer 		{
61412031Slayer 			printf("%.*s\\\n\t:", n, b);
61512031Slayer 			len = 9 - n;
61612031Slayer 		}
61712031Slayer 		else
61812031Slayer 		{
61912031Slayer 			if ((len + n) >= 75)
62012031Slayer 			{
62112031Slayer 				printf("\\\n\t:");
62212031Slayer 				len = 9;
62312031Slayer 			}
62412031Slayer 			printf("%.*s", n, b);
62512031Slayer 		}
62612031Slayer 		len += n;
62712031Slayer 		b += n;
62812031Slayer 		while (*b && index(" \t:\n", *b))
62912031Slayer 			b++;
63012031Slayer 	}
63112031Slayer 	if (b[-1] != ':')
63212031Slayer 		(void) putchar(':');
63312031Slayer 	(void) putchar('\n');
63412031Slayer }
63512031Slayer 
63612031Slayer ent_cmp(a, b)
63712031Slayer 	char **a, **b;
63812031Slayer {
63912031Slayer 	return(strncmp(*a, *b, 2));
64012031Slayer }
64112031Slayer 
64212031Slayer check_dup()
64312031Slayer {
64412031Slayer 	/*
64512031Slayer 	** Look for duplicated names
64612031Slayer 	*/
64712031Slayer 	register char		*p;
64812031Slayer 	register char		*q;
64912031Slayer 	register struct TcName	*tn;
65012031Slayer 	register struct TcName	*tm;
65112031Slayer 
65212031Slayer 	tn = tcNames;
65312031Slayer 	while (tn->file_pos >= 0)
65412031Slayer 	{
65512031Slayer 		p = q = tn->name_buf;
65612031Slayer 		while (*q)
65712031Slayer 		{
65812031Slayer 			while (*p && *p != '|')
65912031Slayer 				p++;
66012031Slayer 			if (p != q && (tm = find_name(q, tn + 1, p - q)))
66112031Slayer 			{
66212031Slayer 				fputs("Duplicate name: ", stdout);
66312031Slayer 				while (q != p)
66412031Slayer 					(void) putchar(*q++);
66512031Slayer 				(void) putchar('\n');
66612031Slayer 				puts(tn->name_buf);
66712031Slayer 				puts(tm->name_buf);
66812031Slayer 				puts("---\n");
66912031Slayer 			}
67012031Slayer 			if (*p == '|')
67112031Slayer 				p++;
67212031Slayer 			q = p;
67312031Slayer 		}
67412031Slayer 		tn++;
67512031Slayer 	}
67612031Slayer }
67712031Slayer 
67812031Slayer struct TcName *
67912031Slayer find_name(name, tn, len)
68012031Slayer 	register char		*name;
68112031Slayer 	register struct TcName	*tn;
68212031Slayer 	register int		len;
68312031Slayer {
68412031Slayer 	/*
68512031Slayer 	** find name of length len in tcname structure buffers.
68612031Slayer 	*/
68712031Slayer 	register char	*p;
68812031Slayer 	register char	*buf;
68912031Slayer 	register int	 n;
69012031Slayer 
69112031Slayer 	while (tn->file_pos >= 0)
69212031Slayer 	{
69312031Slayer 		buf = tn->name_buf;
69412031Slayer 		while (*buf)
69512031Slayer 		{
69612031Slayer 			p = name;
69712031Slayer 			n = len;
69812031Slayer 			if (*buf == '|')
69912031Slayer 				buf++;
70012031Slayer 
70112031Slayer 			while (*buf && *buf != '|')
70212031Slayer 			{
70312031Slayer 				if (*p != *buf)
70412031Slayer 				{
70512031Slayer 					while (*buf && *buf != '|')
70612031Slayer 						buf++;
70712031Slayer 					break;
70812031Slayer 				}
70912031Slayer 
71012031Slayer 				if (--n <= 0)
71112031Slayer 				{
71212031Slayer 					buf++;
71312031Slayer 					if (*buf == '|' || *buf == '\0')
71412031Slayer 						return(tn);
71512031Slayer 					while (*buf && *buf != '|')
71612031Slayer 						buf++;
71712031Slayer 					break;
71812031Slayer 				}
71912031Slayer 				buf++;
72012031Slayer 				p++;
72112031Slayer 			}
72212031Slayer 		}
72312031Slayer 		tn++;
72412031Slayer 	}
72512031Slayer 	return((struct TcName *)0);
72612031Slayer }
72712446Slayer 
72812446Slayer char *
72912446Slayer getdesc(key)
73012446Slayer 	char		*key;
73112446Slayer {
73212446Slayer 	register int	i;
73312446Slayer 
73412446Slayer 	for (i = 0; i <= NOCAPS; i++)
73512446Slayer 		if (strncmp(key, capList[i].cap, 2) == 0)
73612446Slayer 			return (capList[i].desc);
73712458Slayer 	return("");
73812446Slayer }
73913250Slayer 
74013250Slayer unknowncap(key)
74113250Slayer 	char		*key;
74213250Slayer {
74313250Slayer 	register int	i;
74413250Slayer 
74513250Slayer 	for (i = 0; i <= NOCAPS; i++)
74613250Slayer 		if (strncmp(key, capList[i].cap, 2) == 0)
74713250Slayer 			return (0);
74813250Slayer 	return(1);
74913250Slayer }
750