xref: /csrg-svn/local/local.cmd/showtc.c (revision 12461)
112044Slayer #ifndef LINT
2*12461Slayer static char *sccsid="@(#)showtc.c	1.5	(Berkeley) 05/15/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)
1212044Slayer **	-b	show bare entries
1312458Slayer **	-d	-D and stop
1412044Slayer **	-f	following arg is FULL PATHNAME of termcap file
1512044Slayer **	-g	sort on generic names
1612044Slayer **	-s	don't print two char name at the front of every line
1712044Slayer **	-x	expand tc= capabilities
1812031Slayer **	[ent]	display specific entry. tc= will be expanded.
1912031Slayer **
2012031Slayer ** David L. Wasley, U.C.Berkeley
2112446Slayer ** Kevin Layer: modified for 4.1c and misc changes.
2212446Slayer ** Kevin Layer: added the printing of terminal capabilities
2312446Slayer **	in `human' readable form (like that in "man 5 termcap").
2412031Slayer */
2512031Slayer 
2612031Slayer #include <stdio.h>
2712031Slayer #include <sys/file.h>
2812031Slayer #include <ctype.h>
2912031Slayer #include <sys/types.h>
3012031Slayer #include <sys/stat.h>
3112031Slayer 
3212031Slayer #define NO		0
3312031Slayer #define YES		1
3412031Slayer #define CNULL		'\0'
3512031Slayer #define NOENTRIES	1024
3612044Slayer #define USAGE		"usage: %s [-Sxdngb] [-f termcapfile] [entry] ...\n"
3712031Slayer 
3812031Slayer struct TcName {
3912031Slayer 	char	name_buf[124];
4012031Slayer 	long	file_pos;
4112031Slayer } tcNames[NOENTRIES];
4212031Slayer 
43*12461Slayer #define NOCAPS	97
4412446Slayer 
4512446Slayer struct Caps {
4612446Slayer 	char	*cap;
4712446Slayer 	char	*desc;
4812446Slayer } capList[NOCAPS] =
4912446Slayer {
5012446Slayer 	"ae",	"End alternate character set",
5112446Slayer 	"al",	"Add new blank line",
5212446Slayer 	"am",	"Has automatic margins",
5312446Slayer 	"as",	"Start alternate character set",
5412446Slayer 	"bc",	"Backspace if not ^H",
5512446Slayer 	"bs",	"Can backspace with ^H",
5612446Slayer 	"bt",	"Back tab",
5712446Slayer 	"bw",	"Backspace wraps from col 0 to last col",
5812446Slayer 	"CC",	"Command char in prototype if settable",
5912446Slayer 	"cd",	"Clear to end of display",
6012446Slayer 	"ce",	"Clear to end of line",
6112446Slayer 	"ch",	"Like cm, but horizontal motion only",
6212446Slayer 	"cl",	"Clear screen",
6312446Slayer 	"cm",	"Cursor motion",
6412446Slayer 	"co",	"Number of columns in a line",
6512446Slayer 	"cr",	"Carriage return, (default ^M)",
6612446Slayer 	"cs",	"Change scrolling region (vt100), like cm",
6712446Slayer 	"cv",	"Like ch but vertical only.",
6812446Slayer 	"da",	"Display may be retained above",
6912446Slayer 	"dB",	"Number of millisec of bs delay needed",
7012446Slayer 	"db",	"Display may be retained below",
7112446Slayer 	"dC",	"Number of millisec of cr delay needed",
7212446Slayer 	"dc",	"Delete character",
7312446Slayer 	"dF",	"Number of millisec of ff delay needed",
7412446Slayer 	"dl",	"Delete line",
7512446Slayer 	"dm",	"Start Delete mode",
7612446Slayer 	"dN",	"Number of millisec of nl delay needed",
7712446Slayer 	"do",	"Down one line",
78*12461Slayer 	"ds",	"Disable status display",
7912446Slayer 	"dT",	"Number of millisec of tab delay needed",
8012446Slayer 	"ed",	"End delete mode",
8112446Slayer 	"ei",	"End insert mode;give \":ei=:\" if ic",
8212446Slayer 	"eo",	"Can erase overstrikes with a blank",
83*12461Slayer 	"es",	"Escape seq's ok on status line",
8412446Slayer 	"ff",	"Hardcopy page eject (default ^L)",
8512446Slayer 	"fs",	"From status line sequence",
8612446Slayer 	"hc",	"Hardcopy terminal",
8712446Slayer 	"hd",	"Half-line down (forward 1/2 lf)",
8812446Slayer 	"ho",	"Home cursor (if no cm)",
8912446Slayer 	"hs",	"Has 25th status line",
9012446Slayer 	"hu",	"Half-line up (reverse 1/2 lf)",
9112446Slayer 	"hz",	"Hazeltine; can't print ~'s",
9212446Slayer 	"ic",	"Insert character",
9312446Slayer 	"if",	"Name of file containing is",
9412446Slayer 	"im",	"Start insert mode;give \":im=:\" if ic",
9512446Slayer 	"in",	"Insert mode distinguishes nulls on display",
9612446Slayer 	"ip",	"Insert pad after character inserted",
9712446Slayer 	"is",	"Initialization string",
98*12461Slayer 	"i2",	"Initialization string (used by sysline(1))",
9912446Slayer 	"kb",	"Sent by backspace key",
10012446Slayer 	"kd",	"Sent down arrow key",
10112446Slayer 	"ke",	"Out of \"keypad transmit\" mode",
10212446Slayer 	"kh",	"Sent by home key",
10312446Slayer 	"kl",	"Sent by left arrow key",
10412446Slayer 	"kn",	"Number of \"other\" keys",
10512446Slayer 	"ko",	"Tc entries for other non-function keys",
10612446Slayer 	"kr",	"Sent by right arrow key",
10712446Slayer 	"ks",	"Put in \"keypad transmit\" mode",
10812446Slayer 	"ku",	"Sent by up arrow key",
10912446Slayer 	"li",	"Number of lines on screen or page",
11012446Slayer 	"ll",	"Last line, first column (if no cm)",
11112446Slayer 	"ma",	"Arrow key map, used by vi V2 only",
11212446Slayer 	"mi",	"Safe to move while in insert mode",
11312446Slayer 	"ml",	"Memory lock on above cursor.",
11412446Slayer 	"ms",	"Ok to move while in standout/underline mode",
11512446Slayer 	"mu",	"Memory unlock (turn off memory lock).",
11612446Slayer 	"nc",	"No working CR (DM2500,H2000)",
11712446Slayer 	"nd",	"Non-destructive space (cursor right)",
11812446Slayer 	"nl",	"Newline character (default \\n)",
11912446Slayer 	"ns",	"Is a CRT but doesn't scroll.",
12012446Slayer 	"os",	"Terminal overstrikes",
12112446Slayer 	"pc",	"Pad character (rather than null)",
12212446Slayer 	"pt",	"Has hardware tabs (may need to use is)",
12312446Slayer 	"se",	"End stand out mode",
12412446Slayer 	"sf",	"Scroll forwards",
12512446Slayer 	"sg",	"Number of blank chars left by so/se",
12612446Slayer 	"so",	"Begin stand out mode",
12712446Slayer 	"sr",	"Scroll reverse (backwards)",
12812446Slayer 	"ta",	"Tab (other than ^I or with padding)",
12912446Slayer 	"tc",	"Entry of similar terminal - must be last",
13012446Slayer 	"te",	"String to end programs that use cm",
13112446Slayer 	"ti",	"String to begin programs that use cm",
13212446Slayer 	"ts",	"To status line sequence",
13312446Slayer 	"uc",	"Underscore one char and move past it",
13412446Slayer 	"ue",	"End underscore mode",
13512446Slayer 	"ug",	"Number of blank chars left by us or ue",
13612446Slayer 	"ul",	"Underlines, though no overstrike",
13712446Slayer 	"up",	"Upline (cursor up)",
13812446Slayer 	"us",	"Start underscore mode",
13912446Slayer 	"vb",	"Visible bell (may not move cursor)",
14012446Slayer 	"ve",	"Sequence to end open/visual mode",
14112446Slayer 	"vs",	"Sequence to start open/visual mode",
14212446Slayer 	"xb",	"Beehive (f1=escape, f2=ctrl C)",
14312446Slayer 	"xn",	"A newline is ignored after a wrap (Concept)",
14412446Slayer 	"xr",	"Return acts like ce \\r \\n (Delta Data)",
14512446Slayer 	"xs",	"Standout not erased by writing over it (HP 264?)",
14612446Slayer 	"xt",	"Destructive tabs, magic so char (Teleray 1061)"
14712446Slayer };
14812446Slayer 
14912031Slayer #ifdef DEBUG
15012031Slayer int		Dflag = NO;
15112031Slayer #endif
15212031Slayer int		xflag = NO;
15312044Slayer int		Sflag = YES;
15412044Slayer int		sflag = NO;
15512031Slayer int		dflag = NO;
15612031Slayer int		nflag = NO;
15712031Slayer int		gflag = NO;
15812031Slayer int		bflag = NO;
15912031Slayer int		tc_loopc;		/* loop counter */
16012031Slayer char		*tcfile;		/* termcap database pathname */
16112031Slayer char		tcbuf[1024];		/* buffer for termcap description */
16212031Slayer char		*lastchar();
16312031Slayer int		name_cmp();
16412031Slayer int		ent_cmp();
16512031Slayer struct TcName	*find_name();
16612031Slayer char		*getenv();
16712031Slayer char		*ctime();
16812031Slayer char		*strncpy();
16912031Slayer long		ftell();
17012031Slayer 
17112031Slayer main(argc, argv, envp)
17212031Slayer 	int		argc;
17312031Slayer 	char		**argv;
17412031Slayer 	char		**envp;
17512031Slayer {
17612031Slayer 	char		*av;
17712031Slayer 	struct TcName	*tn;
17812031Slayer 	register char	*bp;
17912031Slayer 	long		pos;
18012031Slayer 	int		n;
18112031Slayer 	struct stat	st;
18212031Slayer 	char		envbuf[256];
18312031Slayer 	FILE		*tcfp;
18412031Slayer 
18512031Slayer 	if ((bp = getenv("TERMCAP")) && *bp == '/')
18612031Slayer 		tcfile = bp;
18712031Slayer 	else
18812031Slayer 		tcfile = "/etc/termcap";
18912031Slayer 
19012031Slayer 	while (--argc > 0)
19112031Slayer 	{
19212031Slayer 		if (*(av = *++argv) == '-')
19312031Slayer 		{
19412031Slayer 			while (*++av)
19512031Slayer 			{
19612031Slayer 				switch (*av)
19712031Slayer 				{
19812031Slayer 				/* use alternate termcap file */
19912031Slayer 				case 'f':
20012031Slayer 					if (argc-- <= 0)
20112031Slayer 					{
20212031Slayer 						fprintf(stderr,
20312031Slayer 						    "-f needs a filename\n");
20412031Slayer 						exit(1);
20512031Slayer 					}
20612031Slayer 					tcfile = *++argv;
20712031Slayer 					break;
20812031Slayer 
20912031Slayer 				/* only check for dup names */
21012458Slayer 				case 'd':
21112031Slayer 					nflag = YES;
21212031Slayer 					/* fall thru */
21312031Slayer 
21412031Slayer 				/* look for duplicated names */
21512458Slayer 				case 'D':
21612031Slayer 					dflag = YES;
21712031Slayer 					continue;
21812031Slayer 
21912044Slayer 				/* strip the two name off */
22012044Slayer 				case 's':
22112044Slayer 					sflag = YES;
22212044Slayer 					continue;
22312044Slayer 
22412031Slayer 				/* sort the name array */
22512031Slayer 				case 'S':
22612044Slayer 					Sflag = NO;
22712031Slayer 					continue;
22812031Slayer 
22912031Slayer #ifdef DEBUG
23012458Slayer 				case 'T':
23112031Slayer 					Dflag = YES;
23212031Slayer 					continue;
23312031Slayer #endif
23412031Slayer 
23512031Slayer 				/* sort on generic names */
23612031Slayer 				case 'g':
23712031Slayer 					gflag = YES;
23812031Slayer 					continue;
23912031Slayer 
24012031Slayer 				/* expand entries in 'full mode' */
24112031Slayer 				case 'x':
24212031Slayer 					xflag = YES;
24312031Slayer 					continue;
24412031Slayer 
24512031Slayer 				/* show bare entry */
24612031Slayer 				case 'b':
24712031Slayer 					bflag = YES;
24812031Slayer 					continue;
24912031Slayer 
25012031Slayer 				default:
25112031Slayer 					fprintf(stderr, "showtc: unknown flag: -%c\n", *av);
25212031Slayer 					fprintf(stderr, USAGE, argv[0]);
25312031Slayer 					exit(1);
25412031Slayer 				}
25512031Slayer 			}
25612031Slayer 		}
25712031Slayer 		else
25812031Slayer 			break;
25912031Slayer 	}
26012031Slayer 
26112031Slayer 	/*
26212031Slayer 	 * insert the specified TERMCAP file into the environment
26312031Slayer 	 */
26412031Slayer 	(void) sprintf(envbuf, "TERMCAP=%s", tcfile);
26512031Slayer 	while (*envp)
26612031Slayer 	{
26712031Slayer 		if (strncmp(*envp, "TERMCAP=", 8) == 0)
26812031Slayer 		{
26912031Slayer 			*envp = envbuf;
27012031Slayer 			break;
27112031Slayer 		}
27212031Slayer 		envp++;
27312031Slayer 	}
27412031Slayer 	if (! *envp)
27512031Slayer 		*envp = envbuf;	/* this may be dangerous */
27612031Slayer 
27712031Slayer 	/*
27812031Slayer 	** if user specified type(s), do only those
27912031Slayer 	*/
28012031Slayer 	if (argc > 0)
28112031Slayer 	{
28212031Slayer 		/*
28312031Slayer 		** look for the users specified term types
28412031Slayer 		*/
28512031Slayer 		while (argc > 0)
28612031Slayer 		{
28712031Slayer 			switch (n = tgetent(tcbuf, *argv))
28812031Slayer 			{
28912031Slayer 				case 1:
29012031Slayer 					if (bflag)
29112031Slayer 						(void) prnt_raw(tcbuf);
29212031Slayer 					else
29312031Slayer 						(void) prnt_ent(tcbuf);
29412031Slayer 					break;
29512031Slayer 
29612031Slayer 				case 0:
29712031Slayer 					fprintf(stderr,
29812031Slayer 					   "showtc: bad entry: %s\n", *argv);
29912031Slayer 					break;
30012031Slayer 
30112031Slayer 				case -1:
30212031Slayer 					fputs("showtc: ", stderr);
30312031Slayer 					perror(tcfile);
30412031Slayer 					exit(1);
30512031Slayer 
30612031Slayer 				default:
30712031Slayer 					fprintf(stderr, "bad return from tgetent: %d\n", n);
30812031Slayer 					exit(1);
30912031Slayer 			}
31012031Slayer 			argc--;
31112031Slayer 			argv++;
31212031Slayer 		}
31312031Slayer 		exit(0);
31412031Slayer 	}
31512031Slayer 
31612031Slayer 	if (bflag)
31712031Slayer 	{
31812031Slayer  		fprintf(stderr, "showtc: -b flag with no entries makes no sense.\n");
31912031Slayer 		exit(1);
32012031Slayer 	}
32112031Slayer 
32212031Slayer 
32312031Slayer 	/*
32412031Slayer 	** if no type was specified, do the whole file
32512031Slayer 	*/
32612031Slayer 	if ((tcfp = fopen(tcfile, "r")) == NULL)
32712031Slayer 	{
32812031Slayer 		perror(tcfile);
32912031Slayer 		exit(1);
33012031Slayer 	}
33112031Slayer 
33212031Slayer 	/*
33312031Slayer 	** identify database, for the record
33412031Slayer 	*/
33512031Slayer 	if (stat(tcfile, &st))
33612031Slayer 	{
33712031Slayer 		perror(tcfile);
33812031Slayer 		exit(1);
33912031Slayer 	}
34012031Slayer 	printf("File: %s, last modified: %s\n", tcfile, ctime(&st.st_mtime));
34112031Slayer 
34212031Slayer 
34312031Slayer 	/*
34412031Slayer 	** build termcap entry table
34512031Slayer 	*/
34612031Slayer 	tn = tcNames;
34712031Slayer 	pos = ftell(tcfp);
34812031Slayer 	bp = tcbuf;
34912031Slayer 	while (fgets(bp, sizeof (tcbuf), tcfp) != NULL)
35012031Slayer 	{
35112031Slayer 		if (tcbuf[0] == '#')
35212031Slayer 		{
35312031Slayer 			pos = ftell(tcfp);
35412031Slayer 			bp = tcbuf;
35512031Slayer 			continue;
35612031Slayer 		}
35712031Slayer 
35812031Slayer 		tn->file_pos = pos;
35912031Slayer 
36012031Slayer 		/*
36112031Slayer 		** get full entry
36212031Slayer 		*/
36312031Slayer 		while (*(bp = lastchar(bp)) == '\\' && fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp))
36412031Slayer 			;
36512031Slayer 		/*
36612031Slayer 		** save the names
36712031Slayer 		*/
36812031Slayer 		for (bp = tcbuf; *bp && *bp != ':'; bp++)
36912031Slayer 			;
37012031Slayer 		*bp = '\0';
37112031Slayer 		(void) strncpy(tn->name_buf, tcbuf,
37212031Slayer 				sizeof tcNames[0].name_buf);
37312031Slayer 
37412031Slayer 		pos = ftell(tcfp);
37512031Slayer 		bp = tcbuf;
37612031Slayer 		tn++;
37712031Slayer 	}
37812031Slayer 	tn->file_pos = -1;
37912031Slayer 
38012031Slayer 	/*
38112031Slayer 	** Look for duplicate names
38212031Slayer 	*/
38312031Slayer 	if (dflag)
38412031Slayer 		check_dup();
38512031Slayer 	if (nflag)
38612031Slayer 		exit(0);
38712031Slayer 
38812031Slayer #ifdef DEBUG
38912031Slayer 	if (Dflag)
39012031Slayer 	{
39112031Slayer 		for (tn = tcNames; tn->file_pos >= 0; tn++)
39212031Slayer 		{
39312031Slayer 			printf("Entry #%d:\n\t%s\n\tfile_pos = %ld\n",
39412031Slayer 			tn - tcNames, tn->name_buf, tn->file_pos);
39512031Slayer 		}
39612031Slayer 		exit(0);
39712031Slayer 	}
39812031Slayer #endif
39912031Slayer 
40012031Slayer 	/*
40112031Slayer 	** Order the list
40212031Slayer 	*/
40312044Slayer 	if (Sflag)
40412031Slayer 		qsort((char *)tcNames, tn - tcNames,
40512031Slayer 			sizeof (struct TcName), name_cmp);
40612031Slayer 
40712031Slayer 	/*
40812031Slayer 	** List termcap entry for each name in table
40912031Slayer 	*/
41012031Slayer 	for (tn = tcNames; tn->file_pos >= 0; tn++)
41112031Slayer 	{
41212031Slayer 		tc_loopc = 0;
41312031Slayer 		/*** working toward this ...
41412031Slayer 		(void) prnt_ent(tn);
41512031Slayer 		***/
41612031Slayer 		(void) fseek(tcfp, tn->file_pos, 0);
41712031Slayer 		bp = tcbuf;
41812031Slayer 		while (fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp)
41912031Slayer 			&& *(bp = lastchar(bp)) == '\\')
42012031Slayer 			;
42112031Slayer 		(void) prnt_ent(tcbuf);
42212031Slayer 	}
42312031Slayer }
42412031Slayer 
42512031Slayer char *
42612031Slayer lastchar(b)
42712031Slayer 	char	*b;
42812031Slayer {
42912031Slayer 	register char	*p;
43012031Slayer 
43112031Slayer 	p = b + strlen(b) - 1;
43212031Slayer 	while (*p == '\n' || *p == ' ')
43312031Slayer 		p--;
43412031Slayer 	return(p);
43512031Slayer }
43612031Slayer 
43712031Slayer name_cmp(a, b)
43812031Slayer 	char	*a, *b;
43912031Slayer {
44012031Slayer 	if (gflag)	/* sort on generic names */
44112031Slayer 	{
44212031Slayer 		a += 3;
44312031Slayer 		b += 3;
44412031Slayer 		while (*a && *b && *a != '|' && *a == *b)
44512031Slayer 		{
44612031Slayer 			a++;
44712031Slayer 			b++;
44812031Slayer 		}
44912031Slayer 		if (*a == '|' || *a == CNULL)
45012031Slayer 			return((*b == '|' || *b == CNULL)? 0:-1);
45112031Slayer 		if (*b == '|' || *b == CNULL)
45212031Slayer 			return(1);
45312031Slayer 		return(*a - *b);
45412031Slayer 	}
45512031Slayer 	return(strncmp(a, b, 2));
45612031Slayer }
45712031Slayer 
45812031Slayer prnt_ent(buf)
45912031Slayer 	register char	*buf;
46012031Slayer {
46112031Slayer 	register char	*name;
46212446Slayer 	char		*getdesc();
46312031Slayer 	char		*caps[256];
46412031Slayer 	register char	**cp;
46512031Slayer 	register char	**tp;
46612031Slayer 	char		tname[3];
46712031Slayer 
46812031Slayer 	cp = caps;
46912031Slayer 	name = buf;
47012031Slayer 	tname[3] = '\0';
47112031Slayer 
47212031Slayer 	while (*buf)
47312031Slayer 	{
47412031Slayer 		switch (*buf)
47512031Slayer 		{
47612031Slayer 		case ':':
47712031Slayer 			*buf++ = '\0';
47812031Slayer 			while (*buf && !isalnum(*buf))
47912031Slayer 				buf++;
48012031Slayer 			if (*buf)
48112031Slayer 			{
48212031Slayer 				/*
48312031Slayer 				 * ignore duplicate cap entries
48412031Slayer 				 */
48512031Slayer 				for (tp = caps; tp < cp; tp++)
48612031Slayer 					if (strncmp(buf, *tp, 2) == 0)
48712031Slayer 						goto skip;
48812031Slayer 				*cp++ = buf;
48912031Slayer 			skip:
49012031Slayer 				/*
49112031Slayer 				 * does user want tc= expanded?
49212031Slayer 				 */
49312031Slayer 				if (xflag && strncmp(buf, "tc=", 3) == 0)
49412031Slayer 				{
49512031Slayer 					/*
49612031Slayer 					 * find end of tc=
49712031Slayer 					 */
49812031Slayer 					while (*buf != ':')
49912031Slayer 						buf++;
50012031Slayer 					*buf = '\0';
50112031Slayer 					/*
50212031Slayer 					 * save term name
50312031Slayer 					 */
50412031Slayer 					tname[0] = name[0];
50512031Slayer 					tname[1] = name[1];
50612031Slayer 					printf("%s: expanding %s\n",
50712031Slayer 						tname, cp[-1]);
50812031Slayer 					/*
50912031Slayer 					 * let tgetent do the work
51012031Slayer 					 */
51112031Slayer 					tgetent(tcbuf, tname);
51212031Slayer 					prnt_ent(tcbuf);
51312031Slayer 					return;
51412031Slayer 				}
51512031Slayer 			}
51612031Slayer 			continue;
51712031Slayer 
51812031Slayer 		case '|':
51912031Slayer 			*buf++ = ',';
52012031Slayer 			continue;
52112031Slayer 
52212031Slayer 		default:
52312031Slayer 			buf++;
52412031Slayer 		}
52512031Slayer 	}
52612031Slayer 	*cp = CNULL;		/* was (char *)0 */
52712031Slayer 
52812044Slayer 	if (Sflag)
52912031Slayer 		qsort((char *) caps, cp - caps, sizeof (char *), ent_cmp);
53012031Slayer 
53112031Slayer 	printf("%s\n", name);
53212031Slayer 	for (cp = caps; *cp; cp++)
53312044Slayer 		if (sflag)
53412446Slayer 			printf("%-45s %s\n", getdesc(*cp), *cp);
53512044Slayer 		else
53612446Slayer 		{
53712446Slayer 			printf("%2.2s  %-45s %s\n", name, getdesc(*cp), *cp);
53812446Slayer 		}
53912031Slayer 	(void) putchar('\n');
54012031Slayer }
54112031Slayer 
54212031Slayer prnt_raw(buf)
54312031Slayer 	char		*buf;
54412031Slayer {
54512031Slayer 	register char	*b;
54612031Slayer 	register int	len;
54712031Slayer 	register int	n;
54812031Slayer 	char		*index();
54912031Slayer 
55012031Slayer 	len = 0;
55112031Slayer 	b = buf;
55212031Slayer 	while (*b)
55312031Slayer 	{
55412031Slayer 		if ((n = index(b, ':') - b + 1) <= 0)
55512031Slayer 			n = strlen(b);
55612031Slayer 		if (len == 0)			/* first part */
55712031Slayer 		{
55812031Slayer 			printf("%.*s\\\n\t:", n, b);
55912031Slayer 			len = 9 - n;
56012031Slayer 		}
56112031Slayer 		else
56212031Slayer 		{
56312031Slayer 			if ((len + n) >= 75)
56412031Slayer 			{
56512031Slayer 				printf("\\\n\t:");
56612031Slayer 				len = 9;
56712031Slayer 			}
56812031Slayer 			printf("%.*s", n, b);
56912031Slayer 		}
57012031Slayer 		len += n;
57112031Slayer 		b += n;
57212031Slayer 		while (*b && index(" \t:\n", *b))
57312031Slayer 			b++;
57412031Slayer 	}
57512031Slayer 	if (b[-1] != ':')
57612031Slayer 		(void) putchar(':');
57712031Slayer 	(void) putchar('\n');
57812031Slayer }
57912031Slayer 
58012031Slayer ent_cmp(a, b)
58112031Slayer 	char **a, **b;
58212031Slayer {
58312031Slayer 	return(strncmp(*a, *b, 2));
58412031Slayer }
58512031Slayer 
58612031Slayer check_dup()
58712031Slayer {
58812031Slayer 	/*
58912031Slayer 	** Look for duplicated names
59012031Slayer 	*/
59112031Slayer 	register char		*p;
59212031Slayer 	register char		*q;
59312031Slayer 	register struct TcName	*tn;
59412031Slayer 	register struct TcName	*tm;
59512031Slayer 
59612031Slayer 	tn = tcNames;
59712031Slayer 	while (tn->file_pos >= 0)
59812031Slayer 	{
59912031Slayer 		p = q = tn->name_buf;
60012031Slayer 		while (*q)
60112031Slayer 		{
60212031Slayer 			while (*p && *p != '|')
60312031Slayer 				p++;
60412031Slayer 			if (p != q && (tm = find_name(q, tn + 1, p - q)))
60512031Slayer 			{
60612031Slayer 				fputs("Duplicate name: ", stdout);
60712031Slayer 				while (q != p)
60812031Slayer 					(void) putchar(*q++);
60912031Slayer 				(void) putchar('\n');
61012031Slayer 				puts(tn->name_buf);
61112031Slayer 				puts(tm->name_buf);
61212031Slayer 				puts("---\n");
61312031Slayer 			}
61412031Slayer 			if (*p == '|')
61512031Slayer 				p++;
61612031Slayer 			q = p;
61712031Slayer 		}
61812031Slayer 		tn++;
61912031Slayer 	}
62012031Slayer }
62112031Slayer 
62212031Slayer struct TcName *
62312031Slayer find_name(name, tn, len)
62412031Slayer 	register char		*name;
62512031Slayer 	register struct TcName	*tn;
62612031Slayer 	register int		len;
62712031Slayer {
62812031Slayer 	/*
62912031Slayer 	** find name of length len in tcname structure buffers.
63012031Slayer 	*/
63112031Slayer 	register char	*p;
63212031Slayer 	register char	*buf;
63312031Slayer 	register int	 n;
63412031Slayer 
63512031Slayer 	while (tn->file_pos >= 0)
63612031Slayer 	{
63712031Slayer 		buf = tn->name_buf;
63812031Slayer 		while (*buf)
63912031Slayer 		{
64012031Slayer 			p = name;
64112031Slayer 			n = len;
64212031Slayer 			if (*buf == '|')
64312031Slayer 				buf++;
64412031Slayer 
64512031Slayer 			while (*buf && *buf != '|')
64612031Slayer 			{
64712031Slayer 				if (*p != *buf)
64812031Slayer 				{
64912031Slayer 					while (*buf && *buf != '|')
65012031Slayer 						buf++;
65112031Slayer 					break;
65212031Slayer 				}
65312031Slayer 
65412031Slayer 				if (--n <= 0)
65512031Slayer 				{
65612031Slayer 					buf++;
65712031Slayer 					if (*buf == '|' || *buf == '\0')
65812031Slayer 						return(tn);
65912031Slayer 					while (*buf && *buf != '|')
66012031Slayer 						buf++;
66112031Slayer 					break;
66212031Slayer 				}
66312031Slayer 				buf++;
66412031Slayer 				p++;
66512031Slayer 			}
66612031Slayer 		}
66712031Slayer 		tn++;
66812031Slayer 	}
66912031Slayer 	return((struct TcName *)0);
67012031Slayer }
67112446Slayer 
67212446Slayer char *
67312446Slayer getdesc(key)
67412446Slayer 	char		*key;
67512446Slayer {
67612446Slayer 	register int	i;
67712446Slayer 
67812446Slayer 	for (i = 0; i <= NOCAPS; i++)
67912446Slayer 		if (strncmp(key, capList[i].cap, 2) == 0)
68012446Slayer 			return (capList[i].desc);
68112458Slayer 	return("");
68212446Slayer }
683