📄 otic.c
字号:
/* Copyright (c) 1984 AT&T *//* All Rights Reserved *//* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T *//* The copyright notice above does not evidence any *//* actual or intended publication of such source code. */#ifndef lintstatic char sccsid[] = "@(#)otic.c 1.1 92/07/30 SMI"; /* from S5R3 1.6 */#endif#ifdef pdp11 /* Has to be this small to fit, even split I/D, with several use='s */# define CAPSIZ 2048#else# define CAPSIZ 8192 /* 4096 */#endif#define MAXHOP 32 /* max number of use= indirections */#define COMMENT '#'#define CAPCOMMENT '.'#define SEPARATE ',' /* Separates the capabilities. */#define NAMESEPARATOR '|' /* Separates the names in the list. */#define NUMBER '#'#define STRING '='#define CANCEL '@'#include <stdio.h>#include <ctype.h>#include <sys/types.h>#include <sys/stat.h>#include <unctrl.h>#include "uparm.h"#ifndef E_TERMINFO#define E_TERMINFO "terminfo.src"#endif#ifndef termpath#ifdef S5EMUL#define termpath(name) "/usr/5lib/terminfo/name"#else#define termpath(name) "/usr/lib/terminfo/name"#endif#endif/* * L_ctermid is only defined on USG. * We use it here since we don't include curses.h. */#if defined(L_ctermid) && !defined(sun)#define index strchr#endif/* * compile: program to compile a source terminfo file into object files */static char *tbuf;static int hopcount; /* detect infinite loops in terminfo, init 0 */static long starttime;static int verbose;static char *progname;static char *filename;static int linenumber;static char *terminfo;char *tskip();char *tgetstr();char *tdecode();extern char *boolnames[], *numnames[], *strnames[];extern char *boolcodes[], *numcodes[], *strcodes[];extern char *malloc();extern char *getenv();extern char *index();main(argc, argv)char **argv;{ int i; progname = argv[0]; initcheck(); time(&starttime); while (argc > 1 && argv[1][0] == '-') { switch(argv[1][1]) { case 'v': if (argv[1][2]) verbose = argv[1][2] - '0'; else verbose++; break; default: (void) fprintf(stderr, "Usage: %s [-v] [files...]\n", progname); exit(1); } argc--; argv++; } terminfo = getenv("TERMINFO"); if (argc == 1) compfile(stdin, "stdin"); else for (i=1; i<argc; i++) compfile(fopen(argv[i], "r"), argv[i]); return 0;}/* * Compile a file. This is very similar to the * code in tgetstr but it passes through the whole file. */compfile(tf, fname) FILE *tf; char *fname;{ register char *cp; char bp[CAPSIZ]; char ibuf[CAPSIZ]; if (tf == NULL) { perror(fname); return; } ibuf[0] = 0; linenumber = 0; filename = fname; for (;;) { tbuf = bp; strcpy(bp, ibuf); hopcount = 0; for (;;) { if (fgets(ibuf, sizeof ibuf, tf) == NULL) { if (ferror(tf)) { perror(fname); fclose(tf); return; } fclose(tf); checknames(tbuf); if (*bp && tnchkuse(fname)) store(bp); return; } linenumber++; /* comment or blank line */ if (ibuf[0] == COMMENT || ibuf[0] == '\n') continue; cp = &ibuf[strlen(ibuf)-3]; /* Allow and ignore old style backslashes */ if (*cp == SEPARATE && cp[1] == '\\') cp[1] = 0; cp[2] = 0; /* get rid of newline */ /* lines with leading white space are continuation */ if (!isspace(ibuf[0]) && *bp) break; if (strlen(bp) + strlen(ibuf) >= CAPSIZ) (void) fprintf(stderr, "%s: Terminfo entry too long:\n%s", progname, bp); else { cp = ibuf; while (isspace(*cp)) cp++; strcat(bp, cp); } } /* * We have it, now do something with it. */ checknames(tbuf); if (tnchkuse(fname)) store(bp); }}/* * Code to check names in the buffer against list of valid names. * This is done against the unexpanded form (use= entries are still there) * to avoid redundant messages. */static short *sortedbools, *sortednums, *sortedstrs;static int numbools, numnums, numstrs;static intcmpbools(left, right)short *left, *right;{ return strcmp(boolnames[*left], boolnames[*right]);}static intcmpnums(left, right)short *left, *right;{ return strcmp(numnames[*left], numnames[*right]);}static intcmpstrs(left, right)short *left, *right;{ return strcmp(strnames[*left], strnames[*right]);}initcheck(){ register int i, j; register char **pp; for (i = 0, pp = boolnames; *pp; pp++, i++) ; numbools = i; sortedbools = (short *) malloc(i * sizeof(short)); if (!sortedbools) { (void) fprintf (stderr, "%s: malloc failed!\n", progname); exit(1); } for (j = 0; j < i; j++) sortedbools[j] = j; qsort(sortedbools, numbools, sizeof(short), cmpbools); for (i = 0, pp = numnames; *pp; pp++, i++) ; numnums = i; sortednums = (short *) malloc(i * sizeof(short)); if (!sortednums) { (void) fprintf (stderr, "%s: malloc failed!\n", progname); exit(1); } for (j = 0; j < i; j++) sortednums[j] = j; qsort(sortednums, numnums, sizeof(short), cmpnums); for (i = 0, pp = strnames; *pp; pp++, i++) ; numstrs = i; sortedstrs = (short *) malloc(i * sizeof(short)); if (!sortedstrs) { (void) fprintf (stderr, "%s: malloc failed!\n", progname); exit(1); } for (j = 0; j < i; j++) sortedstrs[j] = j; qsort(sortedstrs, numstrs, sizeof(short), cmpstrs);}binsearch(name, sortedtable, size, table)char *name;short sortedtable[];int size;int table;{ int low, mid, high, cmp; char *cmpname; low = 0; high = size - 1; while (low <= high) { mid = (low + high) / 2; switch (table) { case 1: cmpname = boolnames[sortedtable[mid]]; break; case 2: cmpname = numnames[sortedtable[mid]]; break; case 3: cmpname = strnames[sortedtable[mid]]; break; } cmp = strcmp(cmpname, name); if (cmp == 0) return 1; else if (cmp < 0) low = mid + 1; else high = mid - 1; } return 0;}static intlookfor(name, table)char *name;int table;{ switch(table) { case 1: return binsearch(name, sortedbools, numbools, table); case 2: return binsearch(name, sortednums, numnums, table); case 3: return binsearch(name, sortedstrs, numstrs, table); } return -1;}staticlookup(buf, termname)register char *buf;char *termname;{#define NAMESIZE 10 char name[NAMESIZE]; char *nptr = name; if (*buf == CAPCOMMENT) return 1; /* a name is followed by a SEPARATE, @, # or =. */ while (*buf && *buf != SEPARATE && *buf != CANCEL && *buf != STRING && *buf != NUMBER && !isspace(*buf) && nptr < &name[NAMESIZE-1]) *nptr++ = *buf++; *nptr = '\0'; switch(*buf) { case STRING: /* string capability */ if (!lookfor(name, 3) && strcmp(name, "use") != 0) (void) fprintf (stderr, "%s: file %s, line %d, terminal '%s' has unknown string capability '%s'.\n", progname, filename, linenumber, termname, name); break; case NUMBER: /* numeric capability */ if (!lookfor(name, 2)) (void) fprintf (stderr, "%s: file %s, line %d, terminal '%s' has unknown numeric capability '%s'.\n", progname, filename, linenumber, termname, name); break; case SEPARATE: /* boolean capability */ case ' ': case '\t': if (!lookfor(name, 1)) (void) fprintf (stderr, "%s: file %s, line %d, terminal '%s' has unknown boolean capability '%s'.\n", progname, filename, linenumber, termname, name); break; case CANCEL: /* may be boolean, number or string */ if (!lookfor(name, 1) && !lookfor(name, 2) && !lookfor(name, 3)) (void) fprintf (stderr, "%s: file %s, line %d, terminal '%s' has unknown capability '%s'.\n", progname, filename, linenumber, termname, name); break; default: (void) fprintf (stderr, "%s: file %s, line %d, terminal '%s' has capability name which is too long: '%s...'.\n", progname, filename, linenumber, termname, name); }}staticchecknames(buf)register char *buf;{ char *bufptr = buf; char termname[20]; char *termptr = termname; while (*bufptr && *bufptr != SEPARATE && *bufptr != NAMESEPARATOR && termptr < &termname[20]) *termptr++ = *bufptr++; if (termptr < &termname[20]) *termptr = '\0'; else termname[19] = '\0'; for (buf = tskip(buf); *buf; buf = tskip(buf)) lookup(buf, termname);}/* * Get an entry for terminal name in buffer bp, * from the terminfo file. Parse is very rudimentary; * we just notice escaped newlines. */tgetent(bp, name, fname) char *bp, *name, *fname;{ register char *cp; char ibuf[CAPSIZ]; FILE *tf; ibuf[0] = 0; tf = fopen(fname, "r"); if (tf == NULL) return (-1); tbuf = bp; for (;;) { strcpy(bp, ibuf); for (;;) { if (fgets(ibuf, sizeof ibuf, tf) == NULL) { if (ferror(tf)) { perror(fname); fclose(tf); return (-1); } fclose(tf); if (tnamatch(name)) return(tnchkuse(fname)); return 0; } if (ibuf[0] == COMMENT || ibuf[0] == '\n') /* comment */ continue; cp = &ibuf[strlen(ibuf)-3]; /* Allow and ignore old style backslashes */ if (*cp == SEPARATE && cp[1] == '\\') cp[1] = 0; cp[2] = 0; /* get rid of newline */ /* lines with leading white space are continuation */ if (!isspace(ibuf[0]) && *bp) break; if (strlen(bp) + strlen(ibuf) >= CAPSIZ) (void) fprintf(stderr, "%s: file %s, line %d: Terminfo entry too long:\n%s", progname, filename, linenumber, bp); else { cp = ibuf; while (isspace(*cp)) cp++; strcat(bp, cp); } } /* * The real work for the match. */ if (tnamatch(name)) { fclose(tf); return(tnchkuse(fname)); } }}/* * tnchkuse: look for use=xxx. When found, recursively * find xxx and append that entry (minus the names) * to take the place of the use=xxx entry. This allows terminfo * entries to say "like an HP2621 but doesn't turn on the labels". * Note that this works because of the left to right scan. * Multiple use= entries are allowed. */tnchkuse(fname)char *fname;{ register char *p, *q; char tcname[128 /* 16 */]; /* name of similar terminal */ char tcbuf[CAPSIZ]; char restbuf[CAPSIZ]; char *holdtbuf = tbuf; char *beg_use, *beg_next; p = tbuf; if (++hopcount > MAXHOP) { (void) fprintf(stderr, "%s: file %s, line %d: Infinite use= loop '%s'\n", progname, filename, linenumber, tbuf); return (0); } for (;;) { p = index(p, 'u'); if (p == NULL) { tbuf = holdtbuf; return 1; } beg_use = p; if (*++p != 's' || *++p != 'e' || *++p != '=') continue; strncpy(tcname, ++p, sizeof tcname); q = index(tcname, SEPARATE); if (q) *q = 0; /* try local file ... */ if (tgetent(tcbuf, tcname, fname) != 1) { /* ... and master */ if (tgetent(tcbuf, tcname, E_TERMINFO) != 1) { printf("Cannot find term %s\n", tcname); return(0); } } /* Find the end of the use= spec */ for(beg_next=beg_use; *beg_next && *beg_next!=SEPARATE; beg_next++) ; beg_next++; while (isspace(*beg_next++))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -