[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] Changes to emacs/src/termcap.c [lexbind]
From: |
Miles Bader |
Subject: |
[Emacs-diffs] Changes to emacs/src/termcap.c [lexbind] |
Date: |
Tue, 14 Oct 2003 19:23:24 -0400 |
Index: emacs/src/termcap.c
diff -c /dev/null emacs/src/termcap.c:1.23.2.1
*** /dev/null Tue Oct 14 19:23:24 2003
--- emacs/src/termcap.c Tue Oct 14 19:22:47 2003
***************
*** 0 ****
--- 1,833 ----
+ /* Work-alike for termcap, plus extra features.
+ Copyright (C) 1985, 86, 93, 94, 95, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+ /* Emacs config.h may rename various library functions such as malloc. */
+ #ifdef HAVE_CONFIG_H
+ #include <config.h>
+ #endif
+
+ #ifdef emacs
+
+ #include <lisp.h> /* xmalloc is here */
+ /* Get the O_* definitions for open et al. */
+ #include <sys/file.h>
+ #ifdef HAVE_FCNTL_H
+ #include <fcntl.h>
+ #endif
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+ #endif
+
+ #else /* not emacs */
+
+ #ifdef STDC_HEADERS
+ #include <stdlib.h>
+ #include <string.h>
+ #else
+ char *getenv ();
+ char *malloc ();
+ char *realloc ();
+ #endif
+
+ /* Do this after the include, in case string.h prototypes bcopy. */
+ #if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
+ #define bcopy(s, d, n) memcpy ((d), (s), (n))
+ #endif
+
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+ #endif
+ #ifdef HAVE_FCNTL_H
+ #include <fcntl.h>
+ #endif
+
+ #endif /* not emacs */
+
+ #ifndef NULL
+ #define NULL (char *) 0
+ #endif
+
+ #ifndef O_RDONLY
+ #define O_RDONLY 0
+ #endif
+
+ /* BUFSIZE is the initial size allocated for the buffer
+ for reading the termcap file.
+ It is not a limit.
+ Make it large normally for speed.
+ Make it variable when debugging, so can exercise
+ increasing the space dynamically. */
+
+ #ifndef BUFSIZE
+ #ifdef DEBUG
+ #define BUFSIZE bufsize
+
+ int bufsize = 128;
+ #else
+ #define BUFSIZE 2048
+ #endif
+ #endif
+
+ #ifndef TERMCAP_FILE
+ #define TERMCAP_FILE "/etc/termcap"
+ #endif
+
+ #ifndef emacs
+ static void
+ memory_out ()
+ {
+ write (2, "virtual memory exhausted\n", 25);
+ exit (1);
+ }
+
+ static char *
+ xmalloc (size)
+ unsigned size;
+ {
+ register char *tem = malloc (size);
+
+ if (!tem)
+ memory_out ();
+ return tem;
+ }
+
+ static char *
+ xrealloc (ptr, size)
+ char *ptr;
+ unsigned size;
+ {
+ register char *tem = realloc (ptr, size);
+
+ if (!tem)
+ memory_out ();
+ return tem;
+ }
+ #endif /* not emacs */
+
+ /* Looking up capabilities in the entry already found. */
+
+ /* The pointer to the data made by tgetent is left here
+ for tgetnum, tgetflag and tgetstr to find. */
+ static char *term_entry;
+
+ static char *tgetst1 ();
+
+ /* Search entry BP for capability CAP.
+ Return a pointer to the capability (in BP) if found,
+ 0 if not found. */
+
+ static char *
+ find_capability (bp, cap)
+ register char *bp, *cap;
+ {
+ for (; *bp; bp++)
+ if (bp[0] == ':'
+ && bp[1] == cap[0]
+ && bp[2] == cap[1])
+ return &bp[4];
+ return NULL;
+ }
+
+ /* These are already defined in the System framework in Mac OS X and
+ cause prebinding to fail. */
+ #ifndef MAC_OSX
+ int
+ tgetnum (cap)
+ char *cap;
+ {
+ register char *ptr = find_capability (term_entry, cap);
+ if (!ptr || ptr[-1] != '#')
+ return -1;
+ return atoi (ptr);
+ }
+
+ int
+ tgetflag (cap)
+ char *cap;
+ {
+ register char *ptr = find_capability (term_entry, cap);
+ return ptr && ptr[-1] == ':';
+ }
+
+ /* Look up a string-valued capability CAP.
+ If AREA is non-null, it points to a pointer to a block in which
+ to store the string. That pointer is advanced over the space used.
+ If AREA is null, space is allocated with `malloc'. */
+
+ char *
+ tgetstr (cap, area)
+ char *cap;
+ char **area;
+ {
+ register char *ptr = find_capability (term_entry, cap);
+ if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
+ return NULL;
+ return tgetst1 (ptr, area);
+ }
+ #endif /* MAC_OSX */
+
+ #ifdef IS_EBCDIC_HOST
+ /* Table, indexed by a character in range 0200 to 0300 with 0200 subtracted,
+ gives meaning of character following \, or a space if no special meaning.
+ Sixteen characters per line within the string. */
+
+ static char esctab[]
+ = " \057\026 \047\014 \
+ \025 \015 \
+ \005 \013 \
+ ";
+ #else
+ /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
+ gives meaning of character following \, or a space if no special meaning.
+ Eight characters per line within the string. */
+
+ static char esctab[]
+ = " \007\010 \033\014 \
+ \012 \
+ \015 \011 \013 \
+ ";
+ #endif
+
+ /* PTR points to a string value inside a termcap entry.
+ Copy that value, processing \ and ^ abbreviations,
+ into the block that *AREA points to,
+ or to newly allocated storage if AREA is NULL.
+ Return the address to which we copied the value,
+ or NULL if PTR is NULL. */
+
+ static char *
+ tgetst1 (ptr, area)
+ char *ptr;
+ char **area;
+ {
+ register char *p, *r;
+ register int c;
+ register int size;
+ char *ret;
+ register int c1;
+
+ if (!ptr)
+ return NULL;
+
+ /* `ret' gets address of where to store the string. */
+ if (!area)
+ {
+ /* Compute size of block needed (may overestimate). */
+ p = ptr;
+ while ((c = *p++) && c != ':' && c != '\n')
+ ;
+ ret = (char *) xmalloc (p - ptr + 1);
+ }
+ else
+ ret = *area;
+
+ /* Copy the string value, stopping at null or colon.
+ Also process ^ and \ abbreviations. */
+ p = ptr;
+ r = ret;
+ while ((c = *p++) && c != ':' && c != '\n')
+ {
+ if (c == '^')
+ {
+ c = *p++;
+ if (c == '?')
+ c = 0177;
+ else
+ c &= 037;
+ }
+ else if (c == '\\')
+ {
+ c = *p++;
+ if (c >= '0' && c <= '7')
+ {
+ c -= '0';
+ size = 0;
+
+ while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
+ {
+ c *= 8;
+ c += c1 - '0';
+ p++;
+ }
+ }
+ #ifdef IS_EBCDIC_HOST
+ else if (c >= 0200 && c < 0360)
+ {
+ c1 = esctab[(c & ~0100) - 0200];
+ if (c1 != ' ')
+ c = c1;
+ }
+ #else
+ else if (c >= 0100 && c < 0200)
+ {
+ c1 = esctab[(c & ~040) - 0100];
+ if (c1 != ' ')
+ c = c1;
+ }
+ #endif
+ }
+ *r++ = c;
+ }
+ *r = '\0';
+ /* Update *AREA. */
+ if (area)
+ *area = r + 1;
+ return ret;
+ }
+
+ /* Outputting a string with padding. */
+
+ #ifndef emacs
+ short ospeed;
+ /* If OSPEED is 0, we use this as the actual baud rate. */
+ int tputs_baud_rate;
+ #endif
+
+ /* Already defined in the System framework in Mac OS X and causes
+ prebinding to fail. */
+ #ifndef MAC_OSX
+ char PC;
+ #endif /* MAC_OSX */
+
+ #ifndef emacs
+ /* Actual baud rate if positive;
+ - baud rate / 100 if negative. */
+
+ static int speeds[] =
+ {
+ #ifdef VMS
+ 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
+ -20, -24, -36, -48, -72, -96, -192
+ #else /* not VMS */
+ 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
+ -18, -24, -48, -96, -192, -288, -384, -576, -1152
+ #endif /* not VMS */
+ };
+
+ #endif /* not emacs */
+
+ /* Already defined in the System framework in Mac OS X and causes
+ prebinding to fail. */
+ #ifndef MAC_OSX
+ void
+ tputs (str, nlines, outfun)
+ register char *str;
+ int nlines;
+ register int (*outfun) ();
+ {
+ register int padcount = 0;
+ register int speed;
+
+ #ifdef emacs
+ extern EMACS_INT baud_rate;
+ speed = baud_rate;
+ /* For quite high speeds, convert to the smaller
+ units to avoid overflow. */
+ if (speed > 10000)
+ speed = - speed / 100;
+ #else
+ if (ospeed == 0)
+ speed = tputs_baud_rate;
+ else
+ speed = speeds[ospeed];
+ #endif
+
+ if (!str)
+ return;
+
+ while (*str >= '0' && *str <= '9')
+ {
+ padcount += *str++ - '0';
+ padcount *= 10;
+ }
+ if (*str == '.')
+ {
+ str++;
+ padcount += *str++ - '0';
+ }
+ if (*str == '*')
+ {
+ str++;
+ padcount *= nlines;
+ }
+ while (*str)
+ (*outfun) (*str++);
+
+ /* PADCOUNT is now in units of tenths of msec.
+ SPEED is measured in characters per 10 seconds
+ or in characters per .1 seconds (if negative).
+ We use the smaller units for larger speeds to avoid overflow. */
+ padcount *= speed;
+ padcount += 500;
+ padcount /= 1000;
+ if (speed < 0)
+ padcount = -padcount;
+ else
+ {
+ padcount += 50;
+ padcount /= 100;
+ }
+
+ while (padcount-- > 0)
+ (*outfun) (PC);
+ }
+ #endif /* MAC_OSX */
+
+ /* Finding the termcap entry in the termcap data base. */
+
+ struct termcap_buffer
+ {
+ char *beg;
+ int size;
+ char *ptr;
+ int ateof;
+ int full;
+ };
+
+ /* Forward declarations of static functions. */
+
+ static int scan_file ();
+ static char *gobble_line ();
+ static int compare_contin ();
+ static int name_match ();
+
+ #ifdef VMS
+
+ #include <rmsdef.h>
+ #include <fab.h>
+ #include <nam.h>
+
+ static int
+ valid_filename_p (fn)
+ char *fn;
+ {
+ struct FAB fab = cc$rms_fab;
+ struct NAM nam = cc$rms_nam;
+ char esa[NAM$C_MAXRSS];
+
+ fab.fab$l_fna = fn;
+ fab.fab$b_fns = strlen(fn);
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fop = FAB$M_NAM;
+
+ nam.nam$l_esa = esa;
+ nam.nam$b_ess = sizeof esa;
+
+ return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL;
+ }
+
+ #else /* !VMS */
+
+ #ifdef MSDOS /* MW, May 1993 */
+ static int
+ valid_filename_p (fn)
+ char *fn;
+ {
+ return *fn == '/' || fn[1] == ':';
+ }
+ #else
+ #define valid_filename_p(fn) (*(fn) == '/')
+ #endif
+
+ #endif /* !VMS */
+
+ /* Find the termcap entry data for terminal type NAME
+ and store it in the block that BP points to.
+ Record its address for future use.
+
+ If BP is null, space is dynamically allocated.
+
+ Return -1 if there is some difficulty accessing the data base
+ of terminal types,
+ 0 if the data base is accessible but the type NAME is not defined
+ in it, and some other value otherwise. */
+
+ /* Already defined in the System framework in Mac OS X and causes
+ prebinding to fail. */
+ #ifndef MAC_OSX
+ int
+ tgetent (bp, name)
+ char *bp, *name;
+ {
+ register char *termcap_name;
+ register int fd;
+ struct termcap_buffer buf;
+ register char *bp1;
+ char *tc_search_point;
+ char *term;
+ int malloc_size = 0;
+ register int c;
+ char *tcenv = NULL; /* TERMCAP value, if it contains :tc=. */
+ char *indirect = NULL; /* Terminal type in :tc= in TERMCAP value. */
+ int filep;
+
+ #ifdef INTERNAL_TERMINAL
+ /* For the internal terminal we don't want to read any termcap file,
+ so fake it. */
+ if (!strcmp (name, "internal"))
+ {
+ term = INTERNAL_TERMINAL;
+ if (!bp)
+ {
+ malloc_size = 1 + strlen (term);
+ bp = (char *) xmalloc (malloc_size);
+ }
+ strcpy (bp, term);
+ goto ret;
+ }
+ #endif /* INTERNAL_TERMINAL */
+
+ /* For compatibility with programs like `less' that want to
+ put data in the termcap buffer themselves as a fallback. */
+ if (bp)
+ term_entry = bp;
+
+ termcap_name = getenv ("TERMCAP");
+ if (termcap_name && *termcap_name == '\0')
+ termcap_name = NULL;
+ #if defined (MSDOS) && !defined (TEST)
+ if (termcap_name && (*termcap_name == '\\'
+ || *termcap_name == '/'
+ || termcap_name[1] == ':'))
+ dostounix_filename(termcap_name);
+ #endif
+
+ filep = termcap_name && valid_filename_p (termcap_name);
+
+ /* If termcap_name is non-null and starts with / (in the un*x case, that
is),
+ it is a file name to use instead of /etc/termcap.
+ If it is non-null and does not start with /,
+ it is the entry itself, but only if
+ the name the caller requested matches the TERM variable. */
+
+ if (termcap_name && !filep && !strcmp (name, getenv ("TERM")))
+ {
+ indirect = tgetst1 (find_capability (termcap_name, "tc"), (char **) 0);
+ if (!indirect)
+ {
+ if (!bp)
+ bp = termcap_name;
+ else
+ strcpy (bp, termcap_name);
+ goto ret;
+ }
+ else
+ { /* It has tc=. Need to read /etc/termcap. */
+ tcenv = termcap_name;
+ termcap_name = NULL;
+ }
+ }
+
+ if (!termcap_name || !filep)
+ termcap_name = TERMCAP_FILE;
+
+ /* Here we know we must search a file and termcap_name has its name. */
+
+ #ifdef MSDOS
+ fd = open (termcap_name, O_RDONLY|O_TEXT, 0);
+ #else
+ fd = open (termcap_name, O_RDONLY, 0);
+ #endif
+ if (fd < 0)
+ return -1;
+
+ buf.size = BUFSIZE;
+ /* Add 1 to size to ensure room for terminating null. */
+ buf.beg = (char *) xmalloc (buf.size + 1);
+ term = indirect ? indirect : name;
+
+ if (!bp)
+ {
+ malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
+ bp = (char *) xmalloc (malloc_size);
+ }
+ tc_search_point = bp1 = bp;
+
+ if (indirect)
+ /* Copy the data from the environment variable. */
+ {
+ strcpy (bp, tcenv);
+ bp1 += strlen (tcenv);
+ }
+
+ while (term)
+ {
+ /* Scan the file, reading it via buf, till find start of main entry. */
+ if (scan_file (term, fd, &buf) == 0)
+ {
+ close (fd);
+ free (buf.beg);
+ if (malloc_size)
+ free (bp);
+ return 0;
+ }
+
+ /* Free old `term' if appropriate. */
+ if (term != name)
+ free (term);
+
+ /* If BP is malloc'd by us, make sure it is big enough. */
+ if (malloc_size)
+ {
+ int offset1 = bp1 - bp, offset2 = tc_search_point - bp;
+ malloc_size = offset1 + buf.size;
+ bp = termcap_name = (char *) xrealloc (bp, malloc_size);
+ bp1 = termcap_name + offset1;
+ tc_search_point = termcap_name + offset2;
+ }
+
+ /* Copy the line of the entry from buf into bp. */
+ termcap_name = buf.ptr;
+ while ((*bp1++ = c = *termcap_name++) && c != '\n')
+ /* Drop out any \ newline sequence. */
+ if (c == '\\' && *termcap_name == '\n')
+ {
+ bp1--;
+ termcap_name++;
+ }
+ *bp1 = '\0';
+
+ /* Does this entry refer to another terminal type's entry?
+ If something is found, copy it into heap and null-terminate it. */
+ tc_search_point = find_capability (tc_search_point, "tc");
+ term = tgetst1 (tc_search_point, (char **) 0);
+ }
+
+ close (fd);
+ free (buf.beg);
+
+ if (malloc_size)
+ bp = (char *) xrealloc (bp, bp1 - bp + 1);
+
+ ret:
+ term_entry = bp;
+ return 1;
+ }
+ #endif /* MAC_OSX */
+
+ /* Given file open on FD and buffer BUFP,
+ scan the file from the beginning until a line is found
+ that starts the entry for terminal type STR.
+ Return 1 if successful, with that line in BUFP,
+ or 0 if no entry is found in the file. */
+
+ static int
+ scan_file (str, fd, bufp)
+ char *str;
+ int fd;
+ register struct termcap_buffer *bufp;
+ {
+ register char *end;
+
+ bufp->ptr = bufp->beg;
+ bufp->full = 0;
+ bufp->ateof = 0;
+ *bufp->ptr = '\0';
+
+ lseek (fd, 0L, 0);
+
+ while (!bufp->ateof)
+ {
+ /* Read a line into the buffer. */
+ end = NULL;
+ do
+ {
+ /* if it is continued, append another line to it,
+ until a non-continued line ends. */
+ end = gobble_line (fd, bufp, end);
+ }
+ while (!bufp->ateof && end[-2] == '\\');
+
+ if (*bufp->ptr != '#'
+ && name_match (bufp->ptr, str))
+ return 1;
+
+ /* Discard the line just processed. */
+ bufp->ptr = end;
+ }
+ return 0;
+ }
+
+ /* Return nonzero if NAME is one of the names specified
+ by termcap entry LINE. */
+
+ static int
+ name_match (line, name)
+ char *line, *name;
+ {
+ register char *tem;
+
+ if (!compare_contin (line, name))
+ return 1;
+ /* This line starts an entry. Is it the right one? */
+ for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
+ if (*tem == '|' && !compare_contin (tem + 1, name))
+ return 1;
+
+ return 0;
+ }
+
+ static int
+ compare_contin (str1, str2)
+ register char *str1, *str2;
+ {
+ register int c1, c2;
+ while (1)
+ {
+ c1 = *str1++;
+ c2 = *str2++;
+ while (c1 == '\\' && *str1 == '\n')
+ {
+ str1++;
+ while ((c1 = *str1++) == ' ' || c1 == '\t');
+ }
+ if (c2 == '\0')
+ {
+ /* End of type being looked up. */
+ if (c1 == '|' || c1 == ':')
+ /* If end of name in data base, we win. */
+ return 0;
+ else
+ return 1;
+ }
+ else if (c1 != c2)
+ return 1;
+ }
+ }
+
+ /* Make sure that the buffer <- BUFP contains a full line
+ of the file open on FD, starting at the place BUFP->ptr
+ points to. Can read more of the file, discard stuff before
+ BUFP->ptr, or make the buffer bigger.
+
+ Return the pointer to after the newline ending the line,
+ or to the end of the file, if there is no newline to end it.
+
+ Can also merge on continuation lines. If APPEND_END is
+ non-null, it points past the newline of a line that is
+ continued; we add another line onto it and regard the whole
+ thing as one line. The caller decides when a line is continued. */
+
+ static char *
+ gobble_line (fd, bufp, append_end)
+ int fd;
+ register struct termcap_buffer *bufp;
+ char *append_end;
+ {
+ register char *end;
+ register int nread;
+ register char *buf = bufp->beg;
+ register char *tem;
+
+ if (!append_end)
+ append_end = bufp->ptr;
+
+ while (1)
+ {
+ end = append_end;
+ while (*end && *end != '\n') end++;
+ if (*end)
+ break;
+ if (bufp->ateof)
+ return buf + bufp->full;
+ if (bufp->ptr == buf)
+ {
+ if (bufp->full == bufp->size)
+ {
+ bufp->size *= 2;
+ /* Add 1 to size to ensure room for terminating null. */
+ tem = (char *) xrealloc (buf, bufp->size + 1);
+ bufp->ptr = (bufp->ptr - buf) + tem;
+ append_end = (append_end - buf) + tem;
+ bufp->beg = buf = tem;
+ }
+ }
+ else
+ {
+ append_end -= bufp->ptr - buf;
+ bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf);
+ bufp->ptr = buf;
+ }
+ if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
+ bufp->ateof = 1;
+ bufp->full += nread;
+ buf[bufp->full] = '\0';
+ }
+ return end + 1;
+ }
+
+ #ifdef TEST
+
+ #ifdef NULL
+ #undef NULL
+ #endif
+
+ #include <stdio.h>
+
+ main (argc, argv)
+ int argc;
+ char **argv;
+ {
+ char *term;
+ char *buf;
+
+ term = argv[1];
+ printf ("TERM: %s\n", term);
+
+ buf = (char *) tgetent (0, term);
+ if ((int) buf <= 0)
+ {
+ printf ("No entry.\n");
+ return 0;
+ }
+
+ printf ("Entry: %s\n", buf);
+
+ tprint ("cm");
+ tprint ("AL");
+
+ printf ("co: %d\n", tgetnum ("co"));
+ printf ("am: %d\n", tgetflag ("am"));
+ }
+
+ tprint (cap)
+ char *cap;
+ {
+ char *x = tgetstr (cap, 0);
+ register char *y;
+
+ printf ("%s: ", cap);
+ if (x)
+ {
+ for (y = x; *y; y++)
+ if (*y <= ' ' || *y == 0177)
+ printf ("\\%0o", *y);
+ else
+ putchar (*y);
+ free (x);
+ }
+ else
+ printf ("none");
+ putchar ('\n');
+ }
+
+ #endif /* TEST */
+
+ /* arch-tag: c2e8d427-2271-4fac-95fe-411857238b80
+ (do not change this comment) */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Emacs-diffs] Changes to emacs/src/termcap.c [lexbind],
Miles Bader <=