Blame termcap.c

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