xref: /csrg-svn/local/local.cmd/showtc.c (revision 12044)
1*12044Slayer #ifndef LINT
2*12044Slayer static char *sccsid="@(#)showtc.c	1.2	(Berkeley) 04/25/83";
3*12044Slayer #endif
4*12044Slayer 
512031Slayer /*
612031Slayer ** show termcap entries
712031Slayer **
812031Slayer ** where:
912031Slayer **	-S	sort entries before display
10*12044Slayer **	-b	show bare entries
1112031Slayer **	-d	look for duplicate names
12*12044Slayer **	-f	following arg is FULL PATHNAME of termcap file
13*12044Slayer **	-g	sort on generic names
1412031Slayer **	-n	-d and stop
15*12044Slayer **	-s	don't print two char name at the front of every line
16*12044Slayer **	-x	expand tc= capabilities
1712031Slayer **	[ent]	display specific entry. tc= will be expanded.
1812031Slayer **
1912031Slayer ** David L. Wasley, U.C.Berkeley
2012031Slayer ** Modified for 4.1c by Kevin Layer
2112031Slayer */
2212031Slayer 
2312031Slayer #include <stdio.h>
2412031Slayer #include <sys/file.h>
2512031Slayer #include <ctype.h>
2612031Slayer #include <sys/types.h>
2712031Slayer #include <sys/stat.h>
2812031Slayer 
2912031Slayer #define NO		0
3012031Slayer #define YES		1
3112031Slayer #define CNULL		'\0'
3212031Slayer #define NOENTRIES	1024
33*12044Slayer #define USAGE		"usage: %s [-Sxdngb] [-f termcapfile] [entry] ...\n"
3412031Slayer 
3512031Slayer struct TcName {
3612031Slayer 	char	name_buf[124];
3712031Slayer 	long	file_pos;
3812031Slayer } tcNames[NOENTRIES];
3912031Slayer 
4012031Slayer #ifdef DEBUG
4112031Slayer int		Dflag = NO;
4212031Slayer #endif
4312031Slayer int		xflag = NO;
44*12044Slayer int		Sflag = YES;
45*12044Slayer int		sflag = NO;
4612031Slayer int		dflag = NO;
4712031Slayer int		nflag = NO;
4812031Slayer int		gflag = NO;
4912031Slayer int		bflag = NO;
5012031Slayer int		tc_loopc;		/* loop counter */
5112031Slayer char		*tcfile;		/* termcap database pathname */
5212031Slayer char		tcbuf[1024];		/* buffer for termcap description */
5312031Slayer char		*lastchar();
5412031Slayer int		name_cmp();
5512031Slayer int		ent_cmp();
5612031Slayer struct TcName	*find_name();
5712031Slayer char		*getenv();
5812031Slayer char		*ctime();
5912031Slayer char		*strncpy();
6012031Slayer long		ftell();
6112031Slayer 
6212031Slayer main(argc, argv, envp)
6312031Slayer 	int		argc;
6412031Slayer 	char		**argv;
6512031Slayer 	char		**envp;
6612031Slayer {
6712031Slayer 	char		*av;
6812031Slayer 	struct TcName	*tn;
6912031Slayer 	register char	*bp;
7012031Slayer 	long		pos;
7112031Slayer 	int		n;
7212031Slayer 	struct stat	st;
7312031Slayer 	char		envbuf[256];
7412031Slayer 	FILE		*tcfp;
7512031Slayer 
7612031Slayer 	if ((bp = getenv("TERMCAP")) && *bp == '/')
7712031Slayer 		tcfile = bp;
7812031Slayer 	else
7912031Slayer 		tcfile = "/etc/termcap";
8012031Slayer 
8112031Slayer 	while (--argc > 0)
8212031Slayer 	{
8312031Slayer 		if (*(av = *++argv) == '-')
8412031Slayer 		{
8512031Slayer 			while (*++av)
8612031Slayer 			{
8712031Slayer 				switch (*av)
8812031Slayer 				{
8912031Slayer 				/* use alternate termcap file */
9012031Slayer 				case 'f':
9112031Slayer 					if (argc-- <= 0)
9212031Slayer 					{
9312031Slayer 						fprintf(stderr,
9412031Slayer 						    "-f needs a filename\n");
9512031Slayer 						exit(1);
9612031Slayer 					}
9712031Slayer 					tcfile = *++argv;
9812031Slayer 					break;
9912031Slayer 
10012031Slayer 				/* only check for dup names */
10112031Slayer 				case 'n':
10212031Slayer 					nflag = YES;
10312031Slayer 					/* fall thru */
10412031Slayer 
10512031Slayer 				/* look for duplicated names */
10612031Slayer 				case 'd':
10712031Slayer 					dflag = YES;
10812031Slayer 					continue;
10912031Slayer 
110*12044Slayer 				/* strip the two name off */
111*12044Slayer 				case 's':
112*12044Slayer 					sflag = YES;
113*12044Slayer 					continue;
114*12044Slayer 
11512031Slayer 				/* sort the name array */
11612031Slayer 				case 'S':
117*12044Slayer 					Sflag = NO;
11812031Slayer 					continue;
11912031Slayer 
12012031Slayer #ifdef DEBUG
12112031Slayer 				case 'D':
12212031Slayer 					Dflag = YES;
12312031Slayer 					continue;
12412031Slayer #endif
12512031Slayer 
12612031Slayer 				/* sort on generic names */
12712031Slayer 				case 'g':
12812031Slayer 					gflag = YES;
12912031Slayer 					continue;
13012031Slayer 
13112031Slayer 				/* expand entries in 'full mode' */
13212031Slayer 				case 'x':
13312031Slayer 					xflag = YES;
13412031Slayer 					continue;
13512031Slayer 
13612031Slayer 				/* show bare entry */
13712031Slayer 				case 'b':
13812031Slayer 					bflag = YES;
13912031Slayer 					continue;
14012031Slayer 
14112031Slayer 				default:
14212031Slayer 					fprintf(stderr, "showtc: unknown flag: -%c\n", *av);
14312031Slayer 					fprintf(stderr, USAGE, argv[0]);
14412031Slayer 					exit(1);
14512031Slayer 				}
14612031Slayer 			}
14712031Slayer 		}
14812031Slayer 		else
14912031Slayer 			break;
15012031Slayer 	}
15112031Slayer 
15212031Slayer 	/*
15312031Slayer 	 * insert the specified TERMCAP file into the environment
15412031Slayer 	 */
15512031Slayer 	(void) sprintf(envbuf, "TERMCAP=%s", tcfile);
15612031Slayer 	while (*envp)
15712031Slayer 	{
15812031Slayer 		if (strncmp(*envp, "TERMCAP=", 8) == 0)
15912031Slayer 		{
16012031Slayer 			*envp = envbuf;
16112031Slayer 			break;
16212031Slayer 		}
16312031Slayer 		envp++;
16412031Slayer 	}
16512031Slayer 	if (! *envp)
16612031Slayer 		*envp = envbuf;	/* this may be dangerous */
16712031Slayer 
16812031Slayer 	/*
16912031Slayer 	** if user specified type(s), do only those
17012031Slayer 	*/
17112031Slayer 	if (argc > 0)
17212031Slayer 	{
17312031Slayer 		/*
17412031Slayer 		** look for the users specified term types
17512031Slayer 		*/
17612031Slayer 		while (argc > 0)
17712031Slayer 		{
17812031Slayer 			switch (n = tgetent(tcbuf, *argv))
17912031Slayer 			{
18012031Slayer 				case 1:
18112031Slayer 					if (bflag)
18212031Slayer 						(void) prnt_raw(tcbuf);
18312031Slayer 					else
18412031Slayer 						(void) prnt_ent(tcbuf);
18512031Slayer 					break;
18612031Slayer 
18712031Slayer 				case 0:
18812031Slayer 					fprintf(stderr,
18912031Slayer 					   "showtc: bad entry: %s\n", *argv);
19012031Slayer 					break;
19112031Slayer 
19212031Slayer 				case -1:
19312031Slayer 					fputs("showtc: ", stderr);
19412031Slayer 					perror(tcfile);
19512031Slayer 					exit(1);
19612031Slayer 
19712031Slayer 				default:
19812031Slayer 					fprintf(stderr, "bad return from tgetent: %d\n", n);
19912031Slayer 					exit(1);
20012031Slayer 			}
20112031Slayer 			argc--;
20212031Slayer 			argv++;
20312031Slayer 		}
20412031Slayer 		exit(0);
20512031Slayer 	}
20612031Slayer 
20712031Slayer 	if (bflag)
20812031Slayer 	{
20912031Slayer  		fprintf(stderr, "showtc: -b flag with no entries makes no sense.\n");
21012031Slayer 		exit(1);
21112031Slayer 	}
21212031Slayer 
21312031Slayer 
21412031Slayer 	/*
21512031Slayer 	** if no type was specified, do the whole file
21612031Slayer 	*/
21712031Slayer 	if ((tcfp = fopen(tcfile, "r")) == NULL)
21812031Slayer 	{
21912031Slayer 		perror(tcfile);
22012031Slayer 		exit(1);
22112031Slayer 	}
22212031Slayer 
22312031Slayer 	/*
22412031Slayer 	** identify database, for the record
22512031Slayer 	*/
22612031Slayer 	if (stat(tcfile, &st))
22712031Slayer 	{
22812031Slayer 		perror(tcfile);
22912031Slayer 		exit(1);
23012031Slayer 	}
23112031Slayer 	printf("File: %s, last modified: %s\n", tcfile, ctime(&st.st_mtime));
23212031Slayer 
23312031Slayer 
23412031Slayer 	/*
23512031Slayer 	** build termcap entry table
23612031Slayer 	*/
23712031Slayer 	tn = tcNames;
23812031Slayer 	pos = ftell(tcfp);
23912031Slayer 	bp = tcbuf;
24012031Slayer 	while (fgets(bp, sizeof (tcbuf), tcfp) != NULL)
24112031Slayer 	{
24212031Slayer 		if (tcbuf[0] == '#')
24312031Slayer 		{
24412031Slayer 			pos = ftell(tcfp);
24512031Slayer 			bp = tcbuf;
24612031Slayer 			continue;
24712031Slayer 		}
24812031Slayer 
24912031Slayer 		tn->file_pos = pos;
25012031Slayer 
25112031Slayer 		/*
25212031Slayer 		** get full entry
25312031Slayer 		*/
25412031Slayer 		while (*(bp = lastchar(bp)) == '\\' && fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp))
25512031Slayer 			;
25612031Slayer 		/*
25712031Slayer 		** save the names
25812031Slayer 		*/
25912031Slayer 		for (bp = tcbuf; *bp && *bp != ':'; bp++)
26012031Slayer 			;
26112031Slayer 		*bp = '\0';
26212031Slayer 		(void) strncpy(tn->name_buf, tcbuf,
26312031Slayer 				sizeof tcNames[0].name_buf);
26412031Slayer 
26512031Slayer 		pos = ftell(tcfp);
26612031Slayer 		bp = tcbuf;
26712031Slayer 		tn++;
26812031Slayer 	}
26912031Slayer 	tn->file_pos = -1;
27012031Slayer 
27112031Slayer 	/*
27212031Slayer 	** Look for duplicate names
27312031Slayer 	*/
27412031Slayer 	if (dflag)
27512031Slayer 		check_dup();
27612031Slayer 	if (nflag)
27712031Slayer 		exit(0);
27812031Slayer 
27912031Slayer #ifdef DEBUG
28012031Slayer 	if (Dflag)
28112031Slayer 	{
28212031Slayer 		for (tn = tcNames; tn->file_pos >= 0; tn++)
28312031Slayer 		{
28412031Slayer 			printf("Entry #%d:\n\t%s\n\tfile_pos = %ld\n",
28512031Slayer 			tn - tcNames, tn->name_buf, tn->file_pos);
28612031Slayer 		}
28712031Slayer 		exit(0);
28812031Slayer 	}
28912031Slayer #endif
29012031Slayer 
29112031Slayer 	/*
29212031Slayer 	** Order the list
29312031Slayer 	*/
294*12044Slayer 	if (Sflag)
29512031Slayer 		qsort((char *)tcNames, tn - tcNames,
29612031Slayer 			sizeof (struct TcName), name_cmp);
29712031Slayer 
29812031Slayer 	/*
29912031Slayer 	** List termcap entry for each name in table
30012031Slayer 	*/
30112031Slayer 	for (tn = tcNames; tn->file_pos >= 0; tn++)
30212031Slayer 	{
30312031Slayer 		tc_loopc = 0;
30412031Slayer 		/*** working toward this ...
30512031Slayer 		(void) prnt_ent(tn);
30612031Slayer 		***/
30712031Slayer 		(void) fseek(tcfp, tn->file_pos, 0);
30812031Slayer 		bp = tcbuf;
30912031Slayer 		while (fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp)
31012031Slayer 			&& *(bp = lastchar(bp)) == '\\')
31112031Slayer 			;
31212031Slayer 		(void) prnt_ent(tcbuf);
31312031Slayer 	}
31412031Slayer }
31512031Slayer 
31612031Slayer char *
31712031Slayer lastchar(b)
31812031Slayer 	char	*b;
31912031Slayer {
32012031Slayer 	register char	*p;
32112031Slayer 
32212031Slayer 	p = b + strlen(b) - 1;
32312031Slayer 	while (*p == '\n' || *p == ' ')
32412031Slayer 		p--;
32512031Slayer 	return(p);
32612031Slayer }
32712031Slayer 
32812031Slayer name_cmp(a, b)
32912031Slayer 	char	*a, *b;
33012031Slayer {
33112031Slayer 	if (gflag)	/* sort on generic names */
33212031Slayer 	{
33312031Slayer 		a += 3;
33412031Slayer 		b += 3;
33512031Slayer 		while (*a && *b && *a != '|' && *a == *b)
33612031Slayer 		{
33712031Slayer 			a++;
33812031Slayer 			b++;
33912031Slayer 		}
34012031Slayer 		if (*a == '|' || *a == CNULL)
34112031Slayer 			return((*b == '|' || *b == CNULL)? 0:-1);
34212031Slayer 		if (*b == '|' || *b == CNULL)
34312031Slayer 			return(1);
34412031Slayer 		return(*a - *b);
34512031Slayer 	}
34612031Slayer 	return(strncmp(a, b, 2));
34712031Slayer }
34812031Slayer 
34912031Slayer prnt_ent(buf)
35012031Slayer 	register char	*buf;
35112031Slayer {
35212031Slayer 	register char	*name;
35312031Slayer 	char		*caps[256];
35412031Slayer 	register char	**cp;
35512031Slayer 	register char	**tp;
35612031Slayer 	char		tname[3];
35712031Slayer 
35812031Slayer 	cp = caps;
35912031Slayer 	name = buf;
36012031Slayer 	tname[3] = '\0';
36112031Slayer 
36212031Slayer 	while (*buf)
36312031Slayer 	{
36412031Slayer 		switch (*buf)
36512031Slayer 		{
36612031Slayer 		case ':':
36712031Slayer 			*buf++ = '\0';
36812031Slayer 			while (*buf && !isalnum(*buf))
36912031Slayer 				buf++;
37012031Slayer 			if (*buf)
37112031Slayer 			{
37212031Slayer 				/*
37312031Slayer 				 * ignore duplicate cap entries
37412031Slayer 				 */
37512031Slayer 				for (tp = caps; tp < cp; tp++)
37612031Slayer 					if (strncmp(buf, *tp, 2) == 0)
37712031Slayer 						goto skip;
37812031Slayer 				*cp++ = buf;
37912031Slayer 			skip:
38012031Slayer 				/*
38112031Slayer 				 * does user want tc= expanded?
38212031Slayer 				 */
38312031Slayer 				if (xflag && strncmp(buf, "tc=", 3) == 0)
38412031Slayer 				{
38512031Slayer 					/*
38612031Slayer 					 * find end of tc=
38712031Slayer 					 */
38812031Slayer 					while (*buf != ':')
38912031Slayer 						buf++;
39012031Slayer 					*buf = '\0';
39112031Slayer 					/*
39212031Slayer 					 * save term name
39312031Slayer 					 */
39412031Slayer 					tname[0] = name[0];
39512031Slayer 					tname[1] = name[1];
39612031Slayer 					printf("%s: expanding %s\n",
39712031Slayer 						tname, cp[-1]);
39812031Slayer 					/*
39912031Slayer 					 * let tgetent do the work
40012031Slayer 					 */
40112031Slayer 					tgetent(tcbuf, tname);
40212031Slayer 					prnt_ent(tcbuf);
40312031Slayer 					return;
40412031Slayer 				}
40512031Slayer 			}
40612031Slayer 			continue;
40712031Slayer 
40812031Slayer 		case '|':
40912031Slayer 			*buf++ = ',';
41012031Slayer 			continue;
41112031Slayer 
41212031Slayer 		default:
41312031Slayer 			buf++;
41412031Slayer 		}
41512031Slayer 	}
41612031Slayer 	*cp = CNULL;		/* was (char *)0 */
41712031Slayer 
418*12044Slayer 	if (Sflag)
41912031Slayer 		qsort((char *) caps, cp - caps, sizeof (char *), ent_cmp);
42012031Slayer 
42112031Slayer 	printf("%s\n", name);
42212031Slayer 	for (cp = caps; *cp; cp++)
423*12044Slayer 		if (sflag)
424*12044Slayer 			printf("	%s\n", *cp);
425*12044Slayer 		else
426*12044Slayer 			printf("%2.2s	%s\n", name, *cp);
42712031Slayer 	(void) putchar('\n');
42812031Slayer }
42912031Slayer 
43012031Slayer prnt_raw(buf)
43112031Slayer 	char		*buf;
43212031Slayer {
43312031Slayer 	register char	*b;
43412031Slayer 	register int	len;
43512031Slayer 	register int	n;
43612031Slayer 	char		*index();
43712031Slayer 
43812031Slayer 	len = 0;
43912031Slayer 	b = buf;
44012031Slayer 	while (*b)
44112031Slayer 	{
44212031Slayer 		if ((n = index(b, ':') - b + 1) <= 0)
44312031Slayer 			n = strlen(b);
44412031Slayer 		if (len == 0)			/* first part */
44512031Slayer 		{
44612031Slayer 			printf("%.*s\\\n\t:", n, b);
44712031Slayer 			len = 9 - n;
44812031Slayer 		}
44912031Slayer 		else
45012031Slayer 		{
45112031Slayer 			if ((len + n) >= 75)
45212031Slayer 			{
45312031Slayer 				printf("\\\n\t:");
45412031Slayer 				len = 9;
45512031Slayer 			}
45612031Slayer 			printf("%.*s", n, b);
45712031Slayer 		}
45812031Slayer 		len += n;
45912031Slayer 		b += n;
46012031Slayer 		while (*b && index(" \t:\n", *b))
46112031Slayer 			b++;
46212031Slayer 	}
46312031Slayer 	if (b[-1] != ':')
46412031Slayer 		(void) putchar(':');
46512031Slayer 	(void) putchar('\n');
46612031Slayer }
46712031Slayer 
46812031Slayer ent_cmp(a, b)
46912031Slayer 	char **a, **b;
47012031Slayer {
47112031Slayer 	return(strncmp(*a, *b, 2));
47212031Slayer }
47312031Slayer 
47412031Slayer check_dup()
47512031Slayer {
47612031Slayer 	/*
47712031Slayer 	** Look for duplicated names
47812031Slayer 	*/
47912031Slayer 	register char		*p;
48012031Slayer 	register char		*q;
48112031Slayer 	register struct TcName	*tn;
48212031Slayer 	register struct TcName	*tm;
48312031Slayer 
48412031Slayer 	tn = tcNames;
48512031Slayer 	while (tn->file_pos >= 0)
48612031Slayer 	{
48712031Slayer 		p = q = tn->name_buf;
48812031Slayer 		while (*q)
48912031Slayer 		{
49012031Slayer 			while (*p && *p != '|')
49112031Slayer 				p++;
49212031Slayer 			if (p != q && (tm = find_name(q, tn + 1, p - q)))
49312031Slayer 			{
49412031Slayer 				fputs("Duplicate name: ", stdout);
49512031Slayer 				while (q != p)
49612031Slayer 					(void) putchar(*q++);
49712031Slayer 				(void) putchar('\n');
49812031Slayer 				puts(tn->name_buf);
49912031Slayer 				puts(tm->name_buf);
50012031Slayer 				puts("---\n");
50112031Slayer 			}
50212031Slayer 			if (*p == '|')
50312031Slayer 				p++;
50412031Slayer 			q = p;
50512031Slayer 		}
50612031Slayer 		tn++;
50712031Slayer 	}
50812031Slayer }
50912031Slayer 
51012031Slayer struct TcName *
51112031Slayer find_name(name, tn, len)
51212031Slayer 	register char		*name;
51312031Slayer 	register struct TcName	*tn;
51412031Slayer 	register int		len;
51512031Slayer {
51612031Slayer 	/*
51712031Slayer 	** find name of length len in tcname structure buffers.
51812031Slayer 	*/
51912031Slayer 	register char	*p;
52012031Slayer 	register char	*buf;
52112031Slayer 	register int	 n;
52212031Slayer 
52312031Slayer 	while (tn->file_pos >= 0)
52412031Slayer 	{
52512031Slayer 		buf = tn->name_buf;
52612031Slayer 		while (*buf)
52712031Slayer 		{
52812031Slayer 			p = name;
52912031Slayer 			n = len;
53012031Slayer 			if (*buf == '|')
53112031Slayer 				buf++;
53212031Slayer 
53312031Slayer 			while (*buf && *buf != '|')
53412031Slayer 			{
53512031Slayer 				if (*p != *buf)
53612031Slayer 				{
53712031Slayer 					while (*buf && *buf != '|')
53812031Slayer 						buf++;
53912031Slayer 					break;
54012031Slayer 				}
54112031Slayer 
54212031Slayer 				if (--n <= 0)
54312031Slayer 				{
54412031Slayer 					buf++;
54512031Slayer 					if (*buf == '|' || *buf == '\0')
54612031Slayer 						return(tn);
54712031Slayer 					while (*buf && *buf != '|')
54812031Slayer 						buf++;
54912031Slayer 					break;
55012031Slayer 				}
55112031Slayer 				buf++;
55212031Slayer 				p++;
55312031Slayer 			}
55412031Slayer 		}
55512031Slayer 		tn++;
55612031Slayer 	}
55712031Slayer 	return((struct TcName *)0);
55812031Slayer }
559