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 */

Defined functions

compare_contin defined in line 449; used 3 times
find_capability defined in line 80; used 4 times
gobble_line defined in line 488; used 2 times
main defined in line 540; never used
memory_out defined in line 40; used 2 times
name_match defined in line 433; used 3 times
scan_file defined in line 392; used 2 times
tgetent defined in line 282; used 2 times
tgetflag defined in line 102; used 13 times
tgetnum defined in line 92; used 7 times
tgetst1 defined in line 141; used 3 times
tgetstr defined in line 115; used 50 times
tprint defined in line 571; used 2 times
tputs defined in line 219; used 19 times
xmalloc defined in line 47; used 3 times
xrealloc defined in line 57; used 3 times

Defined variables

PC defined in line 208; used 1 times
bufsize defined in line 34; used 2 times
esctab defined in line 130; used 1 times
ospeed defined in line 207; used 2 times
speeds defined in line 213; used 2 times
term_entry defined in line 73; used 4 times

Defined struct's

buffer defined in line 260; used 6 times

Defined macros

BUFSIZE defined in line 36; used 2 times
Last modified: 1986-02-25
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1288
Valid CSS Valid XHTML 1.0 Strict