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