Annotation of 43BSD/contrib/emacs/src/termcap.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.