xref: /csrg-svn/local/local.cmd/showtc.c (revision 25372)
125326Sserge #ifndef lint
2*25372Sserge static char *sccsid="@(#)showtc.c	1.9	(Berkeley) 11/01/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>
30*25372Sserge #include <sys/param.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 
39*25372Sserge #ifndef	MAXPATHLEN
40*25372Sserge #define MAXPATHLEN	1024
41*25372Sserge #endif
42*25372Sserge 
4312031Slayer struct TcName {
4412031Slayer 	char	name_buf[124];
4512031Slayer 	long	file_pos;
4612031Slayer } tcNames[NOENTRIES];
4712031Slayer 
4812446Slayer struct Caps {
4912446Slayer 	char	*cap;
5012446Slayer 	char	*desc;
5125326Sserge } capList[] =
5212446Slayer {
5325326Sserge 	"AL",	"Add N new blank lines",
5425326Sserge 	"CC",	"Command char in prototype if settable",
5525326Sserge 	"DC",	"Delete N characters",
5625326Sserge 	"DL",	"Delete N lines",
5725326Sserge 	"DO",	"Move cursor down N lines",
5825326Sserge 	"IC",	"Insert N blank characters",
5925326Sserge 	"LE",	"Move cursor left N positions",
6025326Sserge 	"RI",	"Move cursor right N positions",
6125326Sserge 	"UP",	"Move cursor up N lines",
6212446Slayer 	"ae",	"End alternate character set",
6312446Slayer 	"al",	"Add new blank line",
6412446Slayer 	"am",	"Has automatic margins",
6512446Slayer 	"as",	"Start alternate character set",
6612446Slayer 	"bc",	"Backspace if not ^H",
6725326Sserge 	"bl",	"Audible Bell (default ^G)",
6812446Slayer 	"bs",	"Can backspace with ^H",
6912446Slayer 	"bt",	"Back tab",
7012446Slayer 	"bw",	"Backspace wraps from col 0 to last col",
7112446Slayer 	"cd",	"Clear to end of display",
7212446Slayer 	"ce",	"Clear to end of line",
7312446Slayer 	"ch",	"Like cm, but horizontal motion only",
7412446Slayer 	"cl",	"Clear screen",
7512446Slayer 	"cm",	"Cursor motion",
7612446Slayer 	"co",	"Number of columns in a line",
7725326Sserge 	"cr",	"Carriage return (default ^M)",
7812446Slayer 	"cs",	"Change scrolling region (vt100), like cm",
7925326Sserge 	"ct",	"Clear all tab stops",
8012446Slayer 	"cv",	"Like ch but vertical only.",
8125326Sserge 	"dB",	"Number of millisec of bs delay needed",
8225326Sserge 	"dC",	"Number of millisec of cr delay needed",
8325326Sserge 	"dF",	"Number of millisec of ff delay needed",
8425326Sserge 	"dN",	"Number of millisec of nl delay needed",
8525326Sserge 	"dT",	"Number of millisec of tab delay needed",
8612446Slayer 	"da",	"Display may be retained above",
8712446Slayer 	"db",	"Display may be retained below",
8812446Slayer 	"dc",	"Delete character",
8912446Slayer 	"dl",	"Delete line",
9012446Slayer 	"dm",	"Start Delete mode",
9112446Slayer 	"do",	"Down one line",
9212461Slayer 	"ds",	"Disable status display",
9312446Slayer 	"ed",	"End delete mode",
9412446Slayer 	"ei",	"End insert mode;give \":ei=:\" if ic",
9512446Slayer 	"eo",	"Can erase overstrikes with a blank",
9612461Slayer 	"es",	"Escape seq's ok on status line",
9712446Slayer 	"ff",	"Hardcopy page eject (default ^L)",
9812446Slayer 	"fs",	"From status line sequence",
9912446Slayer 	"hc",	"Hardcopy terminal",
10012446Slayer 	"hd",	"Half-line down (forward 1/2 lf)",
10112446Slayer 	"ho",	"Home cursor (if no cm)",
10225326Sserge 	"hs",	"Has status line",
10312446Slayer 	"hu",	"Half-line up (reverse 1/2 lf)",
10412446Slayer 	"hz",	"Hazeltine; can't print ~'s",
10525326Sserge 	"i2",	"Initialization string (used by sysline(1))",
10612446Slayer 	"ic",	"Insert character",
10712446Slayer 	"if",	"Name of file containing is",
10812446Slayer 	"im",	"Start insert mode;give \":im=:\" if ic",
10912446Slayer 	"in",	"Insert mode distinguishes nulls on display",
11012446Slayer 	"ip",	"Insert pad after character inserted",
11112446Slayer 	"is",	"Initialization string",
11225326Sserge 	"k0",	"Sent by function key 0",
11325326Sserge 	"k1",	"Sent by function key 1",
11425326Sserge 	"k2",	"Sent by function key 2",
11525326Sserge 	"k3",	"Sent by function key 3",
11625326Sserge 	"k4",	"Sent by function key 4",
11725326Sserge 	"k5",	"Sent by function key 5",
11825326Sserge 	"k6",	"Sent by function key 6",
11925326Sserge 	"k7",	"Sent by function key 7",
12025326Sserge 	"k8",	"Sent by function key 8",
12125326Sserge 	"k9",	"Sent by function key 9",
12212446Slayer 	"kb",	"Sent by backspace key",
12325326Sserge 	"kd",	"Sent by down arrow key",
12412446Slayer 	"ke",	"Out of \"keypad transmit\" mode",
12512446Slayer 	"kh",	"Sent by home key",
12612446Slayer 	"kl",	"Sent by left arrow key",
12725326Sserge 	"km",	"Has a \"meta\" key (shift, sets parity bit)",
12812446Slayer 	"kn",	"Number of \"other\" keys",
12912446Slayer 	"ko",	"Tc entries for other non-function keys",
13012446Slayer 	"kr",	"Sent by right arrow key",
13112446Slayer 	"ks",	"Put in \"keypad transmit\" mode",
13212446Slayer 	"ku",	"Sent by up arrow key",
13325326Sserge 	"l0",	"Label on function key 0 (if not \"0\")",
13425326Sserge 	"l1",	"Label on function key 1 (if not \"1\")",
13525326Sserge 	"l2",	"Label on function key 2 (if not \"2\")",
13625326Sserge 	"l3",	"Label on function key 3 (if not \"3\")",
13725326Sserge 	"l4",	"Label on function key 4 (if not \"4\")",
13825326Sserge 	"l5",	"Label on function key 5 (if not \"5\")",
13925326Sserge 	"l6",	"Label on function key 6 (if not \"6\")",
14025326Sserge 	"l7",	"Label on function key 7 (if not \"7\")",
14125326Sserge 	"l8",	"Label on function key 8 (if not \"8\")",
14225326Sserge 	"l9",	"Label on function key 9 (if not \"9\")",
14313250Slayer 	"le",	"Move left",
14412446Slayer 	"li",	"Number of lines on screen or page",
14512446Slayer 	"ll",	"Last line, first column (if no cm)",
14612446Slayer 	"ma",	"Arrow key map, used by vi V2 only",
14713250Slayer 	"mb",	"Enter blinking mode",
14813250Slayer 	"md",	"Enter bold mode",
14913250Slayer 	"me",	"Reset video attributes",
15013250Slayer 	"mh",	"Enter halfbright mode",
15112446Slayer 	"mi",	"Safe to move while in insert mode",
15213250Slayer 	"mk",	"Enter protected mode",
15312446Slayer 	"ml",	"Memory lock on above cursor.",
15425326Sserge 	"mp",	"Turn on protected attribute",
15513250Slayer 	"mr",	"Enter reverse video mode",
15612446Slayer 	"ms",	"Ok to move while in standout/underline mode",
15712446Slayer 	"mu",	"Memory unlock (turn off memory lock).",
15812446Slayer 	"nc",	"No working CR (DM2500,H2000)",
15912446Slayer 	"nd",	"Non-destructive space (cursor right)",
16012446Slayer 	"nl",	"Newline character (default \\n)",
16112446Slayer 	"ns",	"Is a CRT but doesn't scroll.",
16212446Slayer 	"os",	"Terminal overstrikes",
16325326Sserge 	"pb",	"Lowest baud where delays are required",
16412446Slayer 	"pc",	"Pad character (rather than null)",
16525326Sserge 	"pl",	"Program function key N to execute string S (terminfo only)",
16612446Slayer 	"pt",	"Has hardware tabs (may need to use is)",
16725326Sserge 	"rc",	"Restore cursor to position of last sc",
16825326Sserge 	"rf",	"Name of file containing reset codes",
16925326Sserge 	"rs",	"Reset terminal completely to sane modes",
17025326Sserge 	"sc",	"Save cursor position",
17112446Slayer 	"se",	"End stand out mode",
17212446Slayer 	"sf",	"Scroll forwards",
17312446Slayer 	"sg",	"Number of blank chars left by so/se",
17412446Slayer 	"so",	"Begin stand out mode",
17512446Slayer 	"sr",	"Scroll reverse (backwards)",
17625326Sserge 	"st",	"Set a tab in all rows, current column",
17712446Slayer 	"ta",	"Tab (other than ^I or with padding)",
17812446Slayer 	"tc",	"Entry of similar terminal - must be last",
17912446Slayer 	"te",	"String to end programs that use cm",
18012446Slayer 	"ti",	"String to begin programs that use cm",
18112446Slayer 	"ts",	"To status line sequence",
18212446Slayer 	"uc",	"Underscore one char and move past it",
18312446Slayer 	"ue",	"End underscore mode",
18412446Slayer 	"ug",	"Number of blank chars left by us or ue",
18512446Slayer 	"ul",	"Underlines, though no overstrike",
18612446Slayer 	"up",	"Upline (cursor up)",
18712446Slayer 	"us",	"Start underscore mode",
18812446Slayer 	"vb",	"Visible bell (may not move cursor)",
18912446Slayer 	"ve",	"Sequence to end open/visual mode",
19012446Slayer 	"vs",	"Sequence to start open/visual mode",
19125326Sserge 	"vt",	"Virtual terminal number (not supported on all systems)",
19212446Slayer 	"xb",	"Beehive (f1=escape, f2=ctrl C)",
19312446Slayer 	"xn",	"A newline is ignored after a wrap (Concept)",
19412446Slayer 	"xr",	"Return acts like ce \\r \\n (Delta Data)",
19512446Slayer 	"xs",	"Standout not erased by writing over it (HP 264?)",
19612446Slayer 	"xt",	"Destructive tabs, magic so char (Teleray 1061)"
19712446Slayer };
19812446Slayer 
19925326Sserge #define NOCAPS	(sizeof capList / sizeof *capList)
20025326Sserge 
20112031Slayer #ifdef DEBUG
20212031Slayer int		Dflag = NO;
20312031Slayer #endif
20412031Slayer int		xflag = NO;
20512044Slayer int		Sflag = YES;
20612044Slayer int		sflag = NO;
20712031Slayer int		dflag = NO;
20812031Slayer int		nflag = NO;
20912031Slayer int		gflag = NO;
21012031Slayer int		bflag = NO;
21113250Slayer int		Uflag = NO;
21212031Slayer int		tc_loopc;		/* loop counter */
21312031Slayer char		*tcfile;		/* termcap database pathname */
214*25372Sserge char		cwd[MAXPATHLEN];	/* current working directory */
21515192Slayer char		tcbuf[2048];		/* buffer for termcap description */
21612031Slayer char		*lastchar();
21712031Slayer int		name_cmp();
21812031Slayer int		ent_cmp();
21912031Slayer struct TcName	*find_name();
22012031Slayer char		*getenv();
22112031Slayer char		*ctime();
22212031Slayer char		*strncpy();
22312031Slayer long		ftell();
22412031Slayer 
main(argc,argv,envp)22512031Slayer main(argc, argv, envp)
22612031Slayer 	int		argc;
22712031Slayer 	char		**argv;
22812031Slayer 	char		**envp;
22912031Slayer {
23012031Slayer 	char		*av;
23112031Slayer 	struct TcName	*tn;
23212031Slayer 	register char	*bp;
23312031Slayer 	long		pos;
23412031Slayer 	int		n;
23512031Slayer 	struct stat	st;
23612031Slayer 	char		envbuf[256];
23712031Slayer 	FILE		*tcfp;
23812031Slayer 
23912031Slayer 	if ((bp = getenv("TERMCAP")) && *bp == '/')
24012031Slayer 		tcfile = bp;
24112031Slayer 	else
24212031Slayer 		tcfile = "/etc/termcap";
24312031Slayer 
24412031Slayer 	while (--argc > 0)
24512031Slayer 	{
24612031Slayer 		if (*(av = *++argv) == '-')
24712031Slayer 		{
24812031Slayer 			while (*++av)
24912031Slayer 			{
25012031Slayer 				switch (*av)
25112031Slayer 				{
25212031Slayer 				/* use alternate termcap file */
25312031Slayer 				case 'f':
25412031Slayer 					if (argc-- <= 0)
25512031Slayer 					{
25612031Slayer 						fprintf(stderr,
25712031Slayer 						    "-f needs a filename\n");
25812031Slayer 						exit(1);
25912031Slayer 					}
26012031Slayer 					tcfile = *++argv;
26112031Slayer 					break;
26212031Slayer 
26312031Slayer 				/* only check for dup names */
26412458Slayer 				case 'd':
26512031Slayer 					nflag = YES;
26612031Slayer 					/* fall thru */
26712031Slayer 
26812031Slayer 				/* look for duplicated names */
26912458Slayer 				case 'D':
27012031Slayer 					dflag = YES;
27112031Slayer 					continue;
27212031Slayer 
27313250Slayer 				case 'U':
27413250Slayer 					Uflag = YES;
27513250Slayer 					continue;
27613250Slayer 
27712044Slayer 				/* strip the two name off */
27812044Slayer 				case 's':
27912044Slayer 					sflag = YES;
28012044Slayer 					continue;
28112044Slayer 
28212031Slayer 				/* sort the name array */
28312031Slayer 				case 'S':
28412044Slayer 					Sflag = NO;
28512031Slayer 					continue;
28612031Slayer 
28712031Slayer #ifdef DEBUG
28812458Slayer 				case 'T':
28912031Slayer 					Dflag = YES;
29012031Slayer 					continue;
29112031Slayer #endif
29212031Slayer 
29312031Slayer 				/* sort on generic names */
29412031Slayer 				case 'g':
29512031Slayer 					gflag = YES;
29612031Slayer 					continue;
29712031Slayer 
29812031Slayer 				/* expand entries in 'full mode' */
29912031Slayer 				case 'x':
30012031Slayer 					xflag = YES;
30112031Slayer 					continue;
30212031Slayer 
30312031Slayer 				/* show bare entry */
30412031Slayer 				case 'b':
30512031Slayer 					bflag = YES;
30612031Slayer 					continue;
30712031Slayer 
30812031Slayer 				default:
30912031Slayer 					fprintf(stderr, "showtc: unknown flag: -%c\n", *av);
31012031Slayer 					fprintf(stderr, USAGE, argv[0]);
31112031Slayer 					exit(1);
31212031Slayer 				}
31312031Slayer 			}
31412031Slayer 		}
31512031Slayer 		else
31612031Slayer 			break;
31712031Slayer 	}
31812031Slayer 
31912031Slayer 	/*
32012031Slayer 	 * insert the specified TERMCAP file into the environment
32112031Slayer 	 */
322*25372Sserge 	if (*tcfile != '/') {
323*25372Sserge 		char	*getwd();
324*25372Sserge 
325*25372Sserge 		if (getwd(cwd) == NULL) {
326*25372Sserge 			fprintf(stderr, "showtc: %s\n", cwd);
327*25372Sserge 			exit(1);
328*25372Sserge 		} else if (strlen(cwd) + strlen(tcfile) + 2 > sizeof cwd) {
329*25372Sserge 			fprintf(stderr, "showtc: %s\n",
330*25372Sserge 				"Current working directory name too long");
331*25372Sserge 			exit(1);
332*25372Sserge 		} else {
333*25372Sserge 			if (cwd[strlen(cwd) - 1] != '/')
334*25372Sserge 				strcat(cwd, "/");
335*25372Sserge 			strcat(cwd, tcfile);
336*25372Sserge 			tcfile = cwd;
337*25372Sserge 		}
338*25372Sserge 	}
33912031Slayer 	(void) sprintf(envbuf, "TERMCAP=%s", tcfile);
34012031Slayer 	while (*envp)
34112031Slayer 	{
34212031Slayer 		if (strncmp(*envp, "TERMCAP=", 8) == 0)
34312031Slayer 		{
34412031Slayer 			*envp = envbuf;
34512031Slayer 			break;
34612031Slayer 		}
34712031Slayer 		envp++;
34812031Slayer 	}
34912031Slayer 	if (! *envp)
35012031Slayer 		*envp = envbuf;	/* this may be dangerous */
35112031Slayer 
35212031Slayer 	/*
35312031Slayer 	** if user specified type(s), do only those
35412031Slayer 	*/
35512031Slayer 	if (argc > 0)
35612031Slayer 	{
35712031Slayer 		/*
35812031Slayer 		** look for the users specified term types
35912031Slayer 		*/
36012031Slayer 		while (argc > 0)
36112031Slayer 		{
36212031Slayer 			switch (n = tgetent(tcbuf, *argv))
36312031Slayer 			{
36412031Slayer 				case 1:
36512031Slayer 					if (bflag)
36612031Slayer 						(void) prnt_raw(tcbuf);
36712031Slayer 					else
36812031Slayer 						(void) prnt_ent(tcbuf);
36912031Slayer 					break;
37012031Slayer 
37112031Slayer 				case 0:
37212031Slayer 					fprintf(stderr,
37312031Slayer 					   "showtc: bad entry: %s\n", *argv);
37412031Slayer 					break;
37512031Slayer 
37612031Slayer 				case -1:
37712031Slayer 					fputs("showtc: ", stderr);
37812031Slayer 					perror(tcfile);
37912031Slayer 					exit(1);
38012031Slayer 
38112031Slayer 				default:
38212031Slayer 					fprintf(stderr, "bad return from tgetent: %d\n", n);
38312031Slayer 					exit(1);
38412031Slayer 			}
38512031Slayer 			argc--;
38612031Slayer 			argv++;
38712031Slayer 		}
38812031Slayer 		exit(0);
38912031Slayer 	}
39012031Slayer 
39112031Slayer 	if (bflag)
39212031Slayer 	{
39312031Slayer  		fprintf(stderr, "showtc: -b flag with no entries makes no sense.\n");
39412031Slayer 		exit(1);
39512031Slayer 	}
39612031Slayer 
39712031Slayer 
39812031Slayer 	/*
39912031Slayer 	** if no type was specified, do the whole file
40012031Slayer 	*/
40112031Slayer 	if ((tcfp = fopen(tcfile, "r")) == NULL)
40212031Slayer 	{
40312031Slayer 		perror(tcfile);
40412031Slayer 		exit(1);
40512031Slayer 	}
40612031Slayer 
40712031Slayer 	/*
40812031Slayer 	** identify database, for the record
40912031Slayer 	*/
41012031Slayer 	if (stat(tcfile, &st))
41112031Slayer 	{
41212031Slayer 		perror(tcfile);
41312031Slayer 		exit(1);
41412031Slayer 	}
41512031Slayer 	printf("File: %s, last modified: %s\n", tcfile, ctime(&st.st_mtime));
41612031Slayer 
41712031Slayer 
41812031Slayer 	/*
41912031Slayer 	** build termcap entry table
42012031Slayer 	*/
42112031Slayer 	tn = tcNames;
42212031Slayer 	pos = ftell(tcfp);
42312031Slayer 	bp = tcbuf;
42412031Slayer 	while (fgets(bp, sizeof (tcbuf), tcfp) != NULL)
42512031Slayer 	{
42612031Slayer 		if (tcbuf[0] == '#')
42712031Slayer 		{
42812031Slayer 			pos = ftell(tcfp);
42912031Slayer 			bp = tcbuf;
43012031Slayer 			continue;
43112031Slayer 		}
43212031Slayer 
43312031Slayer 		tn->file_pos = pos;
43412031Slayer 
43512031Slayer 		/*
43612031Slayer 		** get full entry
43712031Slayer 		*/
43812031Slayer 		while (*(bp = lastchar(bp)) == '\\' && fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp))
43912031Slayer 			;
44012031Slayer 		/*
44112031Slayer 		** save the names
44212031Slayer 		*/
44312031Slayer 		for (bp = tcbuf; *bp && *bp != ':'; bp++)
44412031Slayer 			;
44512031Slayer 		*bp = '\0';
44612031Slayer 		(void) strncpy(tn->name_buf, tcbuf,
44712031Slayer 				sizeof tcNames[0].name_buf);
44812031Slayer 
44912031Slayer 		pos = ftell(tcfp);
45012031Slayer 		bp = tcbuf;
45112031Slayer 		tn++;
45212031Slayer 	}
45312031Slayer 	tn->file_pos = -1;
45412031Slayer 
45512031Slayer 	/*
45612031Slayer 	** Look for duplicate names
45712031Slayer 	*/
45812031Slayer 	if (dflag)
45912031Slayer 		check_dup();
46012031Slayer 	if (nflag)
46112031Slayer 		exit(0);
46212031Slayer 
46312031Slayer #ifdef DEBUG
46412031Slayer 	if (Dflag)
46512031Slayer 	{
46612031Slayer 		for (tn = tcNames; tn->file_pos >= 0; tn++)
46712031Slayer 		{
46812031Slayer 			printf("Entry #%d:\n\t%s\n\tfile_pos = %ld\n",
46912031Slayer 			tn - tcNames, tn->name_buf, tn->file_pos);
47012031Slayer 		}
47112031Slayer 		exit(0);
47212031Slayer 	}
47312031Slayer #endif
47412031Slayer 
47512031Slayer 	/*
47612031Slayer 	** Order the list
47712031Slayer 	*/
47812044Slayer 	if (Sflag)
47912031Slayer 		qsort((char *)tcNames, tn - tcNames,
48012031Slayer 			sizeof (struct TcName), name_cmp);
48112031Slayer 
48212031Slayer 	/*
48312031Slayer 	** List termcap entry for each name in table
48412031Slayer 	*/
48512031Slayer 	for (tn = tcNames; tn->file_pos >= 0; tn++)
48612031Slayer 	{
48712031Slayer 		tc_loopc = 0;
48812031Slayer 		/*** working toward this ...
48912031Slayer 		(void) prnt_ent(tn);
49012031Slayer 		***/
49112031Slayer 		(void) fseek(tcfp, tn->file_pos, 0);
49212031Slayer 		bp = tcbuf;
49312031Slayer 		while (fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp)
49412031Slayer 			&& *(bp = lastchar(bp)) == '\\')
49512031Slayer 			;
49612031Slayer 		(void) prnt_ent(tcbuf);
49712031Slayer 	}
49812031Slayer }
49912031Slayer 
50012031Slayer char *
lastchar(b)50112031Slayer lastchar(b)
50212031Slayer 	char	*b;
50312031Slayer {
50412031Slayer 	register char	*p;
50512031Slayer 
50612031Slayer 	p = b + strlen(b) - 1;
50712031Slayer 	while (*p == '\n' || *p == ' ')
50812031Slayer 		p--;
50912031Slayer 	return(p);
51012031Slayer }
51112031Slayer 
name_cmp(a,b)51212031Slayer name_cmp(a, b)
51312031Slayer 	char	*a, *b;
51412031Slayer {
51512031Slayer 	if (gflag)	/* sort on generic names */
51612031Slayer 	{
51712031Slayer 		a += 3;
51812031Slayer 		b += 3;
51912031Slayer 		while (*a && *b && *a != '|' && *a == *b)
52012031Slayer 		{
52112031Slayer 			a++;
52212031Slayer 			b++;
52312031Slayer 		}
52412031Slayer 		if (*a == '|' || *a == CNULL)
52512031Slayer 			return((*b == '|' || *b == CNULL)? 0:-1);
52612031Slayer 		if (*b == '|' || *b == CNULL)
52712031Slayer 			return(1);
52812031Slayer 		return(*a - *b);
52912031Slayer 	}
53012031Slayer 	return(strncmp(a, b, 2));
53112031Slayer }
53212031Slayer 
prnt_ent(buf)53312031Slayer prnt_ent(buf)
53412031Slayer 	register char	*buf;
53512031Slayer {
53612031Slayer 	register char	*name;
53712446Slayer 	char		*getdesc();
53812031Slayer 	char		*caps[256];
53912031Slayer 	register char	**cp;
54012031Slayer 	register char	**tp;
54112031Slayer 	char		tname[3];
54212031Slayer 
54312031Slayer 	cp = caps;
54412031Slayer 	name = buf;
54512031Slayer 	tname[3] = '\0';
54612031Slayer 
54712031Slayer 	while (*buf)
54812031Slayer 	{
54912031Slayer 		switch (*buf)
55012031Slayer 		{
55112031Slayer 		case ':':
55212031Slayer 			*buf++ = '\0';
55312031Slayer 			while (*buf && !isalnum(*buf))
55412031Slayer 				buf++;
55512031Slayer 			if (*buf)
55612031Slayer 			{
55712031Slayer 				/*
55812031Slayer 				 * ignore duplicate cap entries
55912031Slayer 				 */
56012031Slayer 				for (tp = caps; tp < cp; tp++)
56112031Slayer 					if (strncmp(buf, *tp, 2) == 0)
56212031Slayer 						goto skip;
56312031Slayer 				*cp++ = buf;
56412031Slayer 			skip:
56512031Slayer 				/*
56612031Slayer 				 * does user want tc= expanded?
56712031Slayer 				 */
56812031Slayer 				if (xflag && strncmp(buf, "tc=", 3) == 0)
56912031Slayer 				{
57012031Slayer 					/*
57112031Slayer 					 * find end of tc=
57212031Slayer 					 */
57312031Slayer 					while (*buf != ':')
57412031Slayer 						buf++;
57512031Slayer 					*buf = '\0';
57612031Slayer 					/*
57712031Slayer 					 * save term name
57812031Slayer 					 */
57912031Slayer 					tname[0] = name[0];
58012031Slayer 					tname[1] = name[1];
58112031Slayer 					printf("%s: expanding %s\n",
58212031Slayer 						tname, cp[-1]);
58312031Slayer 					/*
58412031Slayer 					 * let tgetent do the work
58512031Slayer 					 */
58612031Slayer 					tgetent(tcbuf, tname);
58712031Slayer 					prnt_ent(tcbuf);
58812031Slayer 					return;
58912031Slayer 				}
59012031Slayer 			}
59112031Slayer 			continue;
59212031Slayer 
59312031Slayer 		case '|':
59412031Slayer 			*buf++ = ',';
59512031Slayer 			continue;
59612031Slayer 
59712031Slayer 		default:
59812031Slayer 			buf++;
59912031Slayer 		}
60012031Slayer 	}
60112031Slayer 	*cp = CNULL;		/* was (char *)0 */
60212031Slayer 
60312044Slayer 	if (Sflag)
60412031Slayer 		qsort((char *) caps, cp - caps, sizeof (char *), ent_cmp);
60512031Slayer 
60612031Slayer 	printf("%s\n", name);
60712031Slayer 	for (cp = caps; *cp; cp++)
60813250Slayer 		if (Uflag) {
60913250Slayer 			if (unknowncap(*cp)) {
61013250Slayer 				printf("%3.3s\n", *cp);
61113250Slayer 			}
61213250Slayer 		} else if (sflag) {
61312446Slayer 			printf("%-45s %s\n", getdesc(*cp), *cp);
61413250Slayer 		} else {
61512446Slayer 			printf("%2.2s  %-45s %s\n", name, getdesc(*cp), *cp);
61612446Slayer 		}
61712031Slayer 	(void) putchar('\n');
61812031Slayer }
61912031Slayer 
prnt_raw(buf)62012031Slayer prnt_raw(buf)
62112031Slayer 	char		*buf;
62212031Slayer {
62312031Slayer 	register char	*b;
62412031Slayer 	register int	len;
62512031Slayer 	register int	n;
62612031Slayer 	char		*index();
62712031Slayer 
62812031Slayer 	len = 0;
62912031Slayer 	b = buf;
63012031Slayer 	while (*b)
63112031Slayer 	{
63212031Slayer 		if ((n = index(b, ':') - b + 1) <= 0)
63312031Slayer 			n = strlen(b);
63412031Slayer 		if (len == 0)			/* first part */
63512031Slayer 		{
63612031Slayer 			printf("%.*s\\\n\t:", n, b);
63712031Slayer 			len = 9 - n;
63812031Slayer 		}
63912031Slayer 		else
64012031Slayer 		{
64112031Slayer 			if ((len + n) >= 75)
64212031Slayer 			{
64312031Slayer 				printf("\\\n\t:");
64412031Slayer 				len = 9;
64512031Slayer 			}
64612031Slayer 			printf("%.*s", n, b);
64712031Slayer 		}
64812031Slayer 		len += n;
64912031Slayer 		b += n;
65012031Slayer 		while (*b && index(" \t:\n", *b))
65112031Slayer 			b++;
65212031Slayer 	}
65312031Slayer 	if (b[-1] != ':')
65412031Slayer 		(void) putchar(':');
65512031Slayer 	(void) putchar('\n');
65612031Slayer }
65712031Slayer 
ent_cmp(a,b)65812031Slayer ent_cmp(a, b)
65912031Slayer 	char **a, **b;
66012031Slayer {
66112031Slayer 	return(strncmp(*a, *b, 2));
66212031Slayer }
66312031Slayer 
check_dup()66412031Slayer check_dup()
66512031Slayer {
66612031Slayer 	/*
66712031Slayer 	** Look for duplicated names
66812031Slayer 	*/
66912031Slayer 	register char		*p;
67012031Slayer 	register char		*q;
67112031Slayer 	register struct TcName	*tn;
67212031Slayer 	register struct TcName	*tm;
67312031Slayer 
67412031Slayer 	tn = tcNames;
67512031Slayer 	while (tn->file_pos >= 0)
67612031Slayer 	{
67712031Slayer 		p = q = tn->name_buf;
67812031Slayer 		while (*q)
67912031Slayer 		{
68012031Slayer 			while (*p && *p != '|')
68112031Slayer 				p++;
68212031Slayer 			if (p != q && (tm = find_name(q, tn + 1, p - q)))
68312031Slayer 			{
68412031Slayer 				fputs("Duplicate name: ", stdout);
68512031Slayer 				while (q != p)
68612031Slayer 					(void) putchar(*q++);
68712031Slayer 				(void) putchar('\n');
68812031Slayer 				puts(tn->name_buf);
68912031Slayer 				puts(tm->name_buf);
69012031Slayer 				puts("---\n");
69112031Slayer 			}
69212031Slayer 			if (*p == '|')
69312031Slayer 				p++;
69412031Slayer 			q = p;
69512031Slayer 		}
69612031Slayer 		tn++;
69712031Slayer 	}
69812031Slayer }
69912031Slayer 
70012031Slayer struct TcName *
find_name(name,tn,len)70112031Slayer find_name(name, tn, len)
70212031Slayer 	register char		*name;
70312031Slayer 	register struct TcName	*tn;
70412031Slayer 	register int		len;
70512031Slayer {
70612031Slayer 	/*
70712031Slayer 	** find name of length len in tcname structure buffers.
70812031Slayer 	*/
70912031Slayer 	register char	*p;
71012031Slayer 	register char	*buf;
71112031Slayer 	register int	 n;
71212031Slayer 
71312031Slayer 	while (tn->file_pos >= 0)
71412031Slayer 	{
71512031Slayer 		buf = tn->name_buf;
71612031Slayer 		while (*buf)
71712031Slayer 		{
71812031Slayer 			p = name;
71912031Slayer 			n = len;
72012031Slayer 			if (*buf == '|')
72112031Slayer 				buf++;
72212031Slayer 
72312031Slayer 			while (*buf && *buf != '|')
72412031Slayer 			{
72512031Slayer 				if (*p != *buf)
72612031Slayer 				{
72712031Slayer 					while (*buf && *buf != '|')
72812031Slayer 						buf++;
72912031Slayer 					break;
73012031Slayer 				}
73112031Slayer 
73212031Slayer 				if (--n <= 0)
73312031Slayer 				{
73412031Slayer 					buf++;
73512031Slayer 					if (*buf == '|' || *buf == '\0')
73612031Slayer 						return(tn);
73712031Slayer 					while (*buf && *buf != '|')
73812031Slayer 						buf++;
73912031Slayer 					break;
74012031Slayer 				}
74112031Slayer 				buf++;
74212031Slayer 				p++;
74312031Slayer 			}
74412031Slayer 		}
74512031Slayer 		tn++;
74612031Slayer 	}
74712031Slayer 	return((struct TcName *)0);
74812031Slayer }
74912446Slayer 
75012446Slayer char *
getdesc(key)75112446Slayer getdesc(key)
75212446Slayer 	char		*key;
75312446Slayer {
75412446Slayer 	register int	i;
75512446Slayer 
756*25372Sserge 	for (i = 0; i < NOCAPS; i++)
75712446Slayer 		if (strncmp(key, capList[i].cap, 2) == 0)
75812446Slayer 			return (capList[i].desc);
75912458Slayer 	return("");
76012446Slayer }
76113250Slayer 
unknowncap(key)76213250Slayer unknowncap(key)
76313250Slayer 	char		*key;
76413250Slayer {
76513250Slayer 	register int	i;
76613250Slayer 
767*25372Sserge 	for (i = 0; i < NOCAPS; i++)
76813250Slayer 		if (strncmp(key, capList[i].cap, 2) == 0)
76913250Slayer 			return (0);
77013250Slayer 	return(1);
77113250Slayer }
772