|
|
1.1 ! root 1: /* Work-alike for termcap, plus extra features. ! 2: Copyright (C) 1985, 1986 Free Software Foundation, Inc. ! 3: ! 4: This program is free software; you can redistribute it and/or modify ! 5: it under the terms of the GNU General Public License as published by ! 6: the Free Software Foundation; either version 1, or (at your option) ! 7: any later version. ! 8: ! 9: This program is distributed in the hope that it will be useful, ! 10: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 12: GNU General Public License for more details. ! 13: ! 14: You should have received a copy of the GNU General Public License ! 15: along with this program; if not, write to the Free Software ! 16: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: ! 18: In other words, you are welcome to use, share and improve this program. ! 19: You are forbidden to forbid anyone else to use, share and improve ! 20: what you give them. Help stamp out software-hoarding! */ ! 21: ! 22: ! 23: ! 24: /* BUFSIZE is the initial size allocated for the buffer ! 25: for reading the termcap file. ! 26: It is not a limit. ! 27: Make it large normally for speed. ! 28: Make it variable when debugging, so can exercise ! 29: increasing the space dynamically. */ ! 30: ! 31: #ifdef emacs ! 32: #include "config.h" ! 33: #endif ! 34: ! 35: #ifndef BUFSIZE ! 36: #ifdef DEBUG ! 37: #define BUFSIZE bufsize ! 38: ! 39: int bufsize = 128; ! 40: #else ! 41: #define BUFSIZE 2048 ! 42: #endif ! 43: #endif ! 44: ! 45: #ifndef emacs ! 46: static ! 47: memory_out () ! 48: { ! 49: write (2, "Virtual memory exhausted\n", 25); ! 50: exit (1); ! 51: } ! 52: ! 53: static int ! 54: xmalloc (size) ! 55: int size; ! 56: { ! 57: register tem = malloc (size); ! 58: if (!tem) ! 59: memory_out (); ! 60: return tem; ! 61: } ! 62: ! 63: static int ! 64: xrealloc (ptr, size) ! 65: int ptr; ! 66: int size; ! 67: { ! 68: register tem = realloc (ptr, size); ! 69: if (!tem) ! 70: memory_out (); ! 71: return tem; ! 72: } ! 73: #endif /* not emacs */ ! 74: ! 75: /* Looking up capabilities in the entry already found */ ! 76: ! 77: /* The pointer to the data made by tgetent is left here ! 78: for tgetnum, tgetflag and tgetstr to find. */ ! 79: ! 80: static char *term_entry; ! 81: ! 82: static char *tgetst1 (); ! 83: ! 84: /* This is the main subroutine that is used to search ! 85: an entry for a particular capability */ ! 86: ! 87: static char * ! 88: find_capability (bp, cap) ! 89: register char *bp, *cap; ! 90: { ! 91: for (; *bp; bp++) ! 92: if (bp[0] == ':' ! 93: && bp[1] == cap[0] ! 94: && bp[2] == cap[1]) ! 95: return &bp[4]; ! 96: return 0; ! 97: } ! 98: ! 99: int ! 100: tgetnum (cap) ! 101: char *cap; ! 102: { ! 103: register char *ptr = find_capability (term_entry, cap); ! 104: if (!ptr || ptr[-1] != '#') ! 105: return -1; ! 106: return atoi (ptr); ! 107: } ! 108: ! 109: int ! 110: tgetflag (cap) ! 111: char *cap; ! 112: { ! 113: register char *ptr = find_capability (term_entry, cap); ! 114: return 0 != ptr && ptr[-1] == ':'; ! 115: } ! 116: ! 117: /* Look up a string-valued capability `cap'. ! 118: If `area' is nonzero, it points to a pointer to a block in which ! 119: to store the string. That pointer is advanced over the space used. ! 120: If `area' is zero, space is allocated with `malloc'. */ ! 121: ! 122: char * ! 123: tgetstr (cap, area) ! 124: char *cap; ! 125: char **area; ! 126: { ! 127: register char *ptr = find_capability (term_entry, cap); ! 128: if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~')) ! 129: return 0; ! 130: return tgetst1 (ptr, area); ! 131: } ! 132: ! 133: /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted, ! 134: gives meaning of character following \, or a space if no special meaning. ! 135: Eight characters per line within the string. */ ! 136: ! 137: static char esctab[] ! 138: = " \007\010 \033\014 \ ! 139: \012 \ ! 140: \015 \011 \013 \ ! 141: "; ! 142: ! 143: /* Given a pointer to a string value inside a termcap entry (`ptr'), ! 144: copy the value and process \ and ^ abbreviations. ! 145: Copy into block that *area points to, ! 146: or to newly allocated storage if area is 0. */ ! 147: ! 148: static char * ! 149: tgetst1 (ptr, area) ! 150: char *ptr; ! 151: char **area; ! 152: { ! 153: register char *p, *r; ! 154: register int c; ! 155: register int size; ! 156: char *ret; ! 157: register int c1; ! 158: ! 159: if (!ptr) ! 160: return 0; ! 161: ! 162: /* `ret' gets address of where to store the string */ ! 163: if (!area) ! 164: { ! 165: /* Compute size of block needed (may overestimate) */ ! 166: p = ptr; ! 167: while ((c = *p++) && c != ':' && c != '\n'); ! 168: ret = (char *) xmalloc (p - ptr + 1); ! 169: } ! 170: else ! 171: ret = *area; ! 172: ! 173: /* Copy the string value, stopping at null or colon. */ ! 174: /* Also process ^ and \ abbreviations. */ ! 175: p = ptr; ! 176: r = ret; ! 177: while ((c = *p++) && c != ':' && c != '\n') ! 178: { ! 179: if (c == '^') ! 180: c = *p++ & 037; ! 181: else if (c == '\\') ! 182: { ! 183: c = *p++; ! 184: if (c >= '0' && c <= '7') ! 185: { ! 186: c -= '0'; ! 187: size = 0; ! 188: ! 189: while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7') ! 190: { ! 191: c *= 8; ! 192: c += c1 - '0'; ! 193: p++; ! 194: } ! 195: } ! 196: else if (c >= 0100 && c < 0200) ! 197: { ! 198: c1 = esctab[(c & ~040) - 0100]; ! 199: if (c1 != ' ') ! 200: c = c1; ! 201: } ! 202: } ! 203: *r++ = c; ! 204: } ! 205: *r = 0; ! 206: /* Update *area */ ! 207: if (area) ! 208: *area = r + 1; ! 209: return ret; ! 210: } ! 211: ! 212: /* Outputting a string with padding */ ! 213: ! 214: short ospeed; ! 215: char PC; ! 216: ! 217: /* Actual baud rate if positive; ! 218: - baud rate / 100 if negative. */ ! 219: ! 220: static short speeds[] = ! 221: { ! 222: #ifdef VMS ! 223: 0, 50, 75, 110, 134, 150, -3, -6, -12, -18, ! 224: -20, -24, -36, -48, -72, -96, -192 ! 225: #else /* not VMS */ ! 226: 0, 50, 75, 110, 135, 150, -2, -3, -6, -12, ! 227: -18, -24, -48, -96, -192, -384 ! 228: #endif /* not VMS */ ! 229: }; ! 230: ! 231: tputs (string, nlines, outfun) ! 232: register char *string; ! 233: int nlines; ! 234: register int (*outfun) (); ! 235: { ! 236: register int padcount = 0; ! 237: ! 238: if (string == (char *) 0) ! 239: return; ! 240: while (*string >= '0' && *string <= '9') ! 241: { ! 242: padcount += *string++ - '0'; ! 243: padcount *= 10; ! 244: } ! 245: if (*string == '.') ! 246: { ! 247: string++; ! 248: padcount += *string++ - '0'; ! 249: } ! 250: if (*string == '*') ! 251: { ! 252: string++; ! 253: padcount *= nlines; ! 254: } ! 255: while (*string) ! 256: (*outfun) (*string++); ! 257: ! 258: /* padcount is now in units of tenths of msec. */ ! 259: padcount *= speeds[ospeed]; ! 260: padcount += 500; ! 261: padcount /= 1000; ! 262: if (speeds[ospeed] < 0) ! 263: padcount = -padcount; ! 264: else ! 265: { ! 266: padcount += 50; ! 267: padcount /= 100; ! 268: } ! 269: ! 270: while (padcount-- > 0) ! 271: (*outfun) (PC); ! 272: } ! 273: ! 274: /* Finding the termcap entry in the termcap data base */ ! 275: ! 276: struct buffer ! 277: { ! 278: char *beg; ! 279: int size; ! 280: char *ptr; ! 281: int ateof; ! 282: int full; ! 283: }; ! 284: ! 285: /* Forward declarations of static functions */ ! 286: ! 287: static int scan_file (); ! 288: static char *gobble_line (); ! 289: static int compare_contin (); ! 290: static int name_match (); ! 291: ! 292: #ifdef VMS ! 293: ! 294: #include <rmsdef.h> ! 295: #include <fab.h> ! 296: #include <nam.h> ! 297: ! 298: static int ! 299: legal_filename_p (fn) ! 300: char *fn; ! 301: { ! 302: struct FAB fab = cc$rms_fab; ! 303: struct NAM nam = cc$rms_nam; ! 304: char esa[NAM$C_MAXRSS]; ! 305: ! 306: fab.fab$l_fna = fn; ! 307: fab.fab$b_fns = strlen(fn); ! 308: fab.fab$l_nam = &nam; ! 309: fab.fab$l_fop = FAB$M_NAM; ! 310: ! 311: nam.nam$l_esa = esa; ! 312: nam.nam$b_ess = sizeof esa; ! 313: ! 314: return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL; ! 315: } ! 316: ! 317: #endif /* VMS */ ! 318: ! 319: /* Find the termcap entry data for terminal type `name' ! 320: and store it in the block that `bp' points to. ! 321: Record its address for future use. ! 322: ! 323: If `bp' is zero, space is dynamically allocated. */ ! 324: ! 325: int ! 326: tgetent (bp, name) ! 327: char *bp, *name; ! 328: { ! 329: register char *tem; ! 330: register int fd; ! 331: struct buffer buf; ! 332: register char *bp1; ! 333: char *bp2; ! 334: char *term; ! 335: int malloc_size = 0; ! 336: register int c; ! 337: char *tcenv; /* TERMCAP value, if it contais :tc=. */ ! 338: char *indirect = 0; /* Terminal type in :tc= in TERMCAP value. */ ! 339: int filep; ! 340: ! 341: tem = (char *) getenv ("TERMCAP"); ! 342: if (tem && *tem == 0) tem = 0; ! 343: ! 344: #ifdef VMS ! 345: filep = tem && legal_filename_p (tem); ! 346: #else ! 347: filep = tem && (*tem == '/'); ! 348: #endif /* VMS */ ! 349: ! 350: /* If tem is non-null and starts with / (in the un*x case, that is), ! 351: it is a file name to use instead of /etc/termcap. ! 352: If it is non-null and does not start with /, ! 353: it is the entry itself, but only if ! 354: the name the caller requested matches the TERM variable. */ ! 355: ! 356: if (tem && !filep && !strcmp (name, getenv ("TERM"))) ! 357: { ! 358: indirect = tgetst1 (find_capability (tem, "tc"), 0); ! 359: if (!indirect) ! 360: { ! 361: if (!bp) ! 362: bp = tem; ! 363: else ! 364: strcpy (bp, tem); ! 365: goto ret; ! 366: } ! 367: else ! 368: { /* we will need to read /etc/termcap */ ! 369: tcenv = tem; ! 370: tem = 0; ! 371: } ! 372: } ! 373: else ! 374: indirect = (char *) 0; ! 375: ! 376: if (!tem) ! 377: #ifdef VMS ! 378: tem = "emacs_library:[etc]termcap.dat"; ! 379: #else ! 380: tem = "/etc/termcap"; ! 381: #endif ! 382: ! 383: /* Here we know we must search a file and tem has its name. */ ! 384: ! 385: fd = open (tem, 0, 0); ! 386: if (fd < 0) ! 387: return -1; ! 388: ! 389: buf.size = BUFSIZE; ! 390: /* Add 1 to size to ensure room for terminating null. */ ! 391: buf.beg = (char *) xmalloc (buf.size + 1); ! 392: term = indirect ? indirect : name; ! 393: ! 394: if (!bp) ! 395: { ! 396: malloc_size = indirect ? strlen (tcenv) + 1 : buf.size; ! 397: bp = (char *) xmalloc (malloc_size); ! 398: } ! 399: bp1 = bp; ! 400: ! 401: if (indirect) /* copy the data from the environment variable */ ! 402: { ! 403: strcpy (bp, tcenv); ! 404: bp1 += strlen (tcenv); ! 405: } ! 406: ! 407: while (term) ! 408: { ! 409: /* Scan file, reading it via buf, till find start of main entry */ ! 410: if (scan_file (term, fd, &buf) == 0) ! 411: return 0; ! 412: ! 413: /* Free old `term' if appropriate. */ ! 414: if (term != name) ! 415: free (term); ! 416: ! 417: /* If `bp' is malloc'd by us, make sure it is big enough. */ ! 418: if (malloc_size) ! 419: { ! 420: malloc_size = bp1 - bp + buf.size; ! 421: tem = (char *) xrealloc (bp, malloc_size); ! 422: bp1 += tem - bp; ! 423: bp = tem; ! 424: } ! 425: ! 426: bp2 = bp1; ! 427: ! 428: /* Copy the line of the entry from buf into bp. */ ! 429: tem = buf.ptr; ! 430: while ((*bp1++ = c = *tem++) && c != '\n') ! 431: /* Drop out any \ newline sequence. */ ! 432: if (c == '\\' && *tem == '\n') ! 433: { ! 434: bp1--; ! 435: tem++; ! 436: } ! 437: *bp1 = 0; ! 438: ! 439: /* Does this entry refer to another terminal type's entry? */ ! 440: /* If something is found, copy it into heap and null-terminate it */ ! 441: term = tgetst1 (find_capability (bp2, "tc"), 0); ! 442: } ! 443: ! 444: close (fd); ! 445: free (buf.beg); ! 446: ! 447: if (malloc_size) ! 448: { ! 449: bp = (char *) xrealloc (bp, bp1 - bp + 1); ! 450: } ! 451: ! 452: ret: ! 453: term_entry = bp; ! 454: if (malloc_size) ! 455: return (int) bp; ! 456: return 1; ! 457: } ! 458: ! 459: /* Given file open on `fd' and buffer `bufp', ! 460: scan the file from the beginning until a line is found ! 461: that starts the entry for terminal type `string'. ! 462: Returns 1 if successful, with that line in `bufp', ! 463: or returns 0 if no entry found in the file. */ ! 464: ! 465: static int ! 466: scan_file (string, fd, bufp) ! 467: char *string; ! 468: int fd; ! 469: register struct buffer *bufp; ! 470: { ! 471: register char *tem; ! 472: register char *end; ! 473: ! 474: bufp->ptr = bufp->beg; ! 475: bufp->full = 0; ! 476: bufp->ateof = 0; ! 477: *bufp->ptr = 0; ! 478: ! 479: lseek (fd, 0L, 0); ! 480: ! 481: while (!bufp->ateof) ! 482: { ! 483: /* Read a line into the buffer */ ! 484: end = 0; ! 485: do ! 486: { ! 487: /* if it is continued, append another line to it, ! 488: until a non-continued line ends */ ! 489: end = gobble_line (fd, bufp, end); ! 490: } ! 491: while (!bufp->ateof && end[-2] == '\\'); ! 492: ! 493: if (*bufp->ptr != '#' ! 494: && name_match (bufp->ptr, string)) ! 495: return 1; ! 496: ! 497: /* Discard the line just processed */ ! 498: bufp->ptr = end; ! 499: } ! 500: return 0; ! 501: } ! 502: ! 503: /* Return nonzero if NAME is one of the names specified ! 504: by termcap entry LINE. */ ! 505: ! 506: static int ! 507: name_match (line, name) ! 508: char *line, *name; ! 509: { ! 510: register char *tem; ! 511: ! 512: if (!compare_contin (line, name)) ! 513: return 1; ! 514: /* This line starts an entry. Is it the right one? */ ! 515: for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++) ! 516: if (*tem == '|' && !compare_contin (tem + 1, name)) ! 517: return 1; ! 518: ! 519: return 0; ! 520: } ! 521: ! 522: static int ! 523: compare_contin (str1, str2) ! 524: register char *str1, *str2; ! 525: { ! 526: register int c1, c2; ! 527: while (1) ! 528: { ! 529: c1 = *str1++; ! 530: c2 = *str2++; ! 531: while (c1 == '\\' && *str1 == '\n') ! 532: { ! 533: str1++; ! 534: while ((c1 = *str1++) == ' ' || c1 == '\t'); ! 535: } ! 536: if (c2 == '\0') /* end of type being looked up */ ! 537: { ! 538: if (c1 == '|' || c1 == ':') /* If end of name in data base, */ ! 539: return 0; /* we win. */ ! 540: else ! 541: return 1; ! 542: } ! 543: else if (c1 != c2) ! 544: return 1; ! 545: } ! 546: } ! 547: ! 548: /* Make sure that the buffer <- `bufp' contains a full line ! 549: of the file open on `fd', starting at the place `bufp->ptr' ! 550: points to. Can read more of the file, discard stuff before ! 551: `bufp->ptr', or make the buffer bigger. ! 552: ! 553: Returns the pointer to after the newline ending the line, ! 554: or to the end of the file, if there is no newline to end it. ! 555: ! 556: Can also merge on continuation lines. If `append_end' is ! 557: nonzero, it points past the newline of a line that is ! 558: continued; we add another line onto it and regard the whole ! 559: thing as one line. The caller decides when a line is continued. */ ! 560: ! 561: static char * ! 562: gobble_line (fd, bufp, append_end) ! 563: int fd; ! 564: register struct buffer *bufp; ! 565: char *append_end; ! 566: { ! 567: register char *end; ! 568: register int nread; ! 569: register char *buf = bufp->beg; ! 570: register char *tem; ! 571: ! 572: if (append_end == 0) ! 573: append_end = bufp->ptr; ! 574: ! 575: while (1) ! 576: { ! 577: end = append_end; ! 578: while (*end && *end != '\n') end++; ! 579: if (*end) ! 580: break; ! 581: if (bufp->ateof) ! 582: return buf + bufp->full; ! 583: if (bufp->ptr == buf) ! 584: { ! 585: if (bufp->full == bufp->size) ! 586: { ! 587: bufp->size *= 2; ! 588: /* Add 1 to size to ensure room for terminating null. */ ! 589: tem = (char *) xrealloc (buf, bufp->size + 1); ! 590: bufp->ptr = (bufp->ptr - buf) + tem; ! 591: append_end = (append_end - buf) + tem; ! 592: bufp->beg = buf = tem; ! 593: } ! 594: } ! 595: else ! 596: { ! 597: append_end -= bufp->ptr - buf; ! 598: bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf); ! 599: bufp->ptr = buf; ! 600: } ! 601: if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full))) ! 602: bufp->ateof = 1; ! 603: bufp->full += nread; ! 604: buf[bufp->full] = 0; ! 605: } ! 606: return end + 1; ! 607: } ! 608: ! 609: #ifdef TEST ! 610: ! 611: #include <stdio.h> ! 612: ! 613: main (argc, argv) ! 614: int argc; ! 615: char **argv; ! 616: { ! 617: char *term; ! 618: char *buf; ! 619: ! 620: term = argv[1]; ! 621: printf ("TERM: %s\n", term); ! 622: ! 623: buf = (char *) tgetent (0, term); ! 624: if ((int) buf <= 0) ! 625: { ! 626: printf ("No entry.\n"); ! 627: return 0; ! 628: } ! 629: ! 630: printf ("Entry: %s\n", buf); ! 631: ! 632: tprint ("cm"); ! 633: tprint ("AL"); ! 634: ! 635: printf ("co: %d\n", tgetnum ("co")); ! 636: printf ("am: %d\n", tgetflag ("am")); ! 637: } ! 638: ! 639: tprint (cap) ! 640: char *cap; ! 641: { ! 642: char *x = tgetstr (cap, 0); ! 643: register char *y; ! 644: ! 645: printf ("%s: ", cap); ! 646: if (x) ! 647: { ! 648: for (y = x; *y; y++) ! 649: if (*y <= ' ' || *y == 0177) ! 650: printf ("\\%0o", *y); ! 651: else ! 652: putchar (*y); ! 653: free (x); ! 654: } ! 655: else ! 656: printf ("none"); ! 657: putchar ('\n'); ! 658: } ! 659: ! 660: #endif /* TEST */ ! 661:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.