xref: /csrg-svn/local/local.cmd/showtc.c (revision 13250)
112044Slayer #ifndef LINT
2*13250Slayer static char *sccsid="@(#)showtc.c	1.6	(Berkeley) 06/22/83";
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)
12*13250Slayer **	-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 
44*13250Slayer #define NOCAPS	105
4512446Slayer 
4612446Slayer struct Caps {
4712446Slayer 	char	*cap;
4812446Slayer 	char	*desc;
4912446Slayer } capList[NOCAPS] =
5012446Slayer {
5112446Slayer 	"ae",	"End alternate character set",
5212446Slayer 	"al",	"Add new blank line",
5312446Slayer 	"am",	"Has automatic margins",
5412446Slayer 	"as",	"Start alternate character set",
5512446Slayer 	"bc",	"Backspace if not ^H",
56*13250Slayer 	"bl",	"Audible Bell",
5712446Slayer 	"bs",	"Can backspace with ^H",
5812446Slayer 	"bt",	"Back tab",
5912446Slayer 	"bw",	"Backspace wraps from col 0 to last col",
6012446Slayer 	"CC",	"Command char in prototype if settable",
6112446Slayer 	"cd",	"Clear to end of display",
6212446Slayer 	"ce",	"Clear to end of line",
6312446Slayer 	"ch",	"Like cm, but horizontal motion only",
6412446Slayer 	"cl",	"Clear screen",
6512446Slayer 	"cm",	"Cursor motion",
6612446Slayer 	"co",	"Number of columns in a line",
6712446Slayer 	"cr",	"Carriage return, (default ^M)",
6812446Slayer 	"cs",	"Change scrolling region (vt100), like cm",
6912446Slayer 	"cv",	"Like ch but vertical only.",
7012446Slayer 	"da",	"Display may be retained above",
7112446Slayer 	"dB",	"Number of millisec of bs delay needed",
7212446Slayer 	"db",	"Display may be retained below",
7312446Slayer 	"dC",	"Number of millisec of cr delay needed",
7412446Slayer 	"dc",	"Delete character",
7512446Slayer 	"dF",	"Number of millisec of ff delay needed",
7612446Slayer 	"dl",	"Delete line",
7712446Slayer 	"dm",	"Start Delete mode",
7812446Slayer 	"dN",	"Number of millisec of nl delay needed",
7912446Slayer 	"do",	"Down one line",
8012461Slayer 	"ds",	"Disable status display",
8112446Slayer 	"dT",	"Number of millisec of tab delay needed",
8212446Slayer 	"ed",	"End delete mode",
8312446Slayer 	"ei",	"End insert mode;give \":ei=:\" if ic",
8412446Slayer 	"eo",	"Can erase overstrikes with a blank",
8512461Slayer 	"es",	"Escape seq's ok on status line",
8612446Slayer 	"ff",	"Hardcopy page eject (default ^L)",
8712446Slayer 	"fs",	"From status line sequence",
8812446Slayer 	"hc",	"Hardcopy terminal",
8912446Slayer 	"hd",	"Half-line down (forward 1/2 lf)",
9012446Slayer 	"ho",	"Home cursor (if no cm)",
9112446Slayer 	"hs",	"Has 25th status line",
9212446Slayer 	"hu",	"Half-line up (reverse 1/2 lf)",
9312446Slayer 	"hz",	"Hazeltine; can't print ~'s",
9412446Slayer 	"ic",	"Insert character",
9512446Slayer 	"if",	"Name of file containing is",
9612446Slayer 	"im",	"Start insert mode;give \":im=:\" if ic",
9712446Slayer 	"in",	"Insert mode distinguishes nulls on display",
9812446Slayer 	"ip",	"Insert pad after character inserted",
9912446Slayer 	"is",	"Initialization string",
10012461Slayer 	"i2",	"Initialization string (used by sysline(1))",
10112446Slayer 	"kb",	"Sent by backspace key",
10212446Slayer 	"kd",	"Sent down arrow key",
10312446Slayer 	"ke",	"Out of \"keypad transmit\" mode",
10412446Slayer 	"kh",	"Sent by home key",
10512446Slayer 	"kl",	"Sent by left arrow key",
10612446Slayer 	"kn",	"Number of \"other\" keys",
10712446Slayer 	"ko",	"Tc entries for other non-function keys",
10812446Slayer 	"kr",	"Sent by right arrow key",
10912446Slayer 	"ks",	"Put in \"keypad transmit\" mode",
11012446Slayer 	"ku",	"Sent by up arrow key",
111*13250Slayer 	"le",	"Move left",
11212446Slayer 	"li",	"Number of lines on screen or page",
11312446Slayer 	"ll",	"Last line, first column (if no cm)",
11412446Slayer 	"ma",	"Arrow key map, used by vi V2 only",
115*13250Slayer 	"mb",	"Enter blinking mode",
116*13250Slayer 	"md",	"Enter bold mode",
117*13250Slayer 	"me",	"Reset video attributes",
118*13250Slayer 	"mh",	"Enter halfbright mode",
11912446Slayer 	"mi",	"Safe to move while in insert mode",
120*13250Slayer 	"mk",	"Enter protected mode",
12112446Slayer 	"ml",	"Memory lock on above cursor.",
122*13250Slayer 	"mr",	"Enter reverse video mode",
12312446Slayer 	"ms",	"Ok to move while in standout/underline mode",
12412446Slayer 	"mu",	"Memory unlock (turn off memory lock).",
12512446Slayer 	"nc",	"No working CR (DM2500,H2000)",
12612446Slayer 	"nd",	"Non-destructive space (cursor right)",
12712446Slayer 	"nl",	"Newline character (default \\n)",
12812446Slayer 	"ns",	"Is a CRT but doesn't scroll.",
12912446Slayer 	"os",	"Terminal overstrikes",
13012446Slayer 	"pc",	"Pad character (rather than null)",
13112446Slayer 	"pt",	"Has hardware tabs (may need to use is)",
13212446Slayer 	"se",	"End stand out mode",
13312446Slayer 	"sf",	"Scroll forwards",
13412446Slayer 	"sg",	"Number of blank chars left by so/se",
13512446Slayer 	"so",	"Begin stand out mode",
13612446Slayer 	"sr",	"Scroll reverse (backwards)",
13712446Slayer 	"ta",	"Tab (other than ^I or with padding)",
13812446Slayer 	"tc",	"Entry of similar terminal - must be last",
13912446Slayer 	"te",	"String to end programs that use cm",
14012446Slayer 	"ti",	"String to begin programs that use cm",
14112446Slayer 	"ts",	"To status line sequence",
14212446Slayer 	"uc",	"Underscore one char and move past it",
14312446Slayer 	"ue",	"End underscore mode",
14412446Slayer 	"ug",	"Number of blank chars left by us or ue",
14512446Slayer 	"ul",	"Underlines, though no overstrike",
14612446Slayer 	"up",	"Upline (cursor up)",
14712446Slayer 	"us",	"Start underscore mode",
14812446Slayer 	"vb",	"Visible bell (may not move cursor)",
14912446Slayer 	"ve",	"Sequence to end open/visual mode",
15012446Slayer 	"vs",	"Sequence to start open/visual mode",
15112446Slayer 	"xb",	"Beehive (f1=escape, f2=ctrl C)",
15212446Slayer 	"xn",	"A newline is ignored after a wrap (Concept)",
15312446Slayer 	"xr",	"Return acts like ce \\r \\n (Delta Data)",
15412446Slayer 	"xs",	"Standout not erased by writing over it (HP 264?)",
15512446Slayer 	"xt",	"Destructive tabs, magic so char (Teleray 1061)"
15612446Slayer };
15712446Slayer 
15812031Slayer #ifdef DEBUG
15912031Slayer int		Dflag = NO;
16012031Slayer #endif
16112031Slayer int		xflag = NO;
16212044Slayer int		Sflag = YES;
16312044Slayer int		sflag = NO;
16412031Slayer int		dflag = NO;
16512031Slayer int		nflag = NO;
16612031Slayer int		gflag = NO;
16712031Slayer int		bflag = NO;
168*13250Slayer int		Uflag = NO;
16912031Slayer int		tc_loopc;		/* loop counter */
17012031Slayer char		*tcfile;		/* termcap database pathname */
17112031Slayer char		tcbuf[1024];		/* buffer for termcap description */
17212031Slayer char		*lastchar();
17312031Slayer int		name_cmp();
17412031Slayer int		ent_cmp();
17512031Slayer struct TcName	*find_name();
17612031Slayer char		*getenv();
17712031Slayer char		*ctime();
17812031Slayer char		*strncpy();
17912031Slayer long		ftell();
18012031Slayer 
18112031Slayer main(argc, argv, envp)
18212031Slayer 	int		argc;
18312031Slayer 	char		**argv;
18412031Slayer 	char		**envp;
18512031Slayer {
18612031Slayer 	char		*av;
18712031Slayer 	struct TcName	*tn;
18812031Slayer 	register char	*bp;
18912031Slayer 	long		pos;
19012031Slayer 	int		n;
19112031Slayer 	struct stat	st;
19212031Slayer 	char		envbuf[256];
19312031Slayer 	FILE		*tcfp;
19412031Slayer 
19512031Slayer 	if ((bp = getenv("TERMCAP")) && *bp == '/')
19612031Slayer 		tcfile = bp;
19712031Slayer 	else
19812031Slayer 		tcfile = "/etc/termcap";
19912031Slayer 
20012031Slayer 	while (--argc > 0)
20112031Slayer 	{
20212031Slayer 		if (*(av = *++argv) == '-')
20312031Slayer 		{
20412031Slayer 			while (*++av)
20512031Slayer 			{
20612031Slayer 				switch (*av)
20712031Slayer 				{
20812031Slayer 				/* use alternate termcap file */
20912031Slayer 				case 'f':
21012031Slayer 					if (argc-- <= 0)
21112031Slayer 					{
21212031Slayer 						fprintf(stderr,
21312031Slayer 						    "-f needs a filename\n");
21412031Slayer 						exit(1);
21512031Slayer 					}
21612031Slayer 					tcfile = *++argv;
21712031Slayer 					break;
21812031Slayer 
21912031Slayer 				/* only check for dup names */
22012458Slayer 				case 'd':
22112031Slayer 					nflag = YES;
22212031Slayer 					/* fall thru */
22312031Slayer 
22412031Slayer 				/* look for duplicated names */
22512458Slayer 				case 'D':
22612031Slayer 					dflag = YES;
22712031Slayer 					continue;
22812031Slayer 
229*13250Slayer 				case 'U':
230*13250Slayer 					Uflag = YES;
231*13250Slayer 					continue;
232*13250Slayer 
23312044Slayer 				/* strip the two name off */
23412044Slayer 				case 's':
23512044Slayer 					sflag = YES;
23612044Slayer 					continue;
23712044Slayer 
23812031Slayer 				/* sort the name array */
23912031Slayer 				case 'S':
24012044Slayer 					Sflag = NO;
24112031Slayer 					continue;
24212031Slayer 
24312031Slayer #ifdef DEBUG
24412458Slayer 				case 'T':
24512031Slayer 					Dflag = YES;
24612031Slayer 					continue;
24712031Slayer #endif
24812031Slayer 
24912031Slayer 				/* sort on generic names */
25012031Slayer 				case 'g':
25112031Slayer 					gflag = YES;
25212031Slayer 					continue;
25312031Slayer 
25412031Slayer 				/* expand entries in 'full mode' */
25512031Slayer 				case 'x':
25612031Slayer 					xflag = YES;
25712031Slayer 					continue;
25812031Slayer 
25912031Slayer 				/* show bare entry */
26012031Slayer 				case 'b':
26112031Slayer 					bflag = YES;
26212031Slayer 					continue;
26312031Slayer 
26412031Slayer 				default:
26512031Slayer 					fprintf(stderr, "showtc: unknown flag: -%c\n", *av);
26612031Slayer 					fprintf(stderr, USAGE, argv[0]);
26712031Slayer 					exit(1);
26812031Slayer 				}
26912031Slayer 			}
27012031Slayer 		}
27112031Slayer 		else
27212031Slayer 			break;
27312031Slayer 	}
27412031Slayer 
27512031Slayer 	/*
27612031Slayer 	 * insert the specified TERMCAP file into the environment
27712031Slayer 	 */
27812031Slayer 	(void) sprintf(envbuf, "TERMCAP=%s", tcfile);
27912031Slayer 	while (*envp)
28012031Slayer 	{
28112031Slayer 		if (strncmp(*envp, "TERMCAP=", 8) == 0)
28212031Slayer 		{
28312031Slayer 			*envp = envbuf;
28412031Slayer 			break;
28512031Slayer 		}
28612031Slayer 		envp++;
28712031Slayer 	}
28812031Slayer 	if (! *envp)
28912031Slayer 		*envp = envbuf;	/* this may be dangerous */
29012031Slayer 
29112031Slayer 	/*
29212031Slayer 	** if user specified type(s), do only those
29312031Slayer 	*/
29412031Slayer 	if (argc > 0)
29512031Slayer 	{
29612031Slayer 		/*
29712031Slayer 		** look for the users specified term types
29812031Slayer 		*/
29912031Slayer 		while (argc > 0)
30012031Slayer 		{
30112031Slayer 			switch (n = tgetent(tcbuf, *argv))
30212031Slayer 			{
30312031Slayer 				case 1:
30412031Slayer 					if (bflag)
30512031Slayer 						(void) prnt_raw(tcbuf);
30612031Slayer 					else
30712031Slayer 						(void) prnt_ent(tcbuf);
30812031Slayer 					break;
30912031Slayer 
31012031Slayer 				case 0:
31112031Slayer 					fprintf(stderr,
31212031Slayer 					   "showtc: bad entry: %s\n", *argv);
31312031Slayer 					break;
31412031Slayer 
31512031Slayer 				case -1:
31612031Slayer 					fputs("showtc: ", stderr);
31712031Slayer 					perror(tcfile);
31812031Slayer 					exit(1);
31912031Slayer 
32012031Slayer 				default:
32112031Slayer 					fprintf(stderr, "bad return from tgetent: %d\n", n);
32212031Slayer 					exit(1);
32312031Slayer 			}
32412031Slayer 			argc--;
32512031Slayer 			argv++;
32612031Slayer 		}
32712031Slayer 		exit(0);
32812031Slayer 	}
32912031Slayer 
33012031Slayer 	if (bflag)
33112031Slayer 	{
33212031Slayer  		fprintf(stderr, "showtc: -b flag with no entries makes no sense.\n");
33312031Slayer 		exit(1);
33412031Slayer 	}
33512031Slayer 
33612031Slayer 
33712031Slayer 	/*
33812031Slayer 	** if no type was specified, do the whole file
33912031Slayer 	*/
34012031Slayer 	if ((tcfp = fopen(tcfile, "r")) == NULL)
34112031Slayer 	{
34212031Slayer 		perror(tcfile);
34312031Slayer 		exit(1);
34412031Slayer 	}
34512031Slayer 
34612031Slayer 	/*
34712031Slayer 	** identify database, for the record
34812031Slayer 	*/
34912031Slayer 	if (stat(tcfile, &st))
35012031Slayer 	{
35112031Slayer 		perror(tcfile);
35212031Slayer 		exit(1);
35312031Slayer 	}
35412031Slayer 	printf("File: %s, last modified: %s\n", tcfile, ctime(&st.st_mtime));
35512031Slayer 
35612031Slayer 
35712031Slayer 	/*
35812031Slayer 	** build termcap entry table
35912031Slayer 	*/
36012031Slayer 	tn = tcNames;
36112031Slayer 	pos = ftell(tcfp);
36212031Slayer 	bp = tcbuf;
36312031Slayer 	while (fgets(bp, sizeof (tcbuf), tcfp) != NULL)
36412031Slayer 	{
36512031Slayer 		if (tcbuf[0] == '#')
36612031Slayer 		{
36712031Slayer 			pos = ftell(tcfp);
36812031Slayer 			bp = tcbuf;
36912031Slayer 			continue;
37012031Slayer 		}
37112031Slayer 
37212031Slayer 		tn->file_pos = pos;
37312031Slayer 
37412031Slayer 		/*
37512031Slayer 		** get full entry
37612031Slayer 		*/
37712031Slayer 		while (*(bp = lastchar(bp)) == '\\' && fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp))
37812031Slayer 			;
37912031Slayer 		/*
38012031Slayer 		** save the names
38112031Slayer 		*/
38212031Slayer 		for (bp = tcbuf; *bp && *bp != ':'; bp++)
38312031Slayer 			;
38412031Slayer 		*bp = '\0';
38512031Slayer 		(void) strncpy(tn->name_buf, tcbuf,
38612031Slayer 				sizeof tcNames[0].name_buf);
38712031Slayer 
38812031Slayer 		pos = ftell(tcfp);
38912031Slayer 		bp = tcbuf;
39012031Slayer 		tn++;
39112031Slayer 	}
39212031Slayer 	tn->file_pos = -1;
39312031Slayer 
39412031Slayer 	/*
39512031Slayer 	** Look for duplicate names
39612031Slayer 	*/
39712031Slayer 	if (dflag)
39812031Slayer 		check_dup();
39912031Slayer 	if (nflag)
40012031Slayer 		exit(0);
40112031Slayer 
40212031Slayer #ifdef DEBUG
40312031Slayer 	if (Dflag)
40412031Slayer 	{
40512031Slayer 		for (tn = tcNames; tn->file_pos >= 0; tn++)
40612031Slayer 		{
40712031Slayer 			printf("Entry #%d:\n\t%s\n\tfile_pos = %ld\n",
40812031Slayer 			tn - tcNames, tn->name_buf, tn->file_pos);
40912031Slayer 		}
41012031Slayer 		exit(0);
41112031Slayer 	}
41212031Slayer #endif
41312031Slayer 
41412031Slayer 	/*
41512031Slayer 	** Order the list
41612031Slayer 	*/
41712044Slayer 	if (Sflag)
41812031Slayer 		qsort((char *)tcNames, tn - tcNames,
41912031Slayer 			sizeof (struct TcName), name_cmp);
42012031Slayer 
42112031Slayer 	/*
42212031Slayer 	** List termcap entry for each name in table
42312031Slayer 	*/
42412031Slayer 	for (tn = tcNames; tn->file_pos >= 0; tn++)
42512031Slayer 	{
42612031Slayer 		tc_loopc = 0;
42712031Slayer 		/*** working toward this ...
42812031Slayer 		(void) prnt_ent(tn);
42912031Slayer 		***/
43012031Slayer 		(void) fseek(tcfp, tn->file_pos, 0);
43112031Slayer 		bp = tcbuf;
43212031Slayer 		while (fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp)
43312031Slayer 			&& *(bp = lastchar(bp)) == '\\')
43412031Slayer 			;
43512031Slayer 		(void) prnt_ent(tcbuf);
43612031Slayer 	}
43712031Slayer }
43812031Slayer 
43912031Slayer char *
44012031Slayer lastchar(b)
44112031Slayer 	char	*b;
44212031Slayer {
44312031Slayer 	register char	*p;
44412031Slayer 
44512031Slayer 	p = b + strlen(b) - 1;
44612031Slayer 	while (*p == '\n' || *p == ' ')
44712031Slayer 		p--;
44812031Slayer 	return(p);
44912031Slayer }
45012031Slayer 
45112031Slayer name_cmp(a, b)
45212031Slayer 	char	*a, *b;
45312031Slayer {
45412031Slayer 	if (gflag)	/* sort on generic names */
45512031Slayer 	{
45612031Slayer 		a += 3;
45712031Slayer 		b += 3;
45812031Slayer 		while (*a && *b && *a != '|' && *a == *b)
45912031Slayer 		{
46012031Slayer 			a++;
46112031Slayer 			b++;
46212031Slayer 		}
46312031Slayer 		if (*a == '|' || *a == CNULL)
46412031Slayer 			return((*b == '|' || *b == CNULL)? 0:-1);
46512031Slayer 		if (*b == '|' || *b == CNULL)
46612031Slayer 			return(1);
46712031Slayer 		return(*a - *b);
46812031Slayer 	}
46912031Slayer 	return(strncmp(a, b, 2));
47012031Slayer }
47112031Slayer 
47212031Slayer prnt_ent(buf)
47312031Slayer 	register char	*buf;
47412031Slayer {
47512031Slayer 	register char	*name;
47612446Slayer 	char		*getdesc();
47712031Slayer 	char		*caps[256];
47812031Slayer 	register char	**cp;
47912031Slayer 	register char	**tp;
48012031Slayer 	char		tname[3];
48112031Slayer 
48212031Slayer 	cp = caps;
48312031Slayer 	name = buf;
48412031Slayer 	tname[3] = '\0';
48512031Slayer 
48612031Slayer 	while (*buf)
48712031Slayer 	{
48812031Slayer 		switch (*buf)
48912031Slayer 		{
49012031Slayer 		case ':':
49112031Slayer 			*buf++ = '\0';
49212031Slayer 			while (*buf && !isalnum(*buf))
49312031Slayer 				buf++;
49412031Slayer 			if (*buf)
49512031Slayer 			{
49612031Slayer 				/*
49712031Slayer 				 * ignore duplicate cap entries
49812031Slayer 				 */
49912031Slayer 				for (tp = caps; tp < cp; tp++)
50012031Slayer 					if (strncmp(buf, *tp, 2) == 0)
50112031Slayer 						goto skip;
50212031Slayer 				*cp++ = buf;
50312031Slayer 			skip:
50412031Slayer 				/*
50512031Slayer 				 * does user want tc= expanded?
50612031Slayer 				 */
50712031Slayer 				if (xflag && strncmp(buf, "tc=", 3) == 0)
50812031Slayer 				{
50912031Slayer 					/*
51012031Slayer 					 * find end of tc=
51112031Slayer 					 */
51212031Slayer 					while (*buf != ':')
51312031Slayer 						buf++;
51412031Slayer 					*buf = '\0';
51512031Slayer 					/*
51612031Slayer 					 * save term name
51712031Slayer 					 */
51812031Slayer 					tname[0] = name[0];
51912031Slayer 					tname[1] = name[1];
52012031Slayer 					printf("%s: expanding %s\n",
52112031Slayer 						tname, cp[-1]);
52212031Slayer 					/*
52312031Slayer 					 * let tgetent do the work
52412031Slayer 					 */
52512031Slayer 					tgetent(tcbuf, tname);
52612031Slayer 					prnt_ent(tcbuf);
52712031Slayer 					return;
52812031Slayer 				}
52912031Slayer 			}
53012031Slayer 			continue;
53112031Slayer 
53212031Slayer 		case '|':
53312031Slayer 			*buf++ = ',';
53412031Slayer 			continue;
53512031Slayer 
53612031Slayer 		default:
53712031Slayer 			buf++;
53812031Slayer 		}
53912031Slayer 	}
54012031Slayer 	*cp = CNULL;		/* was (char *)0 */
54112031Slayer 
54212044Slayer 	if (Sflag)
54312031Slayer 		qsort((char *) caps, cp - caps, sizeof (char *), ent_cmp);
54412031Slayer 
54512031Slayer 	printf("%s\n", name);
54612031Slayer 	for (cp = caps; *cp; cp++)
547*13250Slayer 		if (Uflag) {
548*13250Slayer 			if (unknowncap(*cp)) {
549*13250Slayer 				printf("%3.3s\n", *cp);
550*13250Slayer 			}
551*13250Slayer 		} else if (sflag) {
55212446Slayer 			printf("%-45s %s\n", getdesc(*cp), *cp);
553*13250Slayer 		} else {
55412446Slayer 			printf("%2.2s  %-45s %s\n", name, getdesc(*cp), *cp);
55512446Slayer 		}
55612031Slayer 	(void) putchar('\n');
55712031Slayer }
55812031Slayer 
55912031Slayer prnt_raw(buf)
56012031Slayer 	char		*buf;
56112031Slayer {
56212031Slayer 	register char	*b;
56312031Slayer 	register int	len;
56412031Slayer 	register int	n;
56512031Slayer 	char		*index();
56612031Slayer 
56712031Slayer 	len = 0;
56812031Slayer 	b = buf;
56912031Slayer 	while (*b)
57012031Slayer 	{
57112031Slayer 		if ((n = index(b, ':') - b + 1) <= 0)
57212031Slayer 			n = strlen(b);
57312031Slayer 		if (len == 0)			/* first part */
57412031Slayer 		{
57512031Slayer 			printf("%.*s\\\n\t:", n, b);
57612031Slayer 			len = 9 - n;
57712031Slayer 		}
57812031Slayer 		else
57912031Slayer 		{
58012031Slayer 			if ((len + n) >= 75)
58112031Slayer 			{
58212031Slayer 				printf("\\\n\t:");
58312031Slayer 				len = 9;
58412031Slayer 			}
58512031Slayer 			printf("%.*s", n, b);
58612031Slayer 		}
58712031Slayer 		len += n;
58812031Slayer 		b += n;
58912031Slayer 		while (*b && index(" \t:\n", *b))
59012031Slayer 			b++;
59112031Slayer 	}
59212031Slayer 	if (b[-1] != ':')
59312031Slayer 		(void) putchar(':');
59412031Slayer 	(void) putchar('\n');
59512031Slayer }
59612031Slayer 
59712031Slayer ent_cmp(a, b)
59812031Slayer 	char **a, **b;
59912031Slayer {
60012031Slayer 	return(strncmp(*a, *b, 2));
60112031Slayer }
60212031Slayer 
60312031Slayer check_dup()
60412031Slayer {
60512031Slayer 	/*
60612031Slayer 	** Look for duplicated names
60712031Slayer 	*/
60812031Slayer 	register char		*p;
60912031Slayer 	register char		*q;
61012031Slayer 	register struct TcName	*tn;
61112031Slayer 	register struct TcName	*tm;
61212031Slayer 
61312031Slayer 	tn = tcNames;
61412031Slayer 	while (tn->file_pos >= 0)
61512031Slayer 	{
61612031Slayer 		p = q = tn->name_buf;
61712031Slayer 		while (*q)
61812031Slayer 		{
61912031Slayer 			while (*p && *p != '|')
62012031Slayer 				p++;
62112031Slayer 			if (p != q && (tm = find_name(q, tn + 1, p - q)))
62212031Slayer 			{
62312031Slayer 				fputs("Duplicate name: ", stdout);
62412031Slayer 				while (q != p)
62512031Slayer 					(void) putchar(*q++);
62612031Slayer 				(void) putchar('\n');
62712031Slayer 				puts(tn->name_buf);
62812031Slayer 				puts(tm->name_buf);
62912031Slayer 				puts("---\n");
63012031Slayer 			}
63112031Slayer 			if (*p == '|')
63212031Slayer 				p++;
63312031Slayer 			q = p;
63412031Slayer 		}
63512031Slayer 		tn++;
63612031Slayer 	}
63712031Slayer }
63812031Slayer 
63912031Slayer struct TcName *
64012031Slayer find_name(name, tn, len)
64112031Slayer 	register char		*name;
64212031Slayer 	register struct TcName	*tn;
64312031Slayer 	register int		len;
64412031Slayer {
64512031Slayer 	/*
64612031Slayer 	** find name of length len in tcname structure buffers.
64712031Slayer 	*/
64812031Slayer 	register char	*p;
64912031Slayer 	register char	*buf;
65012031Slayer 	register int	 n;
65112031Slayer 
65212031Slayer 	while (tn->file_pos >= 0)
65312031Slayer 	{
65412031Slayer 		buf = tn->name_buf;
65512031Slayer 		while (*buf)
65612031Slayer 		{
65712031Slayer 			p = name;
65812031Slayer 			n = len;
65912031Slayer 			if (*buf == '|')
66012031Slayer 				buf++;
66112031Slayer 
66212031Slayer 			while (*buf && *buf != '|')
66312031Slayer 			{
66412031Slayer 				if (*p != *buf)
66512031Slayer 				{
66612031Slayer 					while (*buf && *buf != '|')
66712031Slayer 						buf++;
66812031Slayer 					break;
66912031Slayer 				}
67012031Slayer 
67112031Slayer 				if (--n <= 0)
67212031Slayer 				{
67312031Slayer 					buf++;
67412031Slayer 					if (*buf == '|' || *buf == '\0')
67512031Slayer 						return(tn);
67612031Slayer 					while (*buf && *buf != '|')
67712031Slayer 						buf++;
67812031Slayer 					break;
67912031Slayer 				}
68012031Slayer 				buf++;
68112031Slayer 				p++;
68212031Slayer 			}
68312031Slayer 		}
68412031Slayer 		tn++;
68512031Slayer 	}
68612031Slayer 	return((struct TcName *)0);
68712031Slayer }
68812446Slayer 
68912446Slayer char *
69012446Slayer getdesc(key)
69112446Slayer 	char		*key;
69212446Slayer {
69312446Slayer 	register int	i;
69412446Slayer 
69512446Slayer 	for (i = 0; i <= NOCAPS; i++)
69612446Slayer 		if (strncmp(key, capList[i].cap, 2) == 0)
69712446Slayer 			return (capList[i].desc);
69812458Slayer 	return("");
69912446Slayer }
700*13250Slayer 
701*13250Slayer unknowncap(key)
702*13250Slayer 	char		*key;
703*13250Slayer {
704*13250Slayer 	register int	i;
705*13250Slayer 
706*13250Slayer 	for (i = 0; i <= NOCAPS; i++)
707*13250Slayer 		if (strncmp(key, capList[i].cap, 2) == 0)
708*13250Slayer 			return (0);
709*13250Slayer 	return(1);
710*13250Slayer }
711