allow passing of flags to showtc
[unix-history] / usr / src / local / local.cmd / showtc.c
CommitLineData
5f5976fd
S
1#ifndef lint
2static char *sccsid="@(#)showtc.c 1.8 (Berkeley) %G%";
977b5828
KL
3#endif
4
551db654
KL
5/*
6** show termcap entries
7**
8** where:
ba9c0f2e 9** -D look for duplicate names and print termcap file
551db654 10** -S sort entries before display
ba9c0f2e 11** -T trace (-DDEBUG only)
322eb279 12** -U print unknown capabilities
551db654 13** -b show bare entries
ba9c0f2e 14** -d -D and stop
551db654 15** -f following arg is FULL PATHNAME of termcap file
977b5828 16** -g sort on generic names
977b5828
KL
17** -s don't print two char name at the front of every line
18** -x expand tc= capabilities
551db654
KL
19** [ent] display specific entry. tc= will be expanded.
20**
21** David L. Wasley, U.C.Berkeley
0b733427
KL
22** Kevin Layer: modified for 4.1c and misc changes.
23** Kevin Layer: added the printing of terminal capabilities
24** in `human' readable form (like that in "man 5 termcap").
551db654
KL
25*/
26
551db654
KL
27#include <stdio.h>
28#include <sys/file.h>
29#include <ctype.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32
33#define NO 0
34#define YES 1
35#define CNULL '\0'
36#define NOENTRIES 1024
977b5828 37#define USAGE "usage: %s [-Sxdngb] [-f termcapfile] [entry] ...\n"
551db654
KL
38
39struct TcName {
40 char name_buf[124];
41 long file_pos;
42} tcNames[NOENTRIES];
43
0b733427
KL
44struct Caps {
45 char *cap;
46 char *desc;
5f5976fd 47} capList[] =
0b733427 48{
5f5976fd
S
49 "AL", "Add N new blank lines",
50 "CC", "Command char in prototype if settable",
51 "DC", "Delete N characters",
52 "DL", "Delete N lines",
53 "DO", "Move cursor down N lines",
54 "IC", "Insert N blank characters",
55 "LE", "Move cursor left N positions",
56 "RI", "Move cursor right N positions",
57 "UP", "Move cursor up N lines",
0b733427
KL
58 "ae", "End alternate character set",
59 "al", "Add new blank line",
60 "am", "Has automatic margins",
61 "as", "Start alternate character set",
62 "bc", "Backspace if not ^H",
5f5976fd 63 "bl", "Audible Bell (default ^G)",
0b733427
KL
64 "bs", "Can backspace with ^H",
65 "bt", "Back tab",
66 "bw", "Backspace wraps from col 0 to last col",
0b733427
KL
67 "cd", "Clear to end of display",
68 "ce", "Clear to end of line",
69 "ch", "Like cm, but horizontal motion only",
70 "cl", "Clear screen",
71 "cm", "Cursor motion",
72 "co", "Number of columns in a line",
5f5976fd 73 "cr", "Carriage return (default ^M)",
0b733427 74 "cs", "Change scrolling region (vt100), like cm",
5f5976fd 75 "ct", "Clear all tab stops",
0b733427 76 "cv", "Like ch but vertical only.",
0b733427 77 "dB", "Number of millisec of bs delay needed",
0b733427 78 "dC", "Number of millisec of cr delay needed",
0b733427 79 "dF", "Number of millisec of ff delay needed",
5f5976fd
S
80 "dN", "Number of millisec of nl delay needed",
81 "dT", "Number of millisec of tab delay needed",
82 "da", "Display may be retained above",
83 "db", "Display may be retained below",
84 "dc", "Delete character",
0b733427
KL
85 "dl", "Delete line",
86 "dm", "Start Delete mode",
0b733427 87 "do", "Down one line",
180b3e99 88 "ds", "Disable status display",
0b733427
KL
89 "ed", "End delete mode",
90 "ei", "End insert mode;give \":ei=:\" if ic",
91 "eo", "Can erase overstrikes with a blank",
180b3e99 92 "es", "Escape seq's ok on status line",
0b733427
KL
93 "ff", "Hardcopy page eject (default ^L)",
94 "fs", "From status line sequence",
95 "hc", "Hardcopy terminal",
96 "hd", "Half-line down (forward 1/2 lf)",
97 "ho", "Home cursor (if no cm)",
5f5976fd 98 "hs", "Has status line",
0b733427
KL
99 "hu", "Half-line up (reverse 1/2 lf)",
100 "hz", "Hazeltine; can't print ~'s",
5f5976fd 101 "i2", "Initialization string (used by sysline(1))",
0b733427
KL
102 "ic", "Insert character",
103 "if", "Name of file containing is",
104 "im", "Start insert mode;give \":im=:\" if ic",
105 "in", "Insert mode distinguishes nulls on display",
106 "ip", "Insert pad after character inserted",
107 "is", "Initialization string",
5f5976fd
S
108 "k0", "Sent by function key 0",
109 "k1", "Sent by function key 1",
110 "k2", "Sent by function key 2",
111 "k3", "Sent by function key 3",
112 "k4", "Sent by function key 4",
113 "k5", "Sent by function key 5",
114 "k6", "Sent by function key 6",
115 "k7", "Sent by function key 7",
116 "k8", "Sent by function key 8",
117 "k9", "Sent by function key 9",
0b733427 118 "kb", "Sent by backspace key",
5f5976fd 119 "kd", "Sent by down arrow key",
0b733427
KL
120 "ke", "Out of \"keypad transmit\" mode",
121 "kh", "Sent by home key",
122 "kl", "Sent by left arrow key",
5f5976fd 123 "km", "Has a \"meta\" key (shift, sets parity bit)",
0b733427
KL
124 "kn", "Number of \"other\" keys",
125 "ko", "Tc entries for other non-function keys",
126 "kr", "Sent by right arrow key",
127 "ks", "Put in \"keypad transmit\" mode",
128 "ku", "Sent by up arrow key",
5f5976fd
S
129 "l0", "Label on function key 0 (if not \"0\")",
130 "l1", "Label on function key 1 (if not \"1\")",
131 "l2", "Label on function key 2 (if not \"2\")",
132 "l3", "Label on function key 3 (if not \"3\")",
133 "l4", "Label on function key 4 (if not \"4\")",
134 "l5", "Label on function key 5 (if not \"5\")",
135 "l6", "Label on function key 6 (if not \"6\")",
136 "l7", "Label on function key 7 (if not \"7\")",
137 "l8", "Label on function key 8 (if not \"8\")",
138 "l9", "Label on function key 9 (if not \"9\")",
322eb279 139 "le", "Move left",
0b733427
KL
140 "li", "Number of lines on screen or page",
141 "ll", "Last line, first column (if no cm)",
142 "ma", "Arrow key map, used by vi V2 only",
322eb279
KL
143 "mb", "Enter blinking mode",
144 "md", "Enter bold mode",
145 "me", "Reset video attributes",
146 "mh", "Enter halfbright mode",
0b733427 147 "mi", "Safe to move while in insert mode",
322eb279 148 "mk", "Enter protected mode",
0b733427 149 "ml", "Memory lock on above cursor.",
5f5976fd 150 "mp", "Turn on protected attribute",
322eb279 151 "mr", "Enter reverse video mode",
0b733427
KL
152 "ms", "Ok to move while in standout/underline mode",
153 "mu", "Memory unlock (turn off memory lock).",
154 "nc", "No working CR (DM2500,H2000)",
155 "nd", "Non-destructive space (cursor right)",
156 "nl", "Newline character (default \\n)",
157 "ns", "Is a CRT but doesn't scroll.",
158 "os", "Terminal overstrikes",
5f5976fd 159 "pb", "Lowest baud where delays are required",
0b733427 160 "pc", "Pad character (rather than null)",
5f5976fd 161 "pl", "Program function key N to execute string S (terminfo only)",
0b733427 162 "pt", "Has hardware tabs (may need to use is)",
5f5976fd
S
163 "rc", "Restore cursor to position of last sc",
164 "rf", "Name of file containing reset codes",
165 "rs", "Reset terminal completely to sane modes",
166 "sc", "Save cursor position",
0b733427
KL
167 "se", "End stand out mode",
168 "sf", "Scroll forwards",
169 "sg", "Number of blank chars left by so/se",
170 "so", "Begin stand out mode",
171 "sr", "Scroll reverse (backwards)",
5f5976fd 172 "st", "Set a tab in all rows, current column",
0b733427
KL
173 "ta", "Tab (other than ^I or with padding)",
174 "tc", "Entry of similar terminal - must be last",
175 "te", "String to end programs that use cm",
176 "ti", "String to begin programs that use cm",
177 "ts", "To status line sequence",
178 "uc", "Underscore one char and move past it",
179 "ue", "End underscore mode",
180 "ug", "Number of blank chars left by us or ue",
181 "ul", "Underlines, though no overstrike",
182 "up", "Upline (cursor up)",
183 "us", "Start underscore mode",
184 "vb", "Visible bell (may not move cursor)",
185 "ve", "Sequence to end open/visual mode",
186 "vs", "Sequence to start open/visual mode",
5f5976fd 187 "vt", "Virtual terminal number (not supported on all systems)",
0b733427
KL
188 "xb", "Beehive (f1=escape, f2=ctrl C)",
189 "xn", "A newline is ignored after a wrap (Concept)",
190 "xr", "Return acts like ce \\r \\n (Delta Data)",
191 "xs", "Standout not erased by writing over it (HP 264?)",
192 "xt", "Destructive tabs, magic so char (Teleray 1061)"
193};
194
5f5976fd
S
195#define NOCAPS (sizeof capList / sizeof *capList)
196
551db654
KL
197#ifdef DEBUG
198int Dflag = NO;
199#endif
200int xflag = NO;
977b5828
KL
201int Sflag = YES;
202int sflag = NO;
551db654
KL
203int dflag = NO;
204int nflag = NO;
205int gflag = NO;
206int bflag = NO;
322eb279 207int Uflag = NO;
551db654
KL
208int tc_loopc; /* loop counter */
209char *tcfile; /* termcap database pathname */
2d9f9d8c 210char tcbuf[2048]; /* buffer for termcap description */
551db654
KL
211char *lastchar();
212int name_cmp();
213int ent_cmp();
214struct TcName *find_name();
215char *getenv();
216char *ctime();
217char *strncpy();
218long ftell();
219
220main(argc, argv, envp)
221 int argc;
222 char **argv;
223 char **envp;
224{
225 char *av;
226 struct TcName *tn;
227 register char *bp;
228 long pos;
229 int n;
230 struct stat st;
231 char envbuf[256];
232 FILE *tcfp;
233
234 if ((bp = getenv("TERMCAP")) && *bp == '/')
235 tcfile = bp;
236 else
237 tcfile = "/etc/termcap";
238
239 while (--argc > 0)
240 {
241 if (*(av = *++argv) == '-')
242 {
243 while (*++av)
244 {
245 switch (*av)
246 {
247 /* use alternate termcap file */
248 case 'f':
249 if (argc-- <= 0)
250 {
251 fprintf(stderr,
252 "-f needs a filename\n");
253 exit(1);
254 }
255 tcfile = *++argv;
256 break;
257
258 /* only check for dup names */
ba9c0f2e 259 case 'd':
551db654
KL
260 nflag = YES;
261 /* fall thru */
262
263 /* look for duplicated names */
ba9c0f2e 264 case 'D':
551db654
KL
265 dflag = YES;
266 continue;
267
322eb279
KL
268 case 'U':
269 Uflag = YES;
270 continue;
271
977b5828
KL
272 /* strip the two name off */
273 case 's':
274 sflag = YES;
275 continue;
276
551db654
KL
277 /* sort the name array */
278 case 'S':
977b5828 279 Sflag = NO;
551db654
KL
280 continue;
281
282#ifdef DEBUG
ba9c0f2e 283 case 'T':
551db654
KL
284 Dflag = YES;
285 continue;
286#endif
287
288 /* sort on generic names */
289 case 'g':
290 gflag = YES;
291 continue;
292
293 /* expand entries in 'full mode' */
294 case 'x':
295 xflag = YES;
296 continue;
297
298 /* show bare entry */
299 case 'b':
300 bflag = YES;
301 continue;
302
303 default:
304 fprintf(stderr, "showtc: unknown flag: -%c\n", *av);
305 fprintf(stderr, USAGE, argv[0]);
306 exit(1);
307 }
308 }
309 }
310 else
311 break;
312 }
313
314 /*
315 * insert the specified TERMCAP file into the environment
316 */
317 (void) sprintf(envbuf, "TERMCAP=%s", tcfile);
318 while (*envp)
319 {
320 if (strncmp(*envp, "TERMCAP=", 8) == 0)
321 {
322 *envp = envbuf;
323 break;
324 }
325 envp++;
326 }
327 if (! *envp)
328 *envp = envbuf; /* this may be dangerous */
329
330 /*
331 ** if user specified type(s), do only those
332 */
333 if (argc > 0)
334 {
335 /*
336 ** look for the users specified term types
337 */
338 while (argc > 0)
339 {
340 switch (n = tgetent(tcbuf, *argv))
341 {
342 case 1:
343 if (bflag)
344 (void) prnt_raw(tcbuf);
345 else
346 (void) prnt_ent(tcbuf);
347 break;
348
349 case 0:
350 fprintf(stderr,
351 "showtc: bad entry: %s\n", *argv);
352 break;
353
354 case -1:
355 fputs("showtc: ", stderr);
356 perror(tcfile);
357 exit(1);
358
359 default:
360 fprintf(stderr, "bad return from tgetent: %d\n", n);
361 exit(1);
362 }
363 argc--;
364 argv++;
365 }
366 exit(0);
367 }
368
369 if (bflag)
370 {
371 fprintf(stderr, "showtc: -b flag with no entries makes no sense.\n");
372 exit(1);
373 }
374
375
376 /*
377 ** if no type was specified, do the whole file
378 */
379 if ((tcfp = fopen(tcfile, "r")) == NULL)
380 {
381 perror(tcfile);
382 exit(1);
383 }
384
385 /*
386 ** identify database, for the record
387 */
388 if (stat(tcfile, &st))
389 {
390 perror(tcfile);
391 exit(1);
392 }
393 printf("File: %s, last modified: %s\n", tcfile, ctime(&st.st_mtime));
394
395
396 /*
397 ** build termcap entry table
398 */
399 tn = tcNames;
400 pos = ftell(tcfp);
401 bp = tcbuf;
402 while (fgets(bp, sizeof (tcbuf), tcfp) != NULL)
403 {
404 if (tcbuf[0] == '#')
405 {
406 pos = ftell(tcfp);
407 bp = tcbuf;
408 continue;
409 }
410
411 tn->file_pos = pos;
412
413 /*
414 ** get full entry
415 */
416 while (*(bp = lastchar(bp)) == '\\' && fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp))
417 ;
418 /*
419 ** save the names
420 */
421 for (bp = tcbuf; *bp && *bp != ':'; bp++)
422 ;
423 *bp = '\0';
424 (void) strncpy(tn->name_buf, tcbuf,
425 sizeof tcNames[0].name_buf);
426
427 pos = ftell(tcfp);
428 bp = tcbuf;
429 tn++;
430 }
431 tn->file_pos = -1;
432
433 /*
434 ** Look for duplicate names
435 */
436 if (dflag)
437 check_dup();
438 if (nflag)
439 exit(0);
440
441#ifdef DEBUG
442 if (Dflag)
443 {
444 for (tn = tcNames; tn->file_pos >= 0; tn++)
445 {
446 printf("Entry #%d:\n\t%s\n\tfile_pos = %ld\n",
447 tn - tcNames, tn->name_buf, tn->file_pos);
448 }
449 exit(0);
450 }
451#endif
452
453 /*
454 ** Order the list
455 */
977b5828 456 if (Sflag)
551db654
KL
457 qsort((char *)tcNames, tn - tcNames,
458 sizeof (struct TcName), name_cmp);
459
460 /*
461 ** List termcap entry for each name in table
462 */
463 for (tn = tcNames; tn->file_pos >= 0; tn++)
464 {
465 tc_loopc = 0;
466 /*** working toward this ...
467 (void) prnt_ent(tn);
468 ***/
469 (void) fseek(tcfp, tn->file_pos, 0);
470 bp = tcbuf;
471 while (fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp)
472 && *(bp = lastchar(bp)) == '\\')
473 ;
474 (void) prnt_ent(tcbuf);
475 }
476}
477
478char *
479lastchar(b)
480 char *b;
481{
482 register char *p;
483
484 p = b + strlen(b) - 1;
485 while (*p == '\n' || *p == ' ')
486 p--;
487 return(p);
488}
489
490name_cmp(a, b)
491 char *a, *b;
492{
493 if (gflag) /* sort on generic names */
494 {
495 a += 3;
496 b += 3;
497 while (*a && *b && *a != '|' && *a == *b)
498 {
499 a++;
500 b++;
501 }
502 if (*a == '|' || *a == CNULL)
503 return((*b == '|' || *b == CNULL)? 0:-1);
504 if (*b == '|' || *b == CNULL)
505 return(1);
506 return(*a - *b);
507 }
508 return(strncmp(a, b, 2));
509}
510
511prnt_ent(buf)
512 register char *buf;
513{
514 register char *name;
0b733427 515 char *getdesc();
551db654
KL
516 char *caps[256];
517 register char **cp;
518 register char **tp;
519 char tname[3];
520
521 cp = caps;
522 name = buf;
523 tname[3] = '\0';
524
525 while (*buf)
526 {
527 switch (*buf)
528 {
529 case ':':
530 *buf++ = '\0';
531 while (*buf && !isalnum(*buf))
532 buf++;
533 if (*buf)
534 {
535 /*
536 * ignore duplicate cap entries
537 */
538 for (tp = caps; tp < cp; tp++)
539 if (strncmp(buf, *tp, 2) == 0)
540 goto skip;
541 *cp++ = buf;
542 skip:
543 /*
544 * does user want tc= expanded?
545 */
546 if (xflag && strncmp(buf, "tc=", 3) == 0)
547 {
548 /*
549 * find end of tc=
550 */
551 while (*buf != ':')
552 buf++;
553 *buf = '\0';
554 /*
555 * save term name
556 */
557 tname[0] = name[0];
558 tname[1] = name[1];
559 printf("%s: expanding %s\n",
560 tname, cp[-1]);
561 /*
562 * let tgetent do the work
563 */
564 tgetent(tcbuf, tname);
565 prnt_ent(tcbuf);
566 return;
567 }
568 }
569 continue;
570
571 case '|':
572 *buf++ = ',';
573 continue;
574
575 default:
576 buf++;
577 }
578 }
579 *cp = CNULL; /* was (char *)0 */
580
977b5828 581 if (Sflag)
551db654
KL
582 qsort((char *) caps, cp - caps, sizeof (char *), ent_cmp);
583
584 printf("%s\n", name);
585 for (cp = caps; *cp; cp++)
322eb279
KL
586 if (Uflag) {
587 if (unknowncap(*cp)) {
588 printf("%3.3s\n", *cp);
589 }
590 } else if (sflag) {
0b733427 591 printf("%-45s %s\n", getdesc(*cp), *cp);
322eb279 592 } else {
0b733427
KL
593 printf("%2.2s %-45s %s\n", name, getdesc(*cp), *cp);
594 }
551db654
KL
595 (void) putchar('\n');
596}
597
598prnt_raw(buf)
599 char *buf;
600{
601 register char *b;
602 register int len;
603 register int n;
604 char *index();
605
606 len = 0;
607 b = buf;
608 while (*b)
609 {
610 if ((n = index(b, ':') - b + 1) <= 0)
611 n = strlen(b);
612 if (len == 0) /* first part */
613 {
614 printf("%.*s\\\n\t:", n, b);
615 len = 9 - n;
616 }
617 else
618 {
619 if ((len + n) >= 75)
620 {
621 printf("\\\n\t:");
622 len = 9;
623 }
624 printf("%.*s", n, b);
625 }
626 len += n;
627 b += n;
628 while (*b && index(" \t:\n", *b))
629 b++;
630 }
631 if (b[-1] != ':')
632 (void) putchar(':');
633 (void) putchar('\n');
634}
635
636ent_cmp(a, b)
637 char **a, **b;
638{
639 return(strncmp(*a, *b, 2));
640}
641
642check_dup()
643{
644 /*
645 ** Look for duplicated names
646 */
647 register char *p;
648 register char *q;
649 register struct TcName *tn;
650 register struct TcName *tm;
651
652 tn = tcNames;
653 while (tn->file_pos >= 0)
654 {
655 p = q = tn->name_buf;
656 while (*q)
657 {
658 while (*p && *p != '|')
659 p++;
660 if (p != q && (tm = find_name(q, tn + 1, p - q)))
661 {
662 fputs("Duplicate name: ", stdout);
663 while (q != p)
664 (void) putchar(*q++);
665 (void) putchar('\n');
666 puts(tn->name_buf);
667 puts(tm->name_buf);
668 puts("---\n");
669 }
670 if (*p == '|')
671 p++;
672 q = p;
673 }
674 tn++;
675 }
676}
677
678struct TcName *
679find_name(name, tn, len)
680 register char *name;
681 register struct TcName *tn;
682 register int len;
683{
684 /*
685 ** find name of length len in tcname structure buffers.
686 */
687 register char *p;
688 register char *buf;
689 register int n;
690
691 while (tn->file_pos >= 0)
692 {
693 buf = tn->name_buf;
694 while (*buf)
695 {
696 p = name;
697 n = len;
698 if (*buf == '|')
699 buf++;
700
701 while (*buf && *buf != '|')
702 {
703 if (*p != *buf)
704 {
705 while (*buf && *buf != '|')
706 buf++;
707 break;
708 }
709
710 if (--n <= 0)
711 {
712 buf++;
713 if (*buf == '|' || *buf == '\0')
714 return(tn);
715 while (*buf && *buf != '|')
716 buf++;
717 break;
718 }
719 buf++;
720 p++;
721 }
722 }
723 tn++;
724 }
725 return((struct TcName *)0);
726}
0b733427
KL
727
728char *
729getdesc(key)
730 char *key;
731{
732 register int i;
733
734 for (i = 0; i <= NOCAPS; i++)
735 if (strncmp(key, capList[i].cap, 2) == 0)
736 return (capList[i].desc);
ba9c0f2e 737 return("");
0b733427 738}
322eb279
KL
739
740unknowncap(key)
741 char *key;
742{
743 register int i;
744
745 for (i = 0; i <= NOCAPS; i++)
746 if (strncmp(key, capList[i].cap, 2) == 0)
747 return (0);
748 return(1);
749}