Annotation of GNUtools/emacs/src/termcap.c, revision 1.1.1.1

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: 

unix.superglobalmegacorp.com

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