Annotation of GNUtools/emacs/src/termcap.c, revision 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.