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