|
|
1.1 ! root 1: /* @(#) tic.c: 1.1 10/15/83 (1.15 2/23/83) */ ! 2: ! 3: #ifdef pdp11 ! 4: /* Has to be this small to fit, even split I/D, with several use='s */ ! 5: # define CAPSIZ 2048 ! 6: #else ! 7: # define CAPSIZ 4096 ! 8: #endif ! 9: ! 10: #define MAXHOP 32 /* max number of use= indirections */ ! 11: ! 12: #define COMMENT '#' ! 13: #define SEPARATE ',' ! 14: #define NUMBER '#' ! 15: #define STRING '=' ! 16: #define CANCEL '@' ! 17: ! 18: #include <stdio.h> ! 19: #include <ctype.h> ! 20: #include <sys/types.h> ! 21: #include <sys/stat.h> ! 22: ! 23: #include "../local/uparm.h" ! 24: #ifndef E_TERMINFO ! 25: #define E_TERMINFO "terminfo.src" ! 26: #endif ! 27: ! 28: #ifndef termpath ! 29: #define termpath(name) "/usr/lib/terminfo/name" ! 30: #endif ! 31: ! 32: /* ! 33: * L_ctermid is only defined on USG. ! 34: * We use it here since we don't include curses.h. ! 35: */ ! 36: #ifdef L_ctermid ! 37: #define index strchr ! 38: #endif ! 39: ! 40: /* ! 41: * compile: program to compile a source terminfo file into object files ! 42: */ ! 43: ! 44: static char *tbuf; ! 45: static int hopcount; /* detect infinite loops in terminfo, init 0 */ ! 46: long starttime; ! 47: int verbose; ! 48: char *terminfo; ! 49: char *tskip(); ! 50: char *tgetstr(); ! 51: char *tdecode(); ! 52: char *getenv(); ! 53: ! 54: char *sourcefile = E_TERMINFO; ! 55: ! 56: main(argc, argv) ! 57: char **argv; ! 58: { ! 59: int i; ! 60: ! 61: time(&starttime); ! 62: while (argc > 1 && argv[1][0] == '-') { ! 63: switch(argv[1][1]) { ! 64: case 'v': ! 65: if (argv[1][2]) ! 66: verbose = argv[1][2] - '0'; ! 67: else ! 68: verbose++; ! 69: break; ! 70: default: ! 71: fprintf(stderr, "Usage: compile [-v] [files...]\n"); ! 72: exit(1); ! 73: } ! 74: argc--; argv++; ! 75: } ! 76: ! 77: terminfo = getenv("TERMINFO"); ! 78: ! 79: if (argc == 1) { ! 80: compfile(stdin, "stdin"); ! 81: } ! 82: else for (i=1; i<argc; i++) { ! 83: compfile(fopen(argv[i], "r"), argv[i]); ! 84: } ! 85: } ! 86: ! 87: /* ! 88: * Compile a file. This is very similar to the ! 89: * code in tgetstr but it passes through the whole file. ! 90: */ ! 91: compfile(tf, fname) ! 92: FILE *tf; ! 93: char *fname; ! 94: { ! 95: register char *cp; ! 96: register int c; ! 97: register int i = 0, cnt = 0; ! 98: char bp[CAPSIZ]; ! 99: char ibuf[CAPSIZ]; ! 100: char *cp2; ! 101: ! 102: if (tf == NULL) { ! 103: perror(fname); ! 104: return (-1); ! 105: } ! 106: ibuf[0] = 0; ! 107: for (;;) { ! 108: tbuf = bp; ! 109: strcpy(bp, ibuf); ! 110: for (;;) { ! 111: if (fgets(ibuf, sizeof ibuf, tf) == NULL) { ! 112: fclose(tf); ! 113: if (tnchkuse(fname)) ! 114: store(bp); ! 115: return 0; ! 116: } ! 117: /* comment or blank line */ ! 118: if (ibuf[0] == COMMENT || ibuf[0] == '\n') ! 119: continue; ! 120: cp = &ibuf[strlen(ibuf)-3]; ! 121: /* Allow and ignore old style backslashes */ ! 122: if (*cp == SEPARATE && cp[1] == '\\') ! 123: cp[1] = 0; ! 124: cp[2] = 0; /* get rid of newline */ ! 125: /* lines with leading white space are continuation */ ! 126: if (!isspace(ibuf[0]) && *bp) ! 127: break; ! 128: if (strlen(bp) + strlen(ibuf) >= CAPSIZ) { ! 129: fprintf(stdout, "Terminfo entry too long:\n"); ! 130: fprintf(stdout, "%s", bp); ! 131: } ! 132: else { ! 133: cp = ibuf; ! 134: while (isspace(*cp)) ! 135: cp++; ! 136: strcat(bp, cp); ! 137: } ! 138: } ! 139: ! 140: /* ! 141: * We have it, now do something with it. ! 142: */ ! 143: if (tnchkuse(fname)) ! 144: store(bp); ! 145: } ! 146: } ! 147: ! 148: /* ! 149: * Get an entry for terminal name in buffer bp, ! 150: * from the terminfo file. Parse is very rudimentary; ! 151: * we just notice escaped newlines. ! 152: */ ! 153: tgetent(bp, name, fname) ! 154: char *bp, *name, *fname; ! 155: { ! 156: register char *cp; ! 157: register int c; ! 158: register int i = 0, cnt = 0; ! 159: char ibuf[CAPSIZ]; ! 160: char *cp2; ! 161: FILE *tf; ! 162: ! 163: ibuf[0] = 0; ! 164: tf = fopen(fname, "r"); ! 165: if (tf == NULL) ! 166: return (-1); ! 167: tbuf = bp; ! 168: for (;;) { ! 169: strcpy(bp, ibuf); ! 170: for (;;) { ! 171: if (fgets(ibuf, sizeof ibuf, tf) == NULL) { ! 172: fclose(tf); ! 173: if (tnamatch(name)) ! 174: return(tnchkuse(fname)); ! 175: return 0; ! 176: } ! 177: if (ibuf[0] == COMMENT) /* comment */ ! 178: continue; ! 179: cp = &ibuf[strlen(ibuf)-3]; ! 180: /* Allow and ignore old style backslashes */ ! 181: if (*cp == SEPARATE && cp[1] == '\\') ! 182: cp[1] = 0; ! 183: cp[2] = 0; /* get rid of newline */ ! 184: /* lines with leading white space are continuation */ ! 185: if (!isspace(ibuf[0]) && *bp) ! 186: break; ! 187: if (strlen(bp) + strlen(ibuf) >= CAPSIZ) { ! 188: fprintf(stdout, "Terminfo entry too long:\n"); ! 189: fprintf(stdout, "%s", bp); ! 190: } ! 191: else { ! 192: cp = ibuf; ! 193: while (isspace(*cp)) ! 194: cp++; ! 195: strcat(bp, cp); ! 196: } ! 197: } ! 198: ! 199: /* ! 200: * The real work for the match. ! 201: */ ! 202: if (tnamatch(name)) { ! 203: fclose(tf); ! 204: return(tnchkuse(fname)); ! 205: } ! 206: } ! 207: } ! 208: ! 209: /* ! 210: * tnchkuse: check the last entry, see if it's use=xxx. If so, ! 211: * recursively find xxx and append that entry (minus the names) ! 212: * to take the place of the use=xxx entry. This allows terminfo ! 213: * entries to say "like an HP2621 but doesn't turn on the labels". ! 214: * Note that this works because of the left to right scan. ! 215: */ ! 216: tnchkuse(fname) ! 217: char *fname; ! 218: { ! 219: register char *p, *q; ! 220: char tcname[16]; /* name of similar terminal */ ! 221: char tcbuf[CAPSIZ]; ! 222: char restbuf[CAPSIZ]; ! 223: char *holdtbuf = tbuf; ! 224: char *beg_use, *beg_next; ! 225: char *strchr(); ! 226: int l; ! 227: ! 228: p = tbuf; ! 229: if (++hopcount > MAXHOP) { ! 230: fprintf(stdout, "Infinite use= loop '%s'\n", tbuf); ! 231: return (0); ! 232: } ! 233: for (;;) { ! 234: p = strchr(p, 'u'); ! 235: if (p == NULL) { ! 236: tbuf = holdtbuf; ! 237: return 1; ! 238: } ! 239: beg_use = p; ! 240: if (*++p != 's' || *++p != 'e' || *++p != '=') ! 241: continue; ! 242: strncpy(tcname, ++p, sizeof tcname); ! 243: q = strchr(tcname, SEPARATE); ! 244: if (q) ! 245: *q = 0; ! 246: /* try local file ... */ ! 247: if (tgetent(tcbuf, tcname, fname) != 1) { ! 248: /* ... and master */ ! 249: if (tgetent(tcbuf, tcname, E_TERMINFO) != 1) { ! 250: printf("Cannot find term %s\n", tcname); ! 251: return(0); ! 252: } ! 253: } ! 254: ! 255: /* Find the end of the use= spec */ ! 256: for(beg_next=beg_use; ! 257: *beg_next && *beg_next!=SEPARATE; ! 258: beg_next++) ! 259: ; ! 260: beg_next++; ! 261: while (isspace(*beg_next++)) ! 262: ; ! 263: beg_next--; ! 264: ! 265: /* Now shuffle string around. */ ! 266: strcpy(restbuf, beg_next); ! 267: p = strchr(tcbuf, SEPARATE); ! 268: if (p == NULL) ! 269: p = tcbuf; ! 270: else ! 271: p++; ! 272: strcpy(beg_use, p); ! 273: p = strchr(beg_use, '\0'); ! 274: strcpy(p, restbuf); ! 275: } ! 276: } ! 277: ! 278: /* ! 279: * Tnamatch deals with name matching. The first field of the terminfo ! 280: * entry is a sequence of names separated by |'s, so we compare ! 281: * against each such name. The normal : terminator after the last ! 282: * name (before the first field) stops us. ! 283: */ ! 284: tnamatch(np) ! 285: char *np; ! 286: { ! 287: register char *Np, *Bp; ! 288: ! 289: /* printf("tnamatch, np '%s', tbuf '%s'\n", np, tbuf); */ ! 290: Bp = tbuf; ! 291: if (*Bp == COMMENT) ! 292: return(0); ! 293: for (;;) { ! 294: for (Np = np; *Np && *Bp == *Np; Bp++, Np++) ! 295: ; ! 296: if (*Np == 0 && (*Bp == '|' || *Bp == SEPARATE || *Bp == 0)) ! 297: return (1); ! 298: while (*Bp && *Bp != SEPARATE && *Bp != '|') ! 299: Bp++; ! 300: if (*Bp == 0 || *Bp == SEPARATE) ! 301: return (0); ! 302: Bp++; ! 303: } ! 304: } ! 305: ! 306: /* ! 307: * Skip to the next SEPARATE delimited field. ! 308: */ ! 309: static char * ! 310: tskip(bp) ! 311: register char *bp; ! 312: { ! 313: ! 314: while (*bp && *bp != SEPARATE) ! 315: bp++; ! 316: if (*bp == 0) ! 317: return bp; ! 318: bp++; ! 319: while (isspace(*bp) || *bp == SEPARATE) ! 320: bp++; ! 321: return (bp); ! 322: } ! 323: ! 324: /* ! 325: * Return the (numeric) option id. ! 326: * Numeric options look like ! 327: * li#80 ! 328: * i.e. the option string is separated from the numeric value by ! 329: * a # character. If the option is not found we return -1. ! 330: * Note that we handle octal numbers beginning with 0. ! 331: */ ! 332: tgetnum(id) ! 333: char *id; ! 334: { ! 335: register int i, base; ! 336: register char *bp = tbuf; ! 337: int idl = strlen(id); ! 338: int sign = 1; ! 339: ! 340: for (;;) { ! 341: bp = tskip(bp); ! 342: if (*bp == 0) ! 343: return (-1); ! 344: if (strncmp(id, bp, idl)) ! 345: continue; ! 346: bp += idl; ! 347: if (*bp == CANCEL) ! 348: return(-1); ! 349: if (*bp != NUMBER && *bp != STRING) ! 350: continue; ! 351: bp++; ! 352: if (*bp == '-') { ! 353: sign = -1; ! 354: bp++; ! 355: } ! 356: base = 10; ! 357: if (*bp == '0') ! 358: base = 8; ! 359: i = 0; ! 360: while (isdigit(*bp)) ! 361: i *= base, i += *bp++ - '0'; ! 362: i *= sign; ! 363: return (i); ! 364: } ! 365: } ! 366: ! 367: /* ! 368: * Handle a flag option. ! 369: * Flag options are given "naked", i.e. followed by a : or the end ! 370: * of the buffer. Return 1 if we find the option, or 0 if it is ! 371: * not given. ! 372: */ ! 373: tgetflag(id) ! 374: char *id; ! 375: { ! 376: register char *bp = tbuf; ! 377: int idl = strlen(id); ! 378: ! 379: for (;;) { ! 380: bp = tskip(bp); ! 381: if (!*bp) ! 382: return (0); ! 383: if (strncmp(bp, id, idl) == 0) { ! 384: bp += idl; ! 385: if (!*bp || *bp == SEPARATE) ! 386: return (1); ! 387: else if (*bp == CANCEL) ! 388: return(0); ! 389: } ! 390: } ! 391: } ! 392: ! 393: /* ! 394: * Get a string valued option. ! 395: * These are given as ! 396: * cl=^Z ! 397: * Much decoding is done on the strings, and the strings are ! 398: * placed in area, which is a ref parameter which is updated. ! 399: * No checking on area overflow. ! 400: */ ! 401: char * ! 402: tgetstr(id, area) ! 403: char *id, **area; ! 404: { ! 405: register char *bp = tbuf; ! 406: int idl = strlen(id); ! 407: ! 408: for (;;) { ! 409: bp = tskip(bp); ! 410: if (!*bp) ! 411: return (0); ! 412: if (strncmp(id, bp, idl)) ! 413: continue; ! 414: bp += idl; ! 415: if (*bp == CANCEL) ! 416: return(0); ! 417: if (*bp != STRING) ! 418: continue; ! 419: bp++; ! 420: return (tdecode(bp, area)); ! 421: } ! 422: } ! 423: ! 424: /* ! 425: * Tdecode does the grung work to decode the ! 426: * string capability escapes. ! 427: */ ! 428: static char * ! 429: tdecode(str, area) ! 430: register char *str; ! 431: char **area; ! 432: { ! 433: register char *cp; ! 434: register int c; ! 435: register char *dp; ! 436: int i; ! 437: ! 438: cp = *area; ! 439: while ((c = *str++) && c != SEPARATE) { ! 440: switch (c) { ! 441: ! 442: case '^': ! 443: c = *str++ & 037; ! 444: break; ! 445: ! 446: case '\\': ! 447: /* ! 448: * \x escapes understood: ! 449: * \e escape ! 450: * \E escape ! 451: * \^ ^ ! 452: * \\ \ ! 453: * \, , ! 454: * \: : ! 455: * \l linefeed ! 456: * \n newline (=linefeed) ! 457: * \r return ! 458: * \t tab ! 459: * \b backspace ! 460: * \f formfeed ! 461: * \s space ! 462: * \0 null ! 463: * \### octal ### ! 464: */ ! 465: dp = "e\033E\033^^\\\\,,::l\012n\nr\rt\tb\bf\fs "; ! 466: c = *str++; ! 467: nextc: ! 468: if (*dp++ == c) { ! 469: c = *dp++; ! 470: break; ! 471: } ! 472: dp++; ! 473: if (*dp) ! 474: goto nextc; ! 475: if (isdigit(c)) { ! 476: c -= '0', i = 2; ! 477: do { ! 478: if (!isdigit(*str)) ! 479: break; ! 480: c <<= 3; ! 481: c |= *str++ - '0'; ! 482: } while (--i); ! 483: if (c == 0) ! 484: c = 0200; /* don't term. str. */ ! 485: } ! 486: break; ! 487: } ! 488: *cp++ = c; ! 489: } ! 490: *cp++ = 0; ! 491: str = *area; ! 492: *area = cp; ! 493: return (str); ! 494: } ! 495: ! 496: extern char *boolnames[], *numnames[], *strnames[]; ! 497: extern char *boolcodes[], *numcodes[], *strcodes[]; ! 498: ! 499: char *malloc(); ! 500: char *tgetstr(); ! 501: ! 502: #define TIMAGNUM 0432 ! 503: ! 504: store(cap) ! 505: char *cap; ! 506: { ! 507: register char *cp; ! 508: register int i; ! 509: register char **pp, **np; ! 510: char tcpbuf[1024]; ! 511: char *tcp = tcpbuf; ! 512: char *tname = cap; ! 513: char *tnp; ! 514: char tnbuf[256], names[256]; ! 515: char fnbuf[64], lnbuf[64]; ! 516: char strtab[4096]; ! 517: register char *strtabptr; ! 518: FILE *fd; ! 519: int sname, sbool; ! 520: ! 521: while (*cap != SEPARATE) /* skip over names */ ! 522: cap++; ! 523: *cap = 0; ! 524: strcpy(tnbuf, tname); ! 525: strcpy(names, tname); ! 526: *cap = SEPARATE; ! 527: ! 528: for (tnp=tnbuf; *tnp && *tnp != '|' && *tnp != SEPARATE; tnp++) ! 529: ; ! 530: if (*tnp) ! 531: *tnp++ = 0; ! 532: if (terminfo) { ! 533: strcpy(fnbuf, terminfo); ! 534: strcat(fnbuf, "/"); ! 535: } else { ! 536: strcpy(fnbuf, termpath(/)); ! 537: } ! 538: strcat(fnbuf, tnbuf); ! 539: checkon(fnbuf); ! 540: if (verbose) ! 541: printf("create '%s'\n", fnbuf); ! 542: fd = fopen(fnbuf, "w"); ! 543: if (fd == NULL) { ! 544: perror(fnbuf); ! 545: return; ! 546: } ! 547: ! 548: putsh(TIMAGNUM, fd); ! 549: sname = strlen(names)+1; ! 550: putsh(sname, fd); ! 551: sbool = listlen(boolcodes); ! 552: putsh(sbool, fd); ! 553: putsh(listlen(numcodes), fd); ! 554: putsh(listlen(strcodes), fd); ! 555: putsh(0, fd); /* length of string table */ ! 556: ! 557: /* Write out various terminal names to file, null terminated. */ ! 558: for (cp=names; *cp; cp++) ! 559: putc(*cp, fd); ! 560: putc(0, fd); ! 561: ! 562: /* Write out the booleans: flag */ ! 563: for (pp=boolnames, np=boolcodes; *np; pp++,np++) { ! 564: i = tgetflag(*pp); ! 565: putc(i, fd); ! 566: if (verbose > 2) ! 567: printf("bool cap %s code %s val %d\n", *pp, *np, i); ! 568: } ! 569: if ((sname + sbool) & 1) ! 570: putc(0, fd); ! 571: ! 572: /* Numbers: highbyte, lowbyte. 0377,0377 means -1 (missing) */ ! 573: for (pp=numnames, np=numcodes; *np; pp++,np++) { ! 574: i = tgetnum(*pp); ! 575: putsh(i, fd); ! 576: if (verbose > 1) ! 577: printf("num cap %s code %s val %d\n", *pp, *np, i); ! 578: } ! 579: ! 580: /* Strings: offset into string table. If cap is missing, -1 is used */ ! 581: strtabptr = strtab; ! 582: for (pp=strnames, np=strcodes; *np; pp++,np++) { ! 583: cp = tgetstr(*pp, &tcp); ! 584: if (verbose > 3) ! 585: if (cp) ! 586: printf("str %s code %s val %s\n", *pp, *np, cp); ! 587: else ! 588: printf("str %s code %s val NULL\n", *pp, *np); ! 589: if (cp) { ! 590: putsh(strtabptr-strtab, fd); ! 591: while (*strtabptr++ = *cp++) ! 592: ; ! 593: } else { ! 594: putsh(-1, fd); ! 595: } ! 596: } ! 597: fwrite(strtab, 1, strtabptr-strtab, fd); ! 598: fseek(fd, 10L, 0); /* Back to string table size in header */ ! 599: putsh(strtabptr-strtab, fd); ! 600: fclose(fd); ! 601: hopcount = 0; ! 602: ! 603: while (*tnp) { ! 604: i = 0; ! 605: for (tname=tnp; *tnp && *tnp != '|' && *tnp != SEPARATE; tnp++) ! 606: if (isspace(*tnp)) ! 607: i = 1; ! 608: if (*tnp) ! 609: *tnp++ = 0; ! 610: if (i) ! 611: continue; ! 612: if (terminfo) { ! 613: strcpy(lnbuf, terminfo); ! 614: strcat(lnbuf, "/"); ! 615: } else { ! 616: strcpy(lnbuf, termpath(/)); ! 617: } ! 618: strcat(lnbuf, tname); ! 619: checkon(lnbuf); ! 620: link(fnbuf, lnbuf); ! 621: if (verbose) ! 622: printf("link '%s' '%s'\n", fnbuf, lnbuf); ! 623: } ! 624: } ! 625: ! 626: /* ! 627: * Write a short out to the file in machine-independent format. ! 628: */ ! 629: putsh(val, fd) ! 630: register val; ! 631: FILE *fd; ! 632: { ! 633: if (val != -1) { ! 634: putc(val&0377, fd); ! 635: putc((val>>8)&0377, fd); ! 636: } else { ! 637: /* Write -1 as two 0377's. */ ! 638: putc(0377, fd); ! 639: putc(0377, fd); ! 640: } ! 641: } ! 642: ! 643: listlen(list) ! 644: register char **list; ! 645: { ! 646: register int rv = 0; ! 647: ! 648: while (*list) { ! 649: list++; ! 650: rv++; ! 651: } ! 652: return rv; ! 653: } ! 654: ! 655: /* ! 656: * Do various processing on a file name we are about to create. ! 657: * If it already exists, and it's older than we started, unlink it. ! 658: * Also insert a / after the 2nd char of the tail, and make sure ! 659: * that directory exists. ! 660: */ ! 661: checkon(fn) ! 662: char *fn; ! 663: { ! 664: struct stat stbuf; ! 665: char *fp, *cp; ! 666: char nbuf[64]; ! 667: char cmdbuf[64]; ! 668: ! 669: /* Find last / */ ! 670: for (cp=fn; *cp; cp++) ! 671: if (*cp == '/') ! 672: fp = cp; ! 673: if (cp-fp > 2) { ! 674: cp = fp+2; ! 675: strcpy(nbuf, fp+1); ! 676: *cp = 0; ! 677: if (stat(fn, &stbuf) < 0) { ! 678: sprintf(cmdbuf, "mkdir %s", fn); ! 679: if (verbose) ! 680: printf("%s\n", cmdbuf); ! 681: system(cmdbuf); ! 682: } ! 683: *cp++ = '/'; ! 684: strcpy(cp, nbuf); ! 685: } ! 686: else ! 687: printf("%s: terminal name too short\n", fp+1); ! 688: if (stat(fn, &stbuf) < 0) ! 689: return; ! 690: if (stbuf.st_mtime < starttime) { ! 691: if (verbose > 1) ! 692: printf("unlink %s\n", fn); ! 693: unlink(fn); ! 694: } ! 695: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.