800 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			800 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Work-alike for termcap, plus extra features.
 | 
						||
   Copyright (C) 1985, 86, 93, 94, 95 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA.  */
 | 
						||
 | 
						||
/* Emacs config.h may rename various library functions such as malloc.  */
 | 
						||
#ifdef HAVE_CONFIG_H
 | 
						||
 | 
						||
#include <config.h>
 | 
						||
 | 
						||
/* Get the O_* definitions for open et al.  */
 | 
						||
#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
 | 
						||
#  include <sys/file.h>
 | 
						||
#endif
 | 
						||
 | 
						||
#include <fcntl.h>
 | 
						||
 | 
						||
#ifdef HAVE_STDLIB_H
 | 
						||
#  include <stdlib.h>
 | 
						||
#else
 | 
						||
extern char *getenv ();
 | 
						||
extern char *malloc ();
 | 
						||
extern char *realloc ();
 | 
						||
#endif
 | 
						||
 | 
						||
#else /* not HAVE_CONFIG_H */
 | 
						||
 | 
						||
#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 _POSIX_VERSION
 | 
						||
#include <fcntl.h>
 | 
						||
#endif
 | 
						||
 | 
						||
#endif /* not HAVE_CONFIG_H */
 | 
						||
 | 
						||
#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
 | 
						||
 | 
						||
#include "ltcap.h"
 | 
						||
 | 
						||
#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;
 | 
						||
}
 | 
						||
 | 
						||
__private_extern__
 | 
						||
int
 | 
						||
tgetnum (cap)
 | 
						||
     char *cap;
 | 
						||
{
 | 
						||
  register char *ptr = find_capability (term_entry, cap);
 | 
						||
  if (!ptr || ptr[-1] != '#')
 | 
						||
    return -1;
 | 
						||
  return atoi (ptr);
 | 
						||
}
 | 
						||
 | 
						||
__private_extern__
 | 
						||
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'.  */
 | 
						||
 | 
						||
__private_extern__
 | 
						||
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);
 | 
						||
}
 | 
						||
 | 
						||
/* 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 \
 | 
						||
        ";
 | 
						||
 | 
						||
/* 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++;
 | 
						||
		}
 | 
						||
	    }
 | 
						||
	  else if (c >= 0100 && c < 0200)
 | 
						||
	    {
 | 
						||
	      c1 = esctab[(c & ~040) - 0100];
 | 
						||
	      if (c1 != ' ')
 | 
						||
		c = c1;
 | 
						||
	    }
 | 
						||
	}
 | 
						||
      *r++ = c;
 | 
						||
    }
 | 
						||
  *r = '\0';
 | 
						||
  /* Update *AREA.  */
 | 
						||
  if (area)
 | 
						||
    *area = r + 1;
 | 
						||
  return ret;
 | 
						||
}
 | 
						||
 | 
						||
/* Outputting a string with padding.  */
 | 
						||
 | 
						||
short ospeed;
 | 
						||
/* If OSPEED is 0, we use this as the actual baud rate.  */
 | 
						||
int tputs_baud_rate;
 | 
						||
__private_extern__ char PC = '\0';
 | 
						||
 | 
						||
/* 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 */
 | 
						||
  };
 | 
						||
 | 
						||
__private_extern__
 | 
						||
void
 | 
						||
tputs (str, nlines, outfun)
 | 
						||
     register char *str;
 | 
						||
     int nlines;
 | 
						||
     register int (*outfun) ();
 | 
						||
{
 | 
						||
  register int padcount = 0;
 | 
						||
  register int speed;
 | 
						||
 | 
						||
#ifdef emacs
 | 
						||
  extern 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 if (ospeed > 0 && ospeed < (sizeof speeds / sizeof speeds[0]))
 | 
						||
    speed = speeds[ospeed];
 | 
						||
  else
 | 
						||
    speed = 0;
 | 
						||
#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);
 | 
						||
}
 | 
						||
 | 
						||
/* Finding the termcap entry in the termcap data base.  */
 | 
						||
 | 
						||
struct 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 == '/' ||
 | 
						||
    (*fn >= 'A' && *fn <= 'z' && 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.  */
 | 
						||
 | 
						||
__private_extern__
 | 
						||
int
 | 
						||
tgetent (bp, name)
 | 
						||
     char *bp, *name;
 | 
						||
{
 | 
						||
  register char *termcap_name;
 | 
						||
  register int fd;
 | 
						||
  struct buffer buf;
 | 
						||
  register char *bp1;
 | 
						||
  char *bp2;
 | 
						||
  char *term;
 | 
						||
  int malloc_size = 0;
 | 
						||
  register int c;
 | 
						||
  char *tcenv;			/* 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 0
 | 
						||
#if defined (MSDOS) && !defined (TEST)
 | 
						||
  if (termcap_name && (*termcap_name == '\\'
 | 
						||
		       || *termcap_name == '/'
 | 
						||
		       || termcap_name[1] == ':'))
 | 
						||
    dostounix_filename(termcap_name);
 | 
						||
#endif
 | 
						||
#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);
 | 
						||
    }
 | 
						||
  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)
 | 
						||
	{
 | 
						||
	  malloc_size = bp1 - bp + buf.size;
 | 
						||
	  termcap_name = (char *) xrealloc (bp, malloc_size);
 | 
						||
	  bp1 += termcap_name - bp;
 | 
						||
	  bp = termcap_name;
 | 
						||
	}
 | 
						||
 | 
						||
      bp2 = bp1;
 | 
						||
 | 
						||
      /* 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.  */
 | 
						||
      term = tgetst1 (find_capability (bp2, "tc"), (char **) 0);
 | 
						||
    }
 | 
						||
 | 
						||
  close (fd);
 | 
						||
  free (buf.beg);
 | 
						||
 | 
						||
  if (malloc_size)
 | 
						||
    bp = (char *) xrealloc (bp, bp1 - bp + 1);
 | 
						||
 | 
						||
 ret:
 | 
						||
  term_entry = bp;
 | 
						||
  return 1;
 | 
						||
}
 | 
						||
 | 
						||
/* 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 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 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 */
 |