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