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