1*25326Sserge #ifndef lint 2*25326Sserge static char *sccsid="@(#)showtc.c 1.8 (Berkeley) 10/28/85"; 312044Slayer #endif 412044Slayer 512031Slayer /* 612031Slayer ** show termcap entries 712031Slayer ** 812031Slayer ** where: 912458Slayer ** -D look for duplicate names and print termcap file 1012031Slayer ** -S sort entries before display 1112458Slayer ** -T trace (-DDEBUG only) 1213250Slayer ** -U print unknown capabilities 1312044Slayer ** -b show bare entries 1412458Slayer ** -d -D and stop 1512044Slayer ** -f following arg is FULL PATHNAME of termcap file 1612044Slayer ** -g sort on generic names 1712044Slayer ** -s don't print two char name at the front of every line 1812044Slayer ** -x expand tc= capabilities 1912031Slayer ** [ent] display specific entry. tc= will be expanded. 2012031Slayer ** 2112031Slayer ** David L. Wasley, U.C.Berkeley 2212446Slayer ** Kevin Layer: modified for 4.1c and misc changes. 2312446Slayer ** Kevin Layer: added the printing of terminal capabilities 2412446Slayer ** in `human' readable form (like that in "man 5 termcap"). 2512031Slayer */ 2612031Slayer 2712031Slayer #include <stdio.h> 2812031Slayer #include <sys/file.h> 2912031Slayer #include <ctype.h> 3012031Slayer #include <sys/types.h> 3112031Slayer #include <sys/stat.h> 3212031Slayer 3312031Slayer #define NO 0 3412031Slayer #define YES 1 3512031Slayer #define CNULL '\0' 3612031Slayer #define NOENTRIES 1024 3712044Slayer #define USAGE "usage: %s [-Sxdngb] [-f termcapfile] [entry] ...\n" 3812031Slayer 3912031Slayer struct TcName { 4012031Slayer char name_buf[124]; 4112031Slayer long file_pos; 4212031Slayer } tcNames[NOENTRIES]; 4312031Slayer 4412446Slayer struct Caps { 4512446Slayer char *cap; 4612446Slayer char *desc; 47*25326Sserge } capList[] = 4812446Slayer { 49*25326Sserge "AL", "Add N new blank lines", 50*25326Sserge "CC", "Command char in prototype if settable", 51*25326Sserge "DC", "Delete N characters", 52*25326Sserge "DL", "Delete N lines", 53*25326Sserge "DO", "Move cursor down N lines", 54*25326Sserge "IC", "Insert N blank characters", 55*25326Sserge "LE", "Move cursor left N positions", 56*25326Sserge "RI", "Move cursor right N positions", 57*25326Sserge "UP", "Move cursor up N lines", 5812446Slayer "ae", "End alternate character set", 5912446Slayer "al", "Add new blank line", 6012446Slayer "am", "Has automatic margins", 6112446Slayer "as", "Start alternate character set", 6212446Slayer "bc", "Backspace if not ^H", 63*25326Sserge "bl", "Audible Bell (default ^G)", 6412446Slayer "bs", "Can backspace with ^H", 6512446Slayer "bt", "Back tab", 6612446Slayer "bw", "Backspace wraps from col 0 to last col", 6712446Slayer "cd", "Clear to end of display", 6812446Slayer "ce", "Clear to end of line", 6912446Slayer "ch", "Like cm, but horizontal motion only", 7012446Slayer "cl", "Clear screen", 7112446Slayer "cm", "Cursor motion", 7212446Slayer "co", "Number of columns in a line", 73*25326Sserge "cr", "Carriage return (default ^M)", 7412446Slayer "cs", "Change scrolling region (vt100), like cm", 75*25326Sserge "ct", "Clear all tab stops", 7612446Slayer "cv", "Like ch but vertical only.", 77*25326Sserge "dB", "Number of millisec of bs delay needed", 78*25326Sserge "dC", "Number of millisec of cr delay needed", 79*25326Sserge "dF", "Number of millisec of ff delay needed", 80*25326Sserge "dN", "Number of millisec of nl delay needed", 81*25326Sserge "dT", "Number of millisec of tab delay needed", 8212446Slayer "da", "Display may be retained above", 8312446Slayer "db", "Display may be retained below", 8412446Slayer "dc", "Delete character", 8512446Slayer "dl", "Delete line", 8612446Slayer "dm", "Start Delete mode", 8712446Slayer "do", "Down one line", 8812461Slayer "ds", "Disable status display", 8912446Slayer "ed", "End delete mode", 9012446Slayer "ei", "End insert mode;give \":ei=:\" if ic", 9112446Slayer "eo", "Can erase overstrikes with a blank", 9212461Slayer "es", "Escape seq's ok on status line", 9312446Slayer "ff", "Hardcopy page eject (default ^L)", 9412446Slayer "fs", "From status line sequence", 9512446Slayer "hc", "Hardcopy terminal", 9612446Slayer "hd", "Half-line down (forward 1/2 lf)", 9712446Slayer "ho", "Home cursor (if no cm)", 98*25326Sserge "hs", "Has status line", 9912446Slayer "hu", "Half-line up (reverse 1/2 lf)", 10012446Slayer "hz", "Hazeltine; can't print ~'s", 101*25326Sserge "i2", "Initialization string (used by sysline(1))", 10212446Slayer "ic", "Insert character", 10312446Slayer "if", "Name of file containing is", 10412446Slayer "im", "Start insert mode;give \":im=:\" if ic", 10512446Slayer "in", "Insert mode distinguishes nulls on display", 10612446Slayer "ip", "Insert pad after character inserted", 10712446Slayer "is", "Initialization string", 108*25326Sserge "k0", "Sent by function key 0", 109*25326Sserge "k1", "Sent by function key 1", 110*25326Sserge "k2", "Sent by function key 2", 111*25326Sserge "k3", "Sent by function key 3", 112*25326Sserge "k4", "Sent by function key 4", 113*25326Sserge "k5", "Sent by function key 5", 114*25326Sserge "k6", "Sent by function key 6", 115*25326Sserge "k7", "Sent by function key 7", 116*25326Sserge "k8", "Sent by function key 8", 117*25326Sserge "k9", "Sent by function key 9", 11812446Slayer "kb", "Sent by backspace key", 119*25326Sserge "kd", "Sent by down arrow key", 12012446Slayer "ke", "Out of \"keypad transmit\" mode", 12112446Slayer "kh", "Sent by home key", 12212446Slayer "kl", "Sent by left arrow key", 123*25326Sserge "km", "Has a \"meta\" key (shift, sets parity bit)", 12412446Slayer "kn", "Number of \"other\" keys", 12512446Slayer "ko", "Tc entries for other non-function keys", 12612446Slayer "kr", "Sent by right arrow key", 12712446Slayer "ks", "Put in \"keypad transmit\" mode", 12812446Slayer "ku", "Sent by up arrow key", 129*25326Sserge "l0", "Label on function key 0 (if not \"0\")", 130*25326Sserge "l1", "Label on function key 1 (if not \"1\")", 131*25326Sserge "l2", "Label on function key 2 (if not \"2\")", 132*25326Sserge "l3", "Label on function key 3 (if not \"3\")", 133*25326Sserge "l4", "Label on function key 4 (if not \"4\")", 134*25326Sserge "l5", "Label on function key 5 (if not \"5\")", 135*25326Sserge "l6", "Label on function key 6 (if not \"6\")", 136*25326Sserge "l7", "Label on function key 7 (if not \"7\")", 137*25326Sserge "l8", "Label on function key 8 (if not \"8\")", 138*25326Sserge "l9", "Label on function key 9 (if not \"9\")", 13913250Slayer "le", "Move left", 14012446Slayer "li", "Number of lines on screen or page", 14112446Slayer "ll", "Last line, first column (if no cm)", 14212446Slayer "ma", "Arrow key map, used by vi V2 only", 14313250Slayer "mb", "Enter blinking mode", 14413250Slayer "md", "Enter bold mode", 14513250Slayer "me", "Reset video attributes", 14613250Slayer "mh", "Enter halfbright mode", 14712446Slayer "mi", "Safe to move while in insert mode", 14813250Slayer "mk", "Enter protected mode", 14912446Slayer "ml", "Memory lock on above cursor.", 150*25326Sserge "mp", "Turn on protected attribute", 15113250Slayer "mr", "Enter reverse video mode", 15212446Slayer "ms", "Ok to move while in standout/underline mode", 15312446Slayer "mu", "Memory unlock (turn off memory lock).", 15412446Slayer "nc", "No working CR (DM2500,H2000)", 15512446Slayer "nd", "Non-destructive space (cursor right)", 15612446Slayer "nl", "Newline character (default \\n)", 15712446Slayer "ns", "Is a CRT but doesn't scroll.", 15812446Slayer "os", "Terminal overstrikes", 159*25326Sserge "pb", "Lowest baud where delays are required", 16012446Slayer "pc", "Pad character (rather than null)", 161*25326Sserge "pl", "Program function key N to execute string S (terminfo only)", 16212446Slayer "pt", "Has hardware tabs (may need to use is)", 163*25326Sserge "rc", "Restore cursor to position of last sc", 164*25326Sserge "rf", "Name of file containing reset codes", 165*25326Sserge "rs", "Reset terminal completely to sane modes", 166*25326Sserge "sc", "Save cursor position", 16712446Slayer "se", "End stand out mode", 16812446Slayer "sf", "Scroll forwards", 16912446Slayer "sg", "Number of blank chars left by so/se", 17012446Slayer "so", "Begin stand out mode", 17112446Slayer "sr", "Scroll reverse (backwards)", 172*25326Sserge "st", "Set a tab in all rows, current column", 17312446Slayer "ta", "Tab (other than ^I or with padding)", 17412446Slayer "tc", "Entry of similar terminal - must be last", 17512446Slayer "te", "String to end programs that use cm", 17612446Slayer "ti", "String to begin programs that use cm", 17712446Slayer "ts", "To status line sequence", 17812446Slayer "uc", "Underscore one char and move past it", 17912446Slayer "ue", "End underscore mode", 18012446Slayer "ug", "Number of blank chars left by us or ue", 18112446Slayer "ul", "Underlines, though no overstrike", 18212446Slayer "up", "Upline (cursor up)", 18312446Slayer "us", "Start underscore mode", 18412446Slayer "vb", "Visible bell (may not move cursor)", 18512446Slayer "ve", "Sequence to end open/visual mode", 18612446Slayer "vs", "Sequence to start open/visual mode", 187*25326Sserge "vt", "Virtual terminal number (not supported on all systems)", 18812446Slayer "xb", "Beehive (f1=escape, f2=ctrl C)", 18912446Slayer "xn", "A newline is ignored after a wrap (Concept)", 19012446Slayer "xr", "Return acts like ce \\r \\n (Delta Data)", 19112446Slayer "xs", "Standout not erased by writing over it (HP 264?)", 19212446Slayer "xt", "Destructive tabs, magic so char (Teleray 1061)" 19312446Slayer }; 19412446Slayer 195*25326Sserge #define NOCAPS (sizeof capList / sizeof *capList) 196*25326Sserge 19712031Slayer #ifdef DEBUG 19812031Slayer int Dflag = NO; 19912031Slayer #endif 20012031Slayer int xflag = NO; 20112044Slayer int Sflag = YES; 20212044Slayer int sflag = NO; 20312031Slayer int dflag = NO; 20412031Slayer int nflag = NO; 20512031Slayer int gflag = NO; 20612031Slayer int bflag = NO; 20713250Slayer int Uflag = NO; 20812031Slayer int tc_loopc; /* loop counter */ 20912031Slayer char *tcfile; /* termcap database pathname */ 21015192Slayer char tcbuf[2048]; /* buffer for termcap description */ 21112031Slayer char *lastchar(); 21212031Slayer int name_cmp(); 21312031Slayer int ent_cmp(); 21412031Slayer struct TcName *find_name(); 21512031Slayer char *getenv(); 21612031Slayer char *ctime(); 21712031Slayer char *strncpy(); 21812031Slayer long ftell(); 21912031Slayer 22012031Slayer main(argc, argv, envp) 22112031Slayer int argc; 22212031Slayer char **argv; 22312031Slayer char **envp; 22412031Slayer { 22512031Slayer char *av; 22612031Slayer struct TcName *tn; 22712031Slayer register char *bp; 22812031Slayer long pos; 22912031Slayer int n; 23012031Slayer struct stat st; 23112031Slayer char envbuf[256]; 23212031Slayer FILE *tcfp; 23312031Slayer 23412031Slayer if ((bp = getenv("TERMCAP")) && *bp == '/') 23512031Slayer tcfile = bp; 23612031Slayer else 23712031Slayer tcfile = "/etc/termcap"; 23812031Slayer 23912031Slayer while (--argc > 0) 24012031Slayer { 24112031Slayer if (*(av = *++argv) == '-') 24212031Slayer { 24312031Slayer while (*++av) 24412031Slayer { 24512031Slayer switch (*av) 24612031Slayer { 24712031Slayer /* use alternate termcap file */ 24812031Slayer case 'f': 24912031Slayer if (argc-- <= 0) 25012031Slayer { 25112031Slayer fprintf(stderr, 25212031Slayer "-f needs a filename\n"); 25312031Slayer exit(1); 25412031Slayer } 25512031Slayer tcfile = *++argv; 25612031Slayer break; 25712031Slayer 25812031Slayer /* only check for dup names */ 25912458Slayer case 'd': 26012031Slayer nflag = YES; 26112031Slayer /* fall thru */ 26212031Slayer 26312031Slayer /* look for duplicated names */ 26412458Slayer case 'D': 26512031Slayer dflag = YES; 26612031Slayer continue; 26712031Slayer 26813250Slayer case 'U': 26913250Slayer Uflag = YES; 27013250Slayer continue; 27113250Slayer 27212044Slayer /* strip the two name off */ 27312044Slayer case 's': 27412044Slayer sflag = YES; 27512044Slayer continue; 27612044Slayer 27712031Slayer /* sort the name array */ 27812031Slayer case 'S': 27912044Slayer Sflag = NO; 28012031Slayer continue; 28112031Slayer 28212031Slayer #ifdef DEBUG 28312458Slayer case 'T': 28412031Slayer Dflag = YES; 28512031Slayer continue; 28612031Slayer #endif 28712031Slayer 28812031Slayer /* sort on generic names */ 28912031Slayer case 'g': 29012031Slayer gflag = YES; 29112031Slayer continue; 29212031Slayer 29312031Slayer /* expand entries in 'full mode' */ 29412031Slayer case 'x': 29512031Slayer xflag = YES; 29612031Slayer continue; 29712031Slayer 29812031Slayer /* show bare entry */ 29912031Slayer case 'b': 30012031Slayer bflag = YES; 30112031Slayer continue; 30212031Slayer 30312031Slayer default: 30412031Slayer fprintf(stderr, "showtc: unknown flag: -%c\n", *av); 30512031Slayer fprintf(stderr, USAGE, argv[0]); 30612031Slayer exit(1); 30712031Slayer } 30812031Slayer } 30912031Slayer } 31012031Slayer else 31112031Slayer break; 31212031Slayer } 31312031Slayer 31412031Slayer /* 31512031Slayer * insert the specified TERMCAP file into the environment 31612031Slayer */ 31712031Slayer (void) sprintf(envbuf, "TERMCAP=%s", tcfile); 31812031Slayer while (*envp) 31912031Slayer { 32012031Slayer if (strncmp(*envp, "TERMCAP=", 8) == 0) 32112031Slayer { 32212031Slayer *envp = envbuf; 32312031Slayer break; 32412031Slayer } 32512031Slayer envp++; 32612031Slayer } 32712031Slayer if (! *envp) 32812031Slayer *envp = envbuf; /* this may be dangerous */ 32912031Slayer 33012031Slayer /* 33112031Slayer ** if user specified type(s), do only those 33212031Slayer */ 33312031Slayer if (argc > 0) 33412031Slayer { 33512031Slayer /* 33612031Slayer ** look for the users specified term types 33712031Slayer */ 33812031Slayer while (argc > 0) 33912031Slayer { 34012031Slayer switch (n = tgetent(tcbuf, *argv)) 34112031Slayer { 34212031Slayer case 1: 34312031Slayer if (bflag) 34412031Slayer (void) prnt_raw(tcbuf); 34512031Slayer else 34612031Slayer (void) prnt_ent(tcbuf); 34712031Slayer break; 34812031Slayer 34912031Slayer case 0: 35012031Slayer fprintf(stderr, 35112031Slayer "showtc: bad entry: %s\n", *argv); 35212031Slayer break; 35312031Slayer 35412031Slayer case -1: 35512031Slayer fputs("showtc: ", stderr); 35612031Slayer perror(tcfile); 35712031Slayer exit(1); 35812031Slayer 35912031Slayer default: 36012031Slayer fprintf(stderr, "bad return from tgetent: %d\n", n); 36112031Slayer exit(1); 36212031Slayer } 36312031Slayer argc--; 36412031Slayer argv++; 36512031Slayer } 36612031Slayer exit(0); 36712031Slayer } 36812031Slayer 36912031Slayer if (bflag) 37012031Slayer { 37112031Slayer fprintf(stderr, "showtc: -b flag with no entries makes no sense.\n"); 37212031Slayer exit(1); 37312031Slayer } 37412031Slayer 37512031Slayer 37612031Slayer /* 37712031Slayer ** if no type was specified, do the whole file 37812031Slayer */ 37912031Slayer if ((tcfp = fopen(tcfile, "r")) == NULL) 38012031Slayer { 38112031Slayer perror(tcfile); 38212031Slayer exit(1); 38312031Slayer } 38412031Slayer 38512031Slayer /* 38612031Slayer ** identify database, for the record 38712031Slayer */ 38812031Slayer if (stat(tcfile, &st)) 38912031Slayer { 39012031Slayer perror(tcfile); 39112031Slayer exit(1); 39212031Slayer } 39312031Slayer printf("File: %s, last modified: %s\n", tcfile, ctime(&st.st_mtime)); 39412031Slayer 39512031Slayer 39612031Slayer /* 39712031Slayer ** build termcap entry table 39812031Slayer */ 39912031Slayer tn = tcNames; 40012031Slayer pos = ftell(tcfp); 40112031Slayer bp = tcbuf; 40212031Slayer while (fgets(bp, sizeof (tcbuf), tcfp) != NULL) 40312031Slayer { 40412031Slayer if (tcbuf[0] == '#') 40512031Slayer { 40612031Slayer pos = ftell(tcfp); 40712031Slayer bp = tcbuf; 40812031Slayer continue; 40912031Slayer } 41012031Slayer 41112031Slayer tn->file_pos = pos; 41212031Slayer 41312031Slayer /* 41412031Slayer ** get full entry 41512031Slayer */ 41612031Slayer while (*(bp = lastchar(bp)) == '\\' && fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp)) 41712031Slayer ; 41812031Slayer /* 41912031Slayer ** save the names 42012031Slayer */ 42112031Slayer for (bp = tcbuf; *bp && *bp != ':'; bp++) 42212031Slayer ; 42312031Slayer *bp = '\0'; 42412031Slayer (void) strncpy(tn->name_buf, tcbuf, 42512031Slayer sizeof tcNames[0].name_buf); 42612031Slayer 42712031Slayer pos = ftell(tcfp); 42812031Slayer bp = tcbuf; 42912031Slayer tn++; 43012031Slayer } 43112031Slayer tn->file_pos = -1; 43212031Slayer 43312031Slayer /* 43412031Slayer ** Look for duplicate names 43512031Slayer */ 43612031Slayer if (dflag) 43712031Slayer check_dup(); 43812031Slayer if (nflag) 43912031Slayer exit(0); 44012031Slayer 44112031Slayer #ifdef DEBUG 44212031Slayer if (Dflag) 44312031Slayer { 44412031Slayer for (tn = tcNames; tn->file_pos >= 0; tn++) 44512031Slayer { 44612031Slayer printf("Entry #%d:\n\t%s\n\tfile_pos = %ld\n", 44712031Slayer tn - tcNames, tn->name_buf, tn->file_pos); 44812031Slayer } 44912031Slayer exit(0); 45012031Slayer } 45112031Slayer #endif 45212031Slayer 45312031Slayer /* 45412031Slayer ** Order the list 45512031Slayer */ 45612044Slayer if (Sflag) 45712031Slayer qsort((char *)tcNames, tn - tcNames, 45812031Slayer sizeof (struct TcName), name_cmp); 45912031Slayer 46012031Slayer /* 46112031Slayer ** List termcap entry for each name in table 46212031Slayer */ 46312031Slayer for (tn = tcNames; tn->file_pos >= 0; tn++) 46412031Slayer { 46512031Slayer tc_loopc = 0; 46612031Slayer /*** working toward this ... 46712031Slayer (void) prnt_ent(tn); 46812031Slayer ***/ 46912031Slayer (void) fseek(tcfp, tn->file_pos, 0); 47012031Slayer bp = tcbuf; 47112031Slayer while (fgets(bp, (sizeof tcbuf) - (bp - tcbuf), tcfp) 47212031Slayer && *(bp = lastchar(bp)) == '\\') 47312031Slayer ; 47412031Slayer (void) prnt_ent(tcbuf); 47512031Slayer } 47612031Slayer } 47712031Slayer 47812031Slayer char * 47912031Slayer lastchar(b) 48012031Slayer char *b; 48112031Slayer { 48212031Slayer register char *p; 48312031Slayer 48412031Slayer p = b + strlen(b) - 1; 48512031Slayer while (*p == '\n' || *p == ' ') 48612031Slayer p--; 48712031Slayer return(p); 48812031Slayer } 48912031Slayer 49012031Slayer name_cmp(a, b) 49112031Slayer char *a, *b; 49212031Slayer { 49312031Slayer if (gflag) /* sort on generic names */ 49412031Slayer { 49512031Slayer a += 3; 49612031Slayer b += 3; 49712031Slayer while (*a && *b && *a != '|' && *a == *b) 49812031Slayer { 49912031Slayer a++; 50012031Slayer b++; 50112031Slayer } 50212031Slayer if (*a == '|' || *a == CNULL) 50312031Slayer return((*b == '|' || *b == CNULL)? 0:-1); 50412031Slayer if (*b == '|' || *b == CNULL) 50512031Slayer return(1); 50612031Slayer return(*a - *b); 50712031Slayer } 50812031Slayer return(strncmp(a, b, 2)); 50912031Slayer } 51012031Slayer 51112031Slayer prnt_ent(buf) 51212031Slayer register char *buf; 51312031Slayer { 51412031Slayer register char *name; 51512446Slayer char *getdesc(); 51612031Slayer char *caps[256]; 51712031Slayer register char **cp; 51812031Slayer register char **tp; 51912031Slayer char tname[3]; 52012031Slayer 52112031Slayer cp = caps; 52212031Slayer name = buf; 52312031Slayer tname[3] = '\0'; 52412031Slayer 52512031Slayer while (*buf) 52612031Slayer { 52712031Slayer switch (*buf) 52812031Slayer { 52912031Slayer case ':': 53012031Slayer *buf++ = '\0'; 53112031Slayer while (*buf && !isalnum(*buf)) 53212031Slayer buf++; 53312031Slayer if (*buf) 53412031Slayer { 53512031Slayer /* 53612031Slayer * ignore duplicate cap entries 53712031Slayer */ 53812031Slayer for (tp = caps; tp < cp; tp++) 53912031Slayer if (strncmp(buf, *tp, 2) == 0) 54012031Slayer goto skip; 54112031Slayer *cp++ = buf; 54212031Slayer skip: 54312031Slayer /* 54412031Slayer * does user want tc= expanded? 54512031Slayer */ 54612031Slayer if (xflag && strncmp(buf, "tc=", 3) == 0) 54712031Slayer { 54812031Slayer /* 54912031Slayer * find end of tc= 55012031Slayer */ 55112031Slayer while (*buf != ':') 55212031Slayer buf++; 55312031Slayer *buf = '\0'; 55412031Slayer /* 55512031Slayer * save term name 55612031Slayer */ 55712031Slayer tname[0] = name[0]; 55812031Slayer tname[1] = name[1]; 55912031Slayer printf("%s: expanding %s\n", 56012031Slayer tname, cp[-1]); 56112031Slayer /* 56212031Slayer * let tgetent do the work 56312031Slayer */ 56412031Slayer tgetent(tcbuf, tname); 56512031Slayer prnt_ent(tcbuf); 56612031Slayer return; 56712031Slayer } 56812031Slayer } 56912031Slayer continue; 57012031Slayer 57112031Slayer case '|': 57212031Slayer *buf++ = ','; 57312031Slayer continue; 57412031Slayer 57512031Slayer default: 57612031Slayer buf++; 57712031Slayer } 57812031Slayer } 57912031Slayer *cp = CNULL; /* was (char *)0 */ 58012031Slayer 58112044Slayer if (Sflag) 58212031Slayer qsort((char *) caps, cp - caps, sizeof (char *), ent_cmp); 58312031Slayer 58412031Slayer printf("%s\n", name); 58512031Slayer for (cp = caps; *cp; cp++) 58613250Slayer if (Uflag) { 58713250Slayer if (unknowncap(*cp)) { 58813250Slayer printf("%3.3s\n", *cp); 58913250Slayer } 59013250Slayer } else if (sflag) { 59112446Slayer printf("%-45s %s\n", getdesc(*cp), *cp); 59213250Slayer } else { 59312446Slayer printf("%2.2s %-45s %s\n", name, getdesc(*cp), *cp); 59412446Slayer } 59512031Slayer (void) putchar('\n'); 59612031Slayer } 59712031Slayer 59812031Slayer prnt_raw(buf) 59912031Slayer char *buf; 60012031Slayer { 60112031Slayer register char *b; 60212031Slayer register int len; 60312031Slayer register int n; 60412031Slayer char *index(); 60512031Slayer 60612031Slayer len = 0; 60712031Slayer b = buf; 60812031Slayer while (*b) 60912031Slayer { 61012031Slayer if ((n = index(b, ':') - b + 1) <= 0) 61112031Slayer n = strlen(b); 61212031Slayer if (len == 0) /* first part */ 61312031Slayer { 61412031Slayer printf("%.*s\\\n\t:", n, b); 61512031Slayer len = 9 - n; 61612031Slayer } 61712031Slayer else 61812031Slayer { 61912031Slayer if ((len + n) >= 75) 62012031Slayer { 62112031Slayer printf("\\\n\t:"); 62212031Slayer len = 9; 62312031Slayer } 62412031Slayer printf("%.*s", n, b); 62512031Slayer } 62612031Slayer len += n; 62712031Slayer b += n; 62812031Slayer while (*b && index(" \t:\n", *b)) 62912031Slayer b++; 63012031Slayer } 63112031Slayer if (b[-1] != ':') 63212031Slayer (void) putchar(':'); 63312031Slayer (void) putchar('\n'); 63412031Slayer } 63512031Slayer 63612031Slayer ent_cmp(a, b) 63712031Slayer char **a, **b; 63812031Slayer { 63912031Slayer return(strncmp(*a, *b, 2)); 64012031Slayer } 64112031Slayer 64212031Slayer check_dup() 64312031Slayer { 64412031Slayer /* 64512031Slayer ** Look for duplicated names 64612031Slayer */ 64712031Slayer register char *p; 64812031Slayer register char *q; 64912031Slayer register struct TcName *tn; 65012031Slayer register struct TcName *tm; 65112031Slayer 65212031Slayer tn = tcNames; 65312031Slayer while (tn->file_pos >= 0) 65412031Slayer { 65512031Slayer p = q = tn->name_buf; 65612031Slayer while (*q) 65712031Slayer { 65812031Slayer while (*p && *p != '|') 65912031Slayer p++; 66012031Slayer if (p != q && (tm = find_name(q, tn + 1, p - q))) 66112031Slayer { 66212031Slayer fputs("Duplicate name: ", stdout); 66312031Slayer while (q != p) 66412031Slayer (void) putchar(*q++); 66512031Slayer (void) putchar('\n'); 66612031Slayer puts(tn->name_buf); 66712031Slayer puts(tm->name_buf); 66812031Slayer puts("---\n"); 66912031Slayer } 67012031Slayer if (*p == '|') 67112031Slayer p++; 67212031Slayer q = p; 67312031Slayer } 67412031Slayer tn++; 67512031Slayer } 67612031Slayer } 67712031Slayer 67812031Slayer struct TcName * 67912031Slayer find_name(name, tn, len) 68012031Slayer register char *name; 68112031Slayer register struct TcName *tn; 68212031Slayer register int len; 68312031Slayer { 68412031Slayer /* 68512031Slayer ** find name of length len in tcname structure buffers. 68612031Slayer */ 68712031Slayer register char *p; 68812031Slayer register char *buf; 68912031Slayer register int n; 69012031Slayer 69112031Slayer while (tn->file_pos >= 0) 69212031Slayer { 69312031Slayer buf = tn->name_buf; 69412031Slayer while (*buf) 69512031Slayer { 69612031Slayer p = name; 69712031Slayer n = len; 69812031Slayer if (*buf == '|') 69912031Slayer buf++; 70012031Slayer 70112031Slayer while (*buf && *buf != '|') 70212031Slayer { 70312031Slayer if (*p != *buf) 70412031Slayer { 70512031Slayer while (*buf && *buf != '|') 70612031Slayer buf++; 70712031Slayer break; 70812031Slayer } 70912031Slayer 71012031Slayer if (--n <= 0) 71112031Slayer { 71212031Slayer buf++; 71312031Slayer if (*buf == '|' || *buf == '\0') 71412031Slayer return(tn); 71512031Slayer while (*buf && *buf != '|') 71612031Slayer buf++; 71712031Slayer break; 71812031Slayer } 71912031Slayer buf++; 72012031Slayer p++; 72112031Slayer } 72212031Slayer } 72312031Slayer tn++; 72412031Slayer } 72512031Slayer return((struct TcName *)0); 72612031Slayer } 72712446Slayer 72812446Slayer char * 72912446Slayer getdesc(key) 73012446Slayer char *key; 73112446Slayer { 73212446Slayer register int i; 73312446Slayer 73412446Slayer for (i = 0; i <= NOCAPS; i++) 73512446Slayer if (strncmp(key, capList[i].cap, 2) == 0) 73612446Slayer return (capList[i].desc); 73712458Slayer return(""); 73812446Slayer } 73913250Slayer 74013250Slayer unknowncap(key) 74113250Slayer char *key; 74213250Slayer { 74313250Slayer register int i; 74413250Slayer 74513250Slayer for (i = 0; i <= NOCAPS; i++) 74613250Slayer if (strncmp(key, capList[i].cap, 2) == 0) 74713250Slayer return (0); 74813250Slayer return(1); 74913250Slayer } 750