xref: /original-bsd/local/local.cmd/showtc.c (revision f1fb777f)
1247aff56Sserge #ifndef lint
2*f1fb777fSserge static char *sccsid="@(#)showtc.c	1.9	(Berkeley) 11/01/85";
3d7112359Slayer #endif
4d7112359Slayer 
53a84db2eSlayer /*
63a84db2eSlayer ** show termcap entries
73a84db2eSlayer **
83a84db2eSlayer ** where:
9c11c5bf6Slayer **	-D	look for duplicate names and print termcap file
103a84db2eSlayer **	-S	sort entries before display
11c11c5bf6Slayer **	-T	trace (-DDEBUG only)
124ec13c9bSlayer **	-U	print unknown capabilities
133a84db2eSlayer **	-b	show bare entries
14c11c5bf6Slayer **	-d	-D and stop
153a84db2eSlayer **	-f	following arg is FULL PATHNAME of termcap file
16d7112359Slayer **	-g	sort on generic names
17d7112359Slayer **	-s	don't print two char name at the front of every line
18d7112359Slayer **	-x	expand tc= capabilities
193a84db2eSlayer **	[ent]	display specific entry. tc= will be expanded.
203a84db2eSlayer **
213a84db2eSlayer ** David L. Wasley, U.C.Berkeley
226b6d913cSlayer ** Kevin Layer: modified for 4.1c and misc changes.
236b6d913cSlayer ** Kevin Layer: added the printing of terminal capabilities
246b6d913cSlayer **	in `human' readable form (like that in "man 5 termcap").
253a84db2eSlayer */
263a84db2eSlayer 
273a84db2eSlayer #include <stdio.h>
283a84db2eSlayer #include <sys/file.h>
293a84db2eSlayer #include <ctype.h>
30*f1fb777fSserge #include <sys/param.h>
313a84db2eSlayer #include <sys/stat.h>
323a84db2eSlayer 
333a84db2eSlayer #define NO		0
343a84db2eSlayer #define YES		1
353a84db2eSlayer #define CNULL		'\0'
363a84db2eSlayer #define NOENTRIES	1024
37d7112359Slayer #define USAGE		"usage: %s [-Sxdngb] [-f termcapfile] [entry] ...\n"
383a84db2eSlayer 
39*f1fb777fSserge #ifndef	MAXPATHLEN
40*f1fb777fSserge #define MAXPATHLEN	1024
41*f1fb777fSserge #endif
42*f1fb777fSserge 
433a84db2eSlayer struct TcName {
443a84db2eSlayer 	char	name_buf[124];
453a84db2eSlayer 	long	file_pos;
463a84db2eSlayer } tcNames[NOENTRIES];
473a84db2eSlayer 
486b6d913cSlayer struct Caps {
496b6d913cSlayer 	char	*cap;
506b6d913cSlayer 	char	*desc;
51247aff56Sserge } capList[] =
526b6d913cSlayer {
53247aff56Sserge 	"AL",	"Add N new blank lines",
54247aff56Sserge 	"CC",	"Command char in prototype if settable",
55247aff56Sserge 	"DC",	"Delete N characters",
56247aff56Sserge 	"DL",	"Delete N lines",
57247aff56Sserge 	"DO",	"Move cursor down N lines",
58247aff56Sserge 	"IC",	"Insert N blank characters",
59247aff56Sserge 	"LE",	"Move cursor left N positions",
60247aff56Sserge 	"RI",	"Move cursor right N positions",
61247aff56Sserge 	"UP",	"Move cursor up N lines",
626b6d913cSlayer 	"ae",	"End alternate character set",
636b6d913cSlayer 	"al",	"Add new blank line",
646b6d913cSlayer 	"am",	"Has automatic margins",
656b6d913cSlayer 	"as",	"Start alternate character set",
666b6d913cSlayer 	"bc",	"Backspace if not ^H",
67247aff56Sserge 	"bl",	"Audible Bell (default ^G)",
686b6d913cSlayer 	"bs",	"Can backspace with ^H",
696b6d913cSlayer 	"bt",	"Back tab",
706b6d913cSlayer 	"bw",	"Backspace wraps from col 0 to last col",
716b6d913cSlayer 	"cd",	"Clear to end of display",
726b6d913cSlayer 	"ce",	"Clear to end of line",
736b6d913cSlayer 	"ch",	"Like cm, but horizontal motion only",
746b6d913cSlayer 	"cl",	"Clear screen",
756b6d913cSlayer 	"cm",	"Cursor motion",
766b6d913cSlayer 	"co",	"Number of columns in a line",
77247aff56Sserge 	"cr",	"Carriage return (default ^M)",
786b6d913cSlayer 	"cs",	"Change scrolling region (vt100), like cm",
79247aff56Sserge 	"ct",	"Clear all tab stops",
806b6d913cSlayer 	"cv",	"Like ch but vertical only.",
816b6d913cSlayer 	"dB",	"Number of millisec of bs delay needed",
826b6d913cSlayer 	"dC",	"Number of millisec of cr delay needed",
836b6d913cSlayer 	"dF",	"Number of millisec of ff delay needed",
84247aff56Sserge 	"dN",	"Number of millisec of nl delay needed",
85247aff56Sserge 	"dT",	"Number of millisec of tab delay needed",
86247aff56Sserge 	"da",	"Display may be retained above",
87247aff56Sserge 	"db",	"Display may be retained below",
88247aff56Sserge 	"dc",	"Delete character",
896b6d913cSlayer 	"dl",	"Delete line",
906b6d913cSlayer 	"dm",	"Start Delete mode",
916b6d913cSlayer 	"do",	"Down one line",
92c87a32d3Slayer 	"ds",	"Disable status display",
936b6d913cSlayer 	"ed",	"End delete mode",
946b6d913cSlayer 	"ei",	"End insert mode;give \":ei=:\" if ic",
956b6d913cSlayer 	"eo",	"Can erase overstrikes with a blank",
96c87a32d3Slayer 	"es",	"Escape seq's ok on status line",
976b6d913cSlayer 	"ff",	"Hardcopy page eject (default ^L)",
986b6d913cSlayer 	"fs",	"From status line sequence",
996b6d913cSlayer 	"hc",	"Hardcopy terminal",
1006b6d913cSlayer 	"hd",	"Half-line down (forward 1/2 lf)",
1016b6d913cSlayer 	"ho",	"Home cursor (if no cm)",
102247aff56Sserge 	"hs",	"Has status line",
1036b6d913cSlayer 	"hu",	"Half-line up (reverse 1/2 lf)",
1046b6d913cSlayer 	"hz",	"Hazeltine; can't print ~'s",
105247aff56Sserge 	"i2",	"Initialization string (used by sysline(1))",
1066b6d913cSlayer 	"ic",	"Insert character",
1076b6d913cSlayer 	"if",	"Name of file containing is",
1086b6d913cSlayer 	"im",	"Start insert mode;give \":im=:\" if ic",
1096b6d913cSlayer 	"in",	"Insert mode distinguishes nulls on display",
1106b6d913cSlayer 	"ip",	"Insert pad after character inserted",
1116b6d913cSlayer 	"is",	"Initialization string",
112247aff56Sserge 	"k0",	"Sent by function key 0",
113247aff56Sserge 	"k1",	"Sent by function key 1",
114247aff56Sserge 	"k2",	"Sent by function key 2",
115247aff56Sserge 	"k3",	"Sent by function key 3",
116247aff56Sserge 	"k4",	"Sent by function key 4",
117247aff56Sserge 	"k5",	"Sent by function key 5",
118247aff56Sserge 	"k6",	"Sent by function key 6",
119247aff56Sserge 	"k7",	"Sent by function key 7",
120247aff56Sserge 	"k8",	"Sent by function key 8",
121247aff56Sserge 	"k9",	"Sent by function key 9",
1226b6d913cSlayer 	"kb",	"Sent by backspace key",
123247aff56Sserge 	"kd",	"Sent by down arrow key",
1246b6d913cSlayer 	"ke",	"Out of \"keypad transmit\" mode",
1256b6d913cSlayer 	"kh",	"Sent by home key",
1266b6d913cSlayer 	"kl",	"Sent by left arrow key",
127247aff56Sserge 	"km",	"Has a \"meta\" key (shift, sets parity bit)",
1286b6d913cSlayer 	"kn",	"Number of \"other\" keys",
1296b6d913cSlayer 	"ko",	"Tc entries for other non-function keys",
1306b6d913cSlayer 	"kr",	"Sent by right arrow key",
1316b6d913cSlayer 	"ks",	"Put in \"keypad transmit\" mode",
1326b6d913cSlayer 	"ku",	"Sent by up arrow key",
133247aff56Sserge 	"l0",	"Label on function key 0 (if not \"0\")",
134247aff56Sserge 	"l1",	"Label on function key 1 (if not \"1\")",
135247aff56Sserge 	"l2",	"Label on function key 2 (if not \"2\")",
136247aff56Sserge 	"l3",	"Label on function key 3 (if not \"3\")",
137247aff56Sserge 	"l4",	"Label on function key 4 (if not \"4\")",
138247aff56Sserge 	"l5",	"Label on function key 5 (if not \"5\")",
139247aff56Sserge 	"l6",	"Label on function key 6 (if not \"6\")",
140247aff56Sserge 	"l7",	"Label on function key 7 (if not \"7\")",
141247aff56Sserge 	"l8",	"Label on function key 8 (if not \"8\")",
142247aff56Sserge 	"l9",	"Label on function key 9 (if not \"9\")",
1434ec13c9bSlayer 	"le",	"Move left",
1446b6d913cSlayer 	"li",	"Number of lines on screen or page",
1456b6d913cSlayer 	"ll",	"Last line, first column (if no cm)",
1466b6d913cSlayer 	"ma",	"Arrow key map, used by vi V2 only",
1474ec13c9bSlayer 	"mb",	"Enter blinking mode",
1484ec13c9bSlayer 	"md",	"Enter bold mode",
1494ec13c9bSlayer 	"me",	"Reset video attributes",
1504ec13c9bSlayer 	"mh",	"Enter halfbright mode",
1516b6d913cSlayer 	"mi",	"Safe to move while in insert mode",
1524ec13c9bSlayer 	"mk",	"Enter protected mode",
1536b6d913cSlayer 	"ml",	"Memory lock on above cursor.",
154247aff56Sserge 	"mp",	"Turn on protected attribute",
1554ec13c9bSlayer 	"mr",	"Enter reverse video mode",
1566b6d913cSlayer 	"ms",	"Ok to move while in standout/underline mode",
1576b6d913cSlayer 	"mu",	"Memory unlock (turn off memory lock).",
1586b6d913cSlayer 	"nc",	"No working CR (DM2500,H2000)",
1596b6d913cSlayer 	"nd",	"Non-destructive space (cursor right)",
1606b6d913cSlayer 	"nl",	"Newline character (default \\n)",
1616b6d913cSlayer 	"ns",	"Is a CRT but doesn't scroll.",
1626b6d913cSlayer 	"os",	"Terminal overstrikes",
163247aff56Sserge 	"pb",	"Lowest baud where delays are required",
1646b6d913cSlayer 	"pc",	"Pad character (rather than null)",
165247aff56Sserge 	"pl",	"Program function key N to execute string S (terminfo only)",
1666b6d913cSlayer 	"pt",	"Has hardware tabs (may need to use is)",
167247aff56Sserge 	"rc",	"Restore cursor to position of last sc",
168247aff56Sserge 	"rf",	"Name of file containing reset codes",
169247aff56Sserge 	"rs",	"Reset terminal completely to sane modes",
170247aff56Sserge 	"sc",	"Save cursor position",
1716b6d913cSlayer 	"se",	"End stand out mode",
1726b6d913cSlayer 	"sf",	"Scroll forwards",
1736b6d913cSlayer 	"sg",	"Number of blank chars left by so/se",
1746b6d913cSlayer 	"so",	"Begin stand out mode",
1756b6d913cSlayer 	"sr",	"Scroll reverse (backwards)",
176247aff56Sserge 	"st",	"Set a tab in all rows, current column",
1776b6d913cSlayer 	"ta",	"Tab (other than ^I or with padding)",
1786b6d913cSlayer 	"tc",	"Entry of similar terminal - must be last",
1796b6d913cSlayer 	"te",	"String to end programs that use cm",
1806b6d913cSlayer 	"ti",	"String to begin programs that use cm",
1816b6d913cSlayer 	"ts",	"To status line sequence",
1826b6d913cSlayer 	"uc",	"Underscore one char and move past it",
1836b6d913cSlayer 	"ue",	"End underscore mode",
1846b6d913cSlayer 	"ug",	"Number of blank chars left by us or ue",
1856b6d913cSlayer 	"ul",	"Underlines, though no overstrike",
1866b6d913cSlayer 	"up",	"Upline (cursor up)",
1876b6d913cSlayer 	"us",	"Start underscore mode",
1886b6d913cSlayer 	"vb",	"Visible bell (may not move cursor)",
1896b6d913cSlayer 	"ve",	"Sequence to end open/visual mode",
1906b6d913cSlayer 	"vs",	"Sequence to start open/visual mode",
191247aff56Sserge 	"vt",	"Virtual terminal number (not supported on all systems)",
1926b6d913cSlayer 	"xb",	"Beehive (f1=escape, f2=ctrl C)",
1936b6d913cSlayer 	"xn",	"A newline is ignored after a wrap (Concept)",
1946b6d913cSlayer 	"xr",	"Return acts like ce \\r \\n (Delta Data)",
1956b6d913cSlayer 	"xs",	"Standout not erased by writing over it (HP 264?)",
1966b6d913cSlayer 	"xt",	"Destructive tabs, magic so char (Teleray 1061)"
1976b6d913cSlayer };
1986b6d913cSlayer 
199247aff56Sserge #define NOCAPS	(sizeof capList / sizeof *capList)
200247aff56Sserge 
2013a84db2eSlayer #ifdef DEBUG
2023a84db2eSlayer int		Dflag = NO;
2033a84db2eSlayer #endif
2043a84db2eSlayer int		xflag = NO;
205d7112359Slayer int		Sflag = YES;
206d7112359Slayer int		sflag = NO;
2073a84db2eSlayer int		dflag = NO;
2083a84db2eSlayer int		nflag = NO;
2093a84db2eSlayer int		gflag = NO;
2103a84db2eSlayer int		bflag = NO;
2114ec13c9bSlayer int		Uflag = NO;
2123a84db2eSlayer int		tc_loopc;		/* loop counter */
2133a84db2eSlayer char		*tcfile;		/* termcap database pathname */
214*f1fb777fSserge char		cwd[MAXPATHLEN];	/* current working directory */
2155c2942c8Slayer char		tcbuf[2048];		/* buffer for termcap description */
2163a84db2eSlayer char		*lastchar();
2173a84db2eSlayer int		name_cmp();
2183a84db2eSlayer int		ent_cmp();
2193a84db2eSlayer struct TcName	*find_name();
2203a84db2eSlayer char		*getenv();
2213a84db2eSlayer char		*ctime();
2223a84db2eSlayer char		*strncpy();
2233a84db2eSlayer long		ftell();
2243a84db2eSlayer 
main(argc,argv,envp)2253a84db2eSlayer main(argc, argv, envp)
2263a84db2eSlayer 	int		argc;
2273a84db2eSlayer 	char		**argv;
2283a84db2eSlayer 	char		**envp;
2293a84db2eSlayer {
2303a84db2eSlayer 	char		*av;
2313a84db2eSlayer 	struct TcName	*tn;
2323a84db2eSlayer 	register char	*bp;
2333a84db2eSlayer 	long		pos;
2343a84db2eSlayer 	int		n;
2353a84db2eSlayer 	struct stat	st;
2363a84db2eSlayer 	char		envbuf[256];
2373a84db2eSlayer 	FILE		*tcfp;
2383a84db2eSlayer 
2393a84db2eSlayer 	if ((bp = getenv("TERMCAP")) && *bp == '/')
2403a84db2eSlayer 		tcfile = bp;
2413a84db2eSlayer 	else
2423a84db2eSlayer 		tcfile = "/etc/termcap";
2433a84db2eSlayer 
2443a84db2eSlayer 	while (--argc > 0)
2453a84db2eSlayer 	{
2463a84db2eSlayer 		if (*(av = *++argv) == '-')
2473a84db2eSlayer 		{
2483a84db2eSlayer 			while (*++av)
2493a84db2eSlayer 			{
2503a84db2eSlayer 				switch (*av)
2513a84db2eSlayer 				{
2523a84db2eSlayer 				/* use alternate termcap file */
2533a84db2eSlayer 				case 'f':
2543a84db2eSlayer 					if (argc-- <= 0)
2553a84db2eSlayer 					{
2563a84db2eSlayer 						fprintf(stderr,
2573a84db2eSlayer 						    "-f needs a filename\n");
2583a84db2eSlayer 						exit(1);
2593a84db2eSlayer 					}
2603a84db2eSlayer 					tcfile = *++argv;
2613a84db2eSlayer 					break;
2623a84db2eSlayer 
2633a84db2eSlayer 				/* only check for dup names */
264c11c5bf6Slayer 				case 'd':
2653a84db2eSlayer 					nflag = YES;
2663a84db2eSlayer 					/* fall thru */
2673a84db2eSlayer 
2683a84db2eSlayer 				/* look for duplicated names */
269c11c5bf6Slayer 				case 'D':
2703a84db2eSlayer 					dflag = YES;
2713a84db2eSlayer 					continue;
2723a84db2eSlayer 
2734ec13c9bSlayer 				case 'U':
2744ec13c9bSlayer 					Uflag = YES;
2754ec13c9bSlayer 					continue;
2764ec13c9bSlayer 
277d7112359Slayer 				/* strip the two name off */
278d7112359Slayer 				case 's':
279d7112359Slayer 					sflag = YES;
280d7112359Slayer 					continue;
281d7112359Slayer 
2823a84db2eSlayer 				/* sort the name array */
2833a84db2eSlayer 				case 'S':
284d7112359Slayer 					Sflag = NO;
2853a84db2eSlayer 					continue;
2863a84db2eSlayer 
2873a84db2eSlayer #ifdef DEBUG
288c11c5bf6Slayer 				case 'T':
2893a84db2eSlayer 					Dflag = YES;
2903a84db2eSlayer 					continue;
2913a84db2eSlayer #endif
2923a84db2eSlayer 
2933a84db2eSlayer 				/* sort on generic names */
2943a84db2eSlayer 				case 'g':
2953a84db2eSlayer 					gflag = YES;
2963a84db2eSlayer 					continue;
2973a84db2eSlayer 
2983a84db2eSlayer 				/* expand entries in 'full mode' */
2993a84db2eSlayer 				case 'x':
3003a84db2eSlayer 					xflag = YES;
3013a84db2eSlayer 					continue;
3023a84db2eSlayer 
3033a84db2eSlayer 				/* show bare entry */
3043a84db2eSlayer 				case 'b':
3053a84db2eSlayer 					bflag = YES;
3063a84db2eSlayer 					continue;
3073a84db2eSlayer 
3083a84db2eSlayer 				default:
3093a84db2eSlayer 					fprintf(stderr, "showtc: unknown flag: -%c\n", *av);
3103a84db2eSlayer 					fprintf(stderr, USAGE, argv[0]);
3113a84db2eSlayer 					exit(1);
3123a84db2eSlayer 				}
3133a84db2eSlayer 			}
3143a84db2eSlayer 		}
3153a84db2eSlayer 		else
3163a84db2eSlayer 			break;
3173a84db2eSlayer 	}
3183a84db2eSlayer 
3193a84db2eSlayer 	/*
3203a84db2eSlayer 	 * insert the specified TERMCAP file into the environment
3213a84db2eSlayer 	 */
322*f1fb777fSserge 	if (*tcfile != '/') {
323*f1fb777fSserge 		char	*getwd();
324*f1fb777fSserge 
325*f1fb777fSserge 		if (getwd(cwd) == NULL) {
326*f1fb777fSserge 			fprintf(stderr, "showtc: %s\n", cwd);
327*f1fb777fSserge 			exit(1);
328*f1fb777fSserge 		} else if (strlen(cwd) + strlen(tcfile) + 2 > sizeof cwd) {
329*f1fb777fSserge 			fprintf(stderr, "showtc: %s\n",
330*f1fb777fSserge 				"Current working directory name too long");
331*f1fb777fSserge 			exit(1);
332*f1fb777fSserge 		} else {
333*f1fb777fSserge 			if (cwd[strlen(cwd) - 1] != '/')
334*f1fb777fSserge 				strcat(cwd, "/");
335*f1fb777fSserge 			strcat(cwd, tcfile);
336*f1fb777fSserge 			tcfile = cwd;
337*f1fb777fSserge 		}
338*f1fb777fSserge 	}
3393a84db2eSlayer 	(void) sprintf(envbuf, "TERMCAP=%s", tcfile);
3403a84db2eSlayer 	while (*envp)
3413a84db2eSlayer 	{
3423a84db2eSlayer 		if (strncmp(*envp, "TERMCAP=", 8) == 0)
3433a84db2eSlayer 		{
3443a84db2eSlayer 			*envp = envbuf;
3453a84db2eSlayer 			break;
3463a84db2eSlayer 		}
3473a84db2eSlayer 		envp++;
3483a84db2eSlayer 	}
3493a84db2eSlayer 	if (! *envp)
3503a84db2eSlayer 		*envp = envbuf;	/* this may be dangerous */
3513a84db2eSlayer 
3523a84db2eSlayer 	/*
3533a84db2eSlayer 	** if user specified type(s), do only those
3543a84db2eSlayer 	*/
3553a84db2eSlayer 	if (argc > 0)
3563a84db2eSlayer 	{
3573a84db2eSlayer 		/*
3583a84db2eSlayer 		** look for the users specified term types
3593a84db2eSlayer 		*/
3603a84db2eSlayer 		while (argc > 0)
3613a84db2eSlayer 		{
3623a84db2eSlayer 			switch (n = tgetent(tcbuf, *argv))
3633a84db2eSlayer 			{
3643a84db2eSlayer 				case 1:
3653a84db2eSlayer 					if (bflag)
3663a84db2eSlayer 						(void) prnt_raw(tcbuf);
3673a84db2eSlayer 					else
3683a84db2eSlayer 						(void) prnt_ent(tcbuf);
3693a84db2eSlayer 					break;
3703a84db2eSlayer 
3713a84db2eSlayer 				case 0:
3723a84db2eSlayer 					fprintf(stderr,
3733a84db2eSlayer 					   "showtc: bad entry: %s\n", *argv);
3743a84db2eSlayer 					break;
3753a84db2eSlayer 
3763a84db2eSlayer 				case -1:
3773a84db2eSlayer 					fputs("showtc: ", stderr);
3783a84db2eSlayer 					perror(tcfile);
3793a84db2eSlayer 					exit(1);
3803a84db2eSlayer 
3813a84db2eSlayer 				default:
3823a84db2eSlayer 					fprintf(stderr, "bad return from tgetent: %d\n", n);
3833a84db2eSlayer 					exit(1);
3843a84db2eSlayer 			}
3853a84db2eSlayer 			argc--;
3863a84db2eSlayer 			argv++;
3873a84db2eSlayer 		}
3883a84db2eSlayer 		exit(0);
3893a84db2eSlayer 	}
3903a84db2eSlayer 
3913a84db2eSlayer 	if (bflag)
3923a84db2eSlayer 	{
3933a84db2eSlayer  		fprintf(stderr, "showtc: -b flag with no entries makes no sense.\n");
3943a84db2eSlayer 		exit(1);
3953a84db2eSlayer 	}
3963a84db2eSlayer 
3973a84db2eSlayer 
3983a84db2eSlayer 	/*
3993a84db2eSlayer 	** if no type was specified, do the whole file
4003a84db2eSlayer 	*/
4013a84db2eSlayer 	if ((tcfp = fopen(tcfile, "r")) == NULL)
4023a84db2eSlayer 	{
4033a84db2eSlayer 		perror(tcfile);
4043a84db2eSlayer 		exit(1);
4053a84db2eSlayer 	}
4063a84db2eSlayer 
4073a84db2eSlayer 	/*
4083a84db2eSlayer 	** identify database, for the record
4093a84db2eSlayer 	*/
4103a84db2eSlayer 	if (stat(tcfile, &st))
4113a84db2eSlayer 	{
4123a84db2eSlayer 		perror(tcfile);
4133a84db2eSlayer 		exit(1);
4143a84db2eSlayer 	}
4153a84db2eSlayer 	printf("File: %s, last modified: %s\n", tcfile, ctime(&st.st_mtime));
4163a84db2eSlayer 
4173a84db2eSlayer 
4183a84db2eSlayer 	/*
4193a84db2eSlayer 	** build termcap entry table
4203a84db2eSlayer 	*/
4213a84db2eSlayer 	tn = tcNames;
4223a84db2eSlayer 	pos = ftell(tcfp);
4233a84db2eSlayer 	bp = tcbuf;
4243a84db2eSlayer 	while (fgets(bp, sizeof (tcbuf), tcfp) != NULL)
4253a84db2eSlayer 	{
4263a84db2eSlayer 		if (tcbuf[0] == '#')
4273a84db2eSlayer 		{
4283a84db2eSlayer 			pos = ftell(tcfp);
4293a84db2eSlayer 			bp = tcbuf;
4303a84db2eSlayer 			continue;
4313a84db2eSlayer 		}
4323a84db2eSlayer 
4333a84db2eSlayer 		tn->file_pos = pos;
4343a84db2eSlayer 
4353a84db2eSlayer 		/*
4363a84db2eSlayer 		** get full entry
4373a84db2eSlayer 		*/
4383a84db2eSlayer 		while (*(bp = lastchar(bp)) == '\\' && fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp))
4393a84db2eSlayer 			;
4403a84db2eSlayer 		/*
4413a84db2eSlayer 		** save the names
4423a84db2eSlayer 		*/
4433a84db2eSlayer 		for (bp = tcbuf; *bp && *bp != ':'; bp++)
4443a84db2eSlayer 			;
4453a84db2eSlayer 		*bp = '\0';
4463a84db2eSlayer 		(void) strncpy(tn->name_buf, tcbuf,
4473a84db2eSlayer 				sizeof tcNames[0].name_buf);
4483a84db2eSlayer 
4493a84db2eSlayer 		pos = ftell(tcfp);
4503a84db2eSlayer 		bp = tcbuf;
4513a84db2eSlayer 		tn++;
4523a84db2eSlayer 	}
4533a84db2eSlayer 	tn->file_pos = -1;
4543a84db2eSlayer 
4553a84db2eSlayer 	/*
4563a84db2eSlayer 	** Look for duplicate names
4573a84db2eSlayer 	*/
4583a84db2eSlayer 	if (dflag)
4593a84db2eSlayer 		check_dup();
4603a84db2eSlayer 	if (nflag)
4613a84db2eSlayer 		exit(0);
4623a84db2eSlayer 
4633a84db2eSlayer #ifdef DEBUG
4643a84db2eSlayer 	if (Dflag)
4653a84db2eSlayer 	{
4663a84db2eSlayer 		for (tn = tcNames; tn->file_pos >= 0; tn++)
4673a84db2eSlayer 		{
4683a84db2eSlayer 			printf("Entry #%d:\n\t%s\n\tfile_pos = %ld\n",
4693a84db2eSlayer 			tn - tcNames, tn->name_buf, tn->file_pos);
4703a84db2eSlayer 		}
4713a84db2eSlayer 		exit(0);
4723a84db2eSlayer 	}
4733a84db2eSlayer #endif
4743a84db2eSlayer 
4753a84db2eSlayer 	/*
4763a84db2eSlayer 	** Order the list
4773a84db2eSlayer 	*/
478d7112359Slayer 	if (Sflag)
4793a84db2eSlayer 		qsort((char *)tcNames, tn - tcNames,
4803a84db2eSlayer 			sizeof (struct TcName), name_cmp);
4813a84db2eSlayer 
4823a84db2eSlayer 	/*
4833a84db2eSlayer 	** List termcap entry for each name in table
4843a84db2eSlayer 	*/
4853a84db2eSlayer 	for (tn = tcNames; tn->file_pos >= 0; tn++)
4863a84db2eSlayer 	{
4873a84db2eSlayer 		tc_loopc = 0;
4883a84db2eSlayer 		/*** working toward this ...
4893a84db2eSlayer 		(void) prnt_ent(tn);
4903a84db2eSlayer 		***/
4913a84db2eSlayer 		(void) fseek(tcfp, tn->file_pos, 0);
4923a84db2eSlayer 		bp = tcbuf;
4933a84db2eSlayer 		while (fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp)
4943a84db2eSlayer 			&& *(bp = lastchar(bp)) == '\\')
4953a84db2eSlayer 			;
4963a84db2eSlayer 		(void) prnt_ent(tcbuf);
4973a84db2eSlayer 	}
4983a84db2eSlayer }
4993a84db2eSlayer 
5003a84db2eSlayer char *
lastchar(b)5013a84db2eSlayer lastchar(b)
5023a84db2eSlayer 	char	*b;
5033a84db2eSlayer {
5043a84db2eSlayer 	register char	*p;
5053a84db2eSlayer 
5063a84db2eSlayer 	p = b + strlen(b) - 1;
5073a84db2eSlayer 	while (*p == '\n' || *p == ' ')
5083a84db2eSlayer 		p--;
5093a84db2eSlayer 	return(p);
5103a84db2eSlayer }
5113a84db2eSlayer 
name_cmp(a,b)5123a84db2eSlayer name_cmp(a, b)
5133a84db2eSlayer 	char	*a, *b;
5143a84db2eSlayer {
5153a84db2eSlayer 	if (gflag)	/* sort on generic names */
5163a84db2eSlayer 	{
5173a84db2eSlayer 		a += 3;
5183a84db2eSlayer 		b += 3;
5193a84db2eSlayer 		while (*a && *b && *a != '|' && *a == *b)
5203a84db2eSlayer 		{
5213a84db2eSlayer 			a++;
5223a84db2eSlayer 			b++;
5233a84db2eSlayer 		}
5243a84db2eSlayer 		if (*a == '|' || *a == CNULL)
5253a84db2eSlayer 			return((*b == '|' || *b == CNULL)? 0:-1);
5263a84db2eSlayer 		if (*b == '|' || *b == CNULL)
5273a84db2eSlayer 			return(1);
5283a84db2eSlayer 		return(*a - *b);
5293a84db2eSlayer 	}
5303a84db2eSlayer 	return(strncmp(a, b, 2));
5313a84db2eSlayer }
5323a84db2eSlayer 
prnt_ent(buf)5333a84db2eSlayer prnt_ent(buf)
5343a84db2eSlayer 	register char	*buf;
5353a84db2eSlayer {
5363a84db2eSlayer 	register char	*name;
5376b6d913cSlayer 	char		*getdesc();
5383a84db2eSlayer 	char		*caps[256];
5393a84db2eSlayer 	register char	**cp;
5403a84db2eSlayer 	register char	**tp;
5413a84db2eSlayer 	char		tname[3];
5423a84db2eSlayer 
5433a84db2eSlayer 	cp = caps;
5443a84db2eSlayer 	name = buf;
5453a84db2eSlayer 	tname[3] = '\0';
5463a84db2eSlayer 
5473a84db2eSlayer 	while (*buf)
5483a84db2eSlayer 	{
5493a84db2eSlayer 		switch (*buf)
5503a84db2eSlayer 		{
5513a84db2eSlayer 		case ':':
5523a84db2eSlayer 			*buf++ = '\0';
5533a84db2eSlayer 			while (*buf && !isalnum(*buf))
5543a84db2eSlayer 				buf++;
5553a84db2eSlayer 			if (*buf)
5563a84db2eSlayer 			{
5573a84db2eSlayer 				/*
5583a84db2eSlayer 				 * ignore duplicate cap entries
5593a84db2eSlayer 				 */
5603a84db2eSlayer 				for (tp = caps; tp < cp; tp++)
5613a84db2eSlayer 					if (strncmp(buf, *tp, 2) == 0)
5623a84db2eSlayer 						goto skip;
5633a84db2eSlayer 				*cp++ = buf;
5643a84db2eSlayer 			skip:
5653a84db2eSlayer 				/*
5663a84db2eSlayer 				 * does user want tc= expanded?
5673a84db2eSlayer 				 */
5683a84db2eSlayer 				if (xflag && strncmp(buf, "tc=", 3) == 0)
5693a84db2eSlayer 				{
5703a84db2eSlayer 					/*
5713a84db2eSlayer 					 * find end of tc=
5723a84db2eSlayer 					 */
5733a84db2eSlayer 					while (*buf != ':')
5743a84db2eSlayer 						buf++;
5753a84db2eSlayer 					*buf = '\0';
5763a84db2eSlayer 					/*
5773a84db2eSlayer 					 * save term name
5783a84db2eSlayer 					 */
5793a84db2eSlayer 					tname[0] = name[0];
5803a84db2eSlayer 					tname[1] = name[1];
5813a84db2eSlayer 					printf("%s: expanding %s\n",
5823a84db2eSlayer 						tname, cp[-1]);
5833a84db2eSlayer 					/*
5843a84db2eSlayer 					 * let tgetent do the work
5853a84db2eSlayer 					 */
5863a84db2eSlayer 					tgetent(tcbuf, tname);
5873a84db2eSlayer 					prnt_ent(tcbuf);
5883a84db2eSlayer 					return;
5893a84db2eSlayer 				}
5903a84db2eSlayer 			}
5913a84db2eSlayer 			continue;
5923a84db2eSlayer 
5933a84db2eSlayer 		case '|':
5943a84db2eSlayer 			*buf++ = ',';
5953a84db2eSlayer 			continue;
5963a84db2eSlayer 
5973a84db2eSlayer 		default:
5983a84db2eSlayer 			buf++;
5993a84db2eSlayer 		}
6003a84db2eSlayer 	}
6013a84db2eSlayer 	*cp = CNULL;		/* was (char *)0 */
6023a84db2eSlayer 
603d7112359Slayer 	if (Sflag)
6043a84db2eSlayer 		qsort((char *) caps, cp - caps, sizeof (char *), ent_cmp);
6053a84db2eSlayer 
6063a84db2eSlayer 	printf("%s\n", name);
6073a84db2eSlayer 	for (cp = caps; *cp; cp++)
6084ec13c9bSlayer 		if (Uflag) {
6094ec13c9bSlayer 			if (unknowncap(*cp)) {
6104ec13c9bSlayer 				printf("%3.3s\n", *cp);
6114ec13c9bSlayer 			}
6124ec13c9bSlayer 		} else if (sflag) {
6136b6d913cSlayer 			printf("%-45s %s\n", getdesc(*cp), *cp);
6144ec13c9bSlayer 		} else {
6156b6d913cSlayer 			printf("%2.2s  %-45s %s\n", name, getdesc(*cp), *cp);
6166b6d913cSlayer 		}
6173a84db2eSlayer 	(void) putchar('\n');
6183a84db2eSlayer }
6193a84db2eSlayer 
prnt_raw(buf)6203a84db2eSlayer prnt_raw(buf)
6213a84db2eSlayer 	char		*buf;
6223a84db2eSlayer {
6233a84db2eSlayer 	register char	*b;
6243a84db2eSlayer 	register int	len;
6253a84db2eSlayer 	register int	n;
6263a84db2eSlayer 	char		*index();
6273a84db2eSlayer 
6283a84db2eSlayer 	len = 0;
6293a84db2eSlayer 	b = buf;
6303a84db2eSlayer 	while (*b)
6313a84db2eSlayer 	{
6323a84db2eSlayer 		if ((n = index(b, ':') - b + 1) <= 0)
6333a84db2eSlayer 			n = strlen(b);
6343a84db2eSlayer 		if (len == 0)			/* first part */
6353a84db2eSlayer 		{
6363a84db2eSlayer 			printf("%.*s\\\n\t:", n, b);
6373a84db2eSlayer 			len = 9 - n;
6383a84db2eSlayer 		}
6393a84db2eSlayer 		else
6403a84db2eSlayer 		{
6413a84db2eSlayer 			if ((len + n) >= 75)
6423a84db2eSlayer 			{
6433a84db2eSlayer 				printf("\\\n\t:");
6443a84db2eSlayer 				len = 9;
6453a84db2eSlayer 			}
6463a84db2eSlayer 			printf("%.*s", n, b);
6473a84db2eSlayer 		}
6483a84db2eSlayer 		len += n;
6493a84db2eSlayer 		b += n;
6503a84db2eSlayer 		while (*b && index(" \t:\n", *b))
6513a84db2eSlayer 			b++;
6523a84db2eSlayer 	}
6533a84db2eSlayer 	if (b[-1] != ':')
6543a84db2eSlayer 		(void) putchar(':');
6553a84db2eSlayer 	(void) putchar('\n');
6563a84db2eSlayer }
6573a84db2eSlayer 
ent_cmp(a,b)6583a84db2eSlayer ent_cmp(a, b)
6593a84db2eSlayer 	char **a, **b;
6603a84db2eSlayer {
6613a84db2eSlayer 	return(strncmp(*a, *b, 2));
6623a84db2eSlayer }
6633a84db2eSlayer 
check_dup()6643a84db2eSlayer check_dup()
6653a84db2eSlayer {
6663a84db2eSlayer 	/*
6673a84db2eSlayer 	** Look for duplicated names
6683a84db2eSlayer 	*/
6693a84db2eSlayer 	register char		*p;
6703a84db2eSlayer 	register char		*q;
6713a84db2eSlayer 	register struct TcName	*tn;
6723a84db2eSlayer 	register struct TcName	*tm;
6733a84db2eSlayer 
6743a84db2eSlayer 	tn = tcNames;
6753a84db2eSlayer 	while (tn->file_pos >= 0)
6763a84db2eSlayer 	{
6773a84db2eSlayer 		p = q = tn->name_buf;
6783a84db2eSlayer 		while (*q)
6793a84db2eSlayer 		{
6803a84db2eSlayer 			while (*p && *p != '|')
6813a84db2eSlayer 				p++;
6823a84db2eSlayer 			if (p != q && (tm = find_name(q, tn + 1, p - q)))
6833a84db2eSlayer 			{
6843a84db2eSlayer 				fputs("Duplicate name: ", stdout);
6853a84db2eSlayer 				while (q != p)
6863a84db2eSlayer 					(void) putchar(*q++);
6873a84db2eSlayer 				(void) putchar('\n');
6883a84db2eSlayer 				puts(tn->name_buf);
6893a84db2eSlayer 				puts(tm->name_buf);
6903a84db2eSlayer 				puts("---\n");
6913a84db2eSlayer 			}
6923a84db2eSlayer 			if (*p == '|')
6933a84db2eSlayer 				p++;
6943a84db2eSlayer 			q = p;
6953a84db2eSlayer 		}
6963a84db2eSlayer 		tn++;
6973a84db2eSlayer 	}
6983a84db2eSlayer }
6993a84db2eSlayer 
7003a84db2eSlayer struct TcName *
find_name(name,tn,len)7013a84db2eSlayer find_name(name, tn, len)
7023a84db2eSlayer 	register char		*name;
7033a84db2eSlayer 	register struct TcName	*tn;
7043a84db2eSlayer 	register int		len;
7053a84db2eSlayer {
7063a84db2eSlayer 	/*
7073a84db2eSlayer 	** find name of length len in tcname structure buffers.
7083a84db2eSlayer 	*/
7093a84db2eSlayer 	register char	*p;
7103a84db2eSlayer 	register char	*buf;
7113a84db2eSlayer 	register int	 n;
7123a84db2eSlayer 
7133a84db2eSlayer 	while (tn->file_pos >= 0)
7143a84db2eSlayer 	{
7153a84db2eSlayer 		buf = tn->name_buf;
7163a84db2eSlayer 		while (*buf)
7173a84db2eSlayer 		{
7183a84db2eSlayer 			p = name;
7193a84db2eSlayer 			n = len;
7203a84db2eSlayer 			if (*buf == '|')
7213a84db2eSlayer 				buf++;
7223a84db2eSlayer 
7233a84db2eSlayer 			while (*buf && *buf != '|')
7243a84db2eSlayer 			{
7253a84db2eSlayer 				if (*p != *buf)
7263a84db2eSlayer 				{
7273a84db2eSlayer 					while (*buf && *buf != '|')
7283a84db2eSlayer 						buf++;
7293a84db2eSlayer 					break;
7303a84db2eSlayer 				}
7313a84db2eSlayer 
7323a84db2eSlayer 				if (--n <= 0)
7333a84db2eSlayer 				{
7343a84db2eSlayer 					buf++;
7353a84db2eSlayer 					if (*buf == '|' || *buf == '\0')
7363a84db2eSlayer 						return(tn);
7373a84db2eSlayer 					while (*buf && *buf != '|')
7383a84db2eSlayer 						buf++;
7393a84db2eSlayer 					break;
7403a84db2eSlayer 				}
7413a84db2eSlayer 				buf++;
7423a84db2eSlayer 				p++;
7433a84db2eSlayer 			}
7443a84db2eSlayer 		}
7453a84db2eSlayer 		tn++;
7463a84db2eSlayer 	}
7473a84db2eSlayer 	return((struct TcName *)0);
7483a84db2eSlayer }
7496b6d913cSlayer 
7506b6d913cSlayer char *
getdesc(key)7516b6d913cSlayer getdesc(key)
7526b6d913cSlayer 	char		*key;
7536b6d913cSlayer {
7546b6d913cSlayer 	register int	i;
7556b6d913cSlayer 
756*f1fb777fSserge 	for (i = 0; i < NOCAPS; i++)
7576b6d913cSlayer 		if (strncmp(key, capList[i].cap, 2) == 0)
7586b6d913cSlayer 			return (capList[i].desc);
759c11c5bf6Slayer 	return("");
7606b6d913cSlayer }
7614ec13c9bSlayer 
unknowncap(key)7624ec13c9bSlayer unknowncap(key)
7634ec13c9bSlayer 	char		*key;
7644ec13c9bSlayer {
7654ec13c9bSlayer 	register int	i;
7664ec13c9bSlayer 
767*f1fb777fSserge 	for (i = 0; i < NOCAPS; i++)
7684ec13c9bSlayer 		if (strncmp(key, capList[i].cap, 2) == 0)
7694ec13c9bSlayer 			return (0);
7704ec13c9bSlayer 	return(1);
7714ec13c9bSlayer }
772