ftp.nice.ch/pub/next/unix/editor/me.3.10.N.bs.tar.gz#/me-3.10.N.bs/src/tcap.c

This is tcap.c in view mode; [Download] [Up]

	/*	tcap:	Unix V5, SUN OS, SCO XENIX, V7 and BS4.2 Termcap video driver
		for MicroEMACS 3.10

         12-10-88 - Modifications made by Guy Turcotte to accomodate
                    SunOS V4.0 and Xenix V2.2.1 :
 
                  SunOS mods:
                  
                  o p_seq field of TBIND struct augmented to 10 chars
                    to take into account longer definitions for keys
                    (some Sun's keys definitions need at least 7 chars...)
                    as such, the code in get1key has been modified to take
                    care of the longer p_seq string.
 
                  o tcapopen modified to take care of the tgetstr problem
                    (returns NULL on undefined keys instead of a valid
                    string pointer...)
 
                  o The timout algorithm of get1key has been modified to
                    take care of the following select() function problem:
                    if some chars are already in the terminal buffer before
                    select is called and no others char appears on the terminal,
                    it will timeout anyway... (maybe a feature of SunOs V4.0)
 
                  Xenix mods:
 
                  o The first two points indicated above are applicable for
                    the Xenix OS
 
                  o With my current knowledge, I can't find a clean solution
                    to the timeout problem of the get1key function
                    under Xenix. I modified the code to get rid of the BSD code 
                    (via the #if directive) and use the Xenix nap() and rdchk()
                    functions to 
                    make a 1/30 second wait. Seems to work as long as there is
                    not to much of activity from other processes on the system.
                    (The link command of the makefile must be modified to
                    link with the x library... you must add the option -lx)
 
                  o The input.c file has been modified to not include the
                    get1key function defined there in the case of USG. The
                    #if directive preceeding the get1key definition has been
                    modified from:
 
                     #if (V7 == 0) && (BSD == 0)
 
                    to:
 
                     #if (V7 == 0) && (BSD == 0) && (USG == 0)
                     
                  o The following lines define the new termcap entry for
                    the ansi kind of terminal: it permits the use of functions
                    keys F1 .. F10 and keys HOME,END,PgUp,PgDn on the IBM PC
                    keyboard (the last 3 lines of the definition have been
                    added):
 
 li|ansi|Ansi standard crt:\
 	:al=\E[L:am:bs:cd=\E[J:ce=\E[K:cl=\E[2J\E[H:cm=\E[%i%d;%dH:co#80:\
 	:dc=\E[P:dl=\E[M:do=\E[B:bt=\E[Z:ei=:ho=\E[H:ic=\E[@:im=:li#25:\
 	:nd=\E[C:pt:so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:up=\E[A:\
 	:kb=^h:ku=\E[A:kd=\E[B:kl=\E[D:kr=\E[C:eo:sf=\E[S:sr=\E[T:\
 	:GS=\E[12m:GE=\E[10m:GV=\63:GH=D:\
 	:GC=E:GL=\64:GR=C:RT=^J:G1=?:G2=Z:G3=@:G4=Y:GU=A:GD=B:\
 	:CW=\E[M:NU=\E[N:RF=\E[O:RC=\E[P:\
 	:WL=\E[S:WR=\E[T:CL=\E[U:CR=\E[V:\
 	:HM=\E[H:EN=\E[F:PU=\E[I:PD=\E[G:\
 	:k1=\E[M:k2=\E[N:k3=\E[O:k4=\E[P:k5=\E[Q:\
 	:k6=\E[R:k7=\E[S:k8=\E[T:k9=\E[U:k0=\E[V:\
 	:kh=\E[H:kH=\E[F:kA=\E[L:kN=\E[G:kP=\E[I:
                    
*/

/*
 * a non-portable but generally usable USG option for get1key() is suggested;
 * it allows use of the function keys needed to handle menus, specifically
 * those of .emacsrc and the *.cmd files; 
 *
 * it assumes typeahead() is enabled;
 *
 * the ttable[] bindings include shifted function and keypad keys;
 *
 * following is a sample ansi terminfo file, which has strings for the 
 * normal and shifted keys, and which adheres more-or-less to the 
 * ansi standard;
 *
 * a user without write permission on the system terminfo files likely
 * will have to set up a local TERMINFO environment by use of .profile,
 * and perhaps reprogram the function and keypad strings of the terminal;
 *
 * j.a. rupley, tucson, az  - rupley!local@megaron.arizona.edu
 */

/*-
ansi|modified terminfo description 
# DELETE #...# COMMENTS #...# BEFORE #...# TIC'ING #
# standard stuff #
	am, xon, cols#80, lines#24, bel=^G, cr=\r, clear=\E[H\E[J, 
	el=\E[K, ed=\E[J, cup=\E[%i%p1%d;%p2%dH, cud1=\n, home=\E[H, 
	cub1=\b, cuf1=\E[C, cuu1=\E[A, dch1=\E[P, dl1=\E[M, blink=\E[5m, 
	bold=\E[1m, smir=\E[4h, invis=\E[8m, rev=\E[7m, smso=\E[7m, 
	smul=\E[4m, sgr0=\E[m, rmir=\E[4l, rmso=\E[0m, rmul=\E[0m, 
	is2=\E[=h, ich1=\E[@, il1=\E[L, 
	dl=\E[%p1%dM, cud=\E[%p1%dB, 
	ich=\E[%p1%d@, il=\E[%p1%dL, cub=\E[%p1%dD, cuf=\E[%p1%dC, 
	cuu=\E[%p1%dA, ind=\n, ht=\t, 
# function keys - kf0=kf10 #
	kf1=\EOc, kf2=\EOd, kf3=\EOe, kf4=\EOf, 
	kf5=\EOg, kf6=\EOh, kf7=\EOi, kf8=\EOj, kf9=\EOk, 
	kf0=\EOl, kf10=\EOl, 
# shifted function keys - lf0=lf10 #
# tricky - store and recover strings as labels #
	lf1=\EOC, lf2=\EOD, lf3=\EOE, lf4=\EOF, 
	lf5=\EOG, lf6=\EOH, lf7=\EOI, lf8=\EOJ, lf9=\EOK, 
	lf0=\EOL, lf10=\EOL, 
# keypad keys #
	khome=\E[H,	kcuu1=\E[A,	kpp=\E[U, 
	kcub1=\E[D, 			kcuf1=\E[C, 
	kll=\E[E, 	kcud1=\E[B, 	knp=\E[V, 
# ins #
	kich1=\E[@, 
# shifted keypad keys #
	ka1=\E[!H,	kri=\E[S,	ka3=\E[!U, 
	kclr=\E[!@,			kel=\E[!A, 
	kc1=\E[!E,	kind=\E[T,	kc3=\E[!V,
# shifted ins and shifted del #
	kil1=\E[L,			kdch1=\E[P,
# miscellaneous #
	kdl1=\E[M, 
	cbt=\E[Z, 
	kbs=\b, 
*/

/*
 * The following is a fleshed-out ansi terminfo file as needed by
 * the SCO Xenix console.
 * Jonathan Bayer, Roselle Park, NJ.  ...!uunet!ispi!jbayer or
 *					jbayer@ispi.uucp
 *
 
# ========================================================
ansi|Ansi standard crt,
	cr=^M, cud1=^J, ind=^J, bel=^G,
	kich1=\E[L, am, cub1=^H, ed=\E[J, el=\E[K,
	clear=\E[2J\E[H, cup=\E[%i%p1%d;%p2%dH, cols#80,
	dch1=\E[P, dl1=\E[M, cud1=\E[B, cbt=\E[Z, rmir=,
	khome=\E[H, ich1=\E[@, smir=, lines#25,
	cuf1=\E[C, ht=^I, smso=\E[7m, rmso=\E[m, smul=\E[4m,
	rmul=\E[m, cuu1=\E[A,
	kbs=^h, kcuu1=\E[A, kcud1=\E[B, kcub1=\E[D, 
	kcuf1=\E[C, eo, ind=\E[S, ri=\E[T,
# added keys here
# function keys
	kf1=\E[M, kf2=\E[N, kf3=\E[O, kf4=\E[P, kf5=\E[Q,
	kf6=\E[R, kf7=\E[S, kf8=\E[T, kf9=\E[U, kf0=\E[V,
	knp=\E[G, kpp=\E[I, kll=\E[F, 
# shifted function keys - lf0=lf10 #
# tricky - store and recover strings as labels #
	lf1=\E[Y,
	lf2=\E[Z, lf3=\E[a, lf4=\E[b, lf5=\E[c, 
	lf6=\E[d, lf7=\E[e, lf8=\E[f, lf9=\E[g, lf0=\E[h, 
# keypad keys #
	ka1=\E[H,	ka3=\E[I, 
	kc1=\E[F,	kc3=\E[G,
# ins 
	kil1=\E[L,
# miscellaneous #, delete line
	kdl1=\E[M, 

*
*/ 

#define termdef 1			/* don't define "term" external */

#include <stdio.h>
#include	"estruct.h"
#include	"etype.h"
#include	"edef.h"
#include	"elang.h"

char	*mgetstr ();

#if TERMCAP

#if	USG | HPUX
#include	<time.h>
#endif
#if	BSD | V7
#include	<sys/types.h>
#include	<sys/time.h>
#endif

#define MARGIN	8
#define SCRSIZ	64
#define NPAUSE	10			/* # times thru update to pause */
#define BEL	0x07
#define ESC	0x1B

/*	Termcap Sequence definitions	*/

typedef struct TBIND {
	char p_name[4]; /* sequence name */
	short p_code;	/* resulting keycode of sequence */
	char p_seq[10];	/* terminal escape sequence */
} TBIND;

  TBIND ttable[] = {
	"bt",	SHFT | CTRL | 'i',	"",	/* backtab */
	"k1",	SPEC | '1',		"",	/* function key 1 */
	"k2",	SPEC | '2',		"",	/* function key 2 */
	"k3",	SPEC | '3',		"",	/* function key 3 */
	"k4",	SPEC | '4',		"",	/* function key 4 */
	"k5",	SPEC | '5',		"",	/* function key 5 */
	"k6",	SPEC | '6',		"",	/* function key 6 */
	"k7",	SPEC | '7',		"",	/* function key 7 */
	"k8",	SPEC | '8',		"",	/* function key 8 */
	"k9",	SPEC | '9',		"",	/* function key 9 */
	"k0",	SPEC | '0',		"",	/* function key 10 */
	"kA",	CTRL | 'O',		"",	/* insert line */
	"kb",	CTRL | 'H',		"",	/* backspace */
	"kC",	CTRL | 'L',		"",	/* clear screen */
	"kD",	SPEC | 'D',		"",	/* delete character */
	"kd",	CTRL | 'N',		"",	/* down cursor */
	"kE",	CTRL | 'K',		"",	/* clear to end of line */
	"kF",	CTRL | 'V',		"",	/* scroll down */
	"kH",	SPEC | '>',		"",	/* home down [END?] key */
	"kh",	SPEC | '<',		"",	/* home */
	"kI",	SPEC | 'C',		"",	/* insert character */
	"kL",	CTRL | 'K',		"",	/* delete line */
	"kl",	CTRL | 'B',		"",	/* left cursor */
	"kN",	SPEC | 'V',		"",	/* next page */
	"kP",	SPEC | 'Z',		"",	/* previous page */
	"kR",	CTRL | 'Z',		"",	/* scroll down */
	"kr",	CTRL | 'F',		"",	/* right cursor */
	"ku",	CTRL | 'P',		"",	/* up cursor */
/* the following are additions to the standard table */
  
 	"l1",	SHFT | SPEC | '1',	"",	/* shift-function key 1 */
 	"l2",	SHFT | SPEC | '2',	"",	/* shift-function key 2 */
 	"l3",	SHFT | SPEC | '3',	"",	/* shift-function key 3 */
 	"l4",	SHFT | SPEC | '4',	"",	/* shift-function key 4 */
 	"l5",	SHFT | SPEC | '5',	"",	/* shift-function key 5 */
 	"l6",	SHFT | SPEC | '6',	"",	/* shift-function key 6 */
 	"l7",	SHFT | SPEC | '7',	"",	/* shift-function key 7 */
 	"l8",	SHFT | SPEC | '8',	"",	/* shift-function key 8 */
 	"l9",	SHFT | SPEC | '9',	"",	/* shift-function key 9 */
 	"l0",	SHFT | SPEC | '0',	"",	/* shift-function key 10 */
 
/* the following are less obvious */
 
/* shift left	# kC kclr  clear screen */	/* bound to backword */
/*	"kC",	META | 'B',		"",	/* kclr /* clear screen */
 	"kC",	SPEC | CTRL | 'B',	"",	/* kclr /* clear screen */
/* shift right	# kE kel  clear to eol */	/* bound to forwword */
/*	"kE",	META | 'F',		"",	/* kel /* clear to eol */
 	"kE",	SPEC | CTRL | 'F',	"",	/* kel /* clear to eol */
/* shift pgup	# K3 ka3  pad upper right */	/* bound to gotobop */
/*	"K3",	META | 'P',		"",	/* ka3 /* pad upper right */
 	"K3",	SPEC | CTRL | 'Z',	"",	/* ka3 /* pad upper right */
/* shift pgdn	# K5 kc3  pad lower right */	/* bound to gotoeop */
/*	"K5",	META | 'N',		"",	/* kc3 /* pad lower right */
 	"K5",	SPEC | CTRL | 'V',	"",	/* kc3 /* pad lower right */
/* shift home	# K1 ka1  pad upper left */	/* unbound key */
 	"K1",	SPEC | CTRL | '<',	"",	/* ka1 /* pad upper left */
/* shift end	# K4 kc1  pad lower left */	/* unbound key */
 	"K4",	SPEC | CTRL | '>',	"",	/* kc1 /* pad lower left */
 
  };
 
#define	NTBINDS	sizeof(ttable)/sizeof(TBIND)

extern int	ttopen();
extern int	ttgetc();
extern int	ttputc();
extern int	tgetnum();
extern int	ttflush();
extern int	ttclose();
extern int	tcapkopen();
extern int	tcapkclose();
extern int	tcapgetc();
extern int	tcapmove();
extern int	tcapeeol();
extern int	tcapeeop();
extern int	tcapbeep();
extern int	tcaprev();
extern int	tcapcres();
extern int	tcapopen();
extern int	tcapclose();
extern int	tput();
extern char	*tgoto();
#if	COLOR
extern	int	tcapfcol();
extern	int	tcapbcol();
#endif

#define TCAPSLEN 1024
char tcapbuf[TCAPSLEN];
char *UP, PC, *CM, *CE, *CL, *SO, *SE, *IS, *KS, *KE;

TERM term = {
	0, 0, 0, 0,	/* these four values are set dynamically at open time */
	MARGIN,
	SCRSIZ,
	NPAUSE,
	tcapopen,
	tcapclose,
	tcapkopen,
	tcapkclose,
	tcapgetc,
	ttputc,
	ttflush,
	tcapmove,
	tcapeeol,
	tcapeeop,
	tcapbeep,
	tcaprev,
	tcapcres
#if	COLOR
	, tcapfcol,
	tcapbcol
#endif
};

/*	input buffers and pointers	*/

#define	IBUFSIZE	64	/* this must be a power of 2 */

unsigned char in_buf[IBUFSIZE];	/* input character buffer */
int in_next = 0;		/* pos to retrieve next input character */
int in_last = 0;		/* pos to place most recent input character */

in_init()	/* initialize the input buffer */

{
	in_next = in_last = 0;
}

in_check()	/* is the input buffer non-empty? */

{
	if (in_next == in_last)
		return(FALSE);
	else
		return(TRUE);
}

in_put(event)

int event;	/* event to enter into the input buffer */

{
	in_buf[in_last++] = event;
	in_last &= (IBUFSIZE - 1);
}

int in_get()	/* get an event from the input buffer */

{
	register int event;	/* event to return */

	event = in_buf[in_next++];
	in_next &= (IBUFSIZE - 1);
	return(event);
}

/*	Open the terminal
	put it in RA mode
	learn about the screen size
	read TERMCAP strings for function keys
*/

tcapopen()

{
	register int index;		/* general index */
	char *t, *p;
	char tcbuf[1024];
	char *tv_stype;
	char err_str[72];
	char *getenv();
	char *tgetstr();

	if ((tv_stype = getenv("TERM")) == NULL) {
		puts(TEXT182);
/*		     "Environment variable TERM not defined!" */
		meexit(1);
	}

	if ((tgetent(tcbuf, tv_stype)) != 1) {
		sprintf(err_str, TEXT183, tv_stype);
/*				 "Unknown terminal type %s!" */
		puts(err_str);
		meexit(1);
	}

 
	if ((term.t_nrow=(short)tgetnum("li")-1) == -1) {
	       puts(TEXT184);
/*		    "termcap entry incomplete (lines)" */
	       meexit(1);
	}
	term.t_mrow =  term.t_nrow;

	if ((term.t_ncol=(short)tgetnum("co")) == -1){
		puts(TEXT185);
/*		    "Termcap entry incomplete (columns)" */
		meexit(1);
	}
	term.t_mcol = term.t_ncol;

	p = tcapbuf;
	t = tgetstr("pc", &p);
	if (t)
		PC = *t;

	CL = tgetstr("cl", &p);
	CM = tgetstr("cm", &p);
	CE = tgetstr("ce", &p);
	UP = tgetstr("up", &p);
	SE = tgetstr("se", &p);
	SO = tgetstr("so", &p);
	if (SO != NULL)
		revexist = TRUE;

	if (CL == NULL || CM == NULL || UP == NULL)
	{
		puts(TEXT186);
/*		     "Incomplete termcap entry\n" */
		meexit(1);
	}

	if (CE == NULL) 	/* will we be able to use clear to EOL? */
		eolexist = FALSE;
		 
	IS = tgetstr("is", &p); /* extract init string */
	KS = tgetstr("ks", &p); /* extract keypad transmit string */
	KE = tgetstr("ke", &p); /* extract keypad transmit end string */
	        
	/* read definitions of various function keys into ttable */
	for (index = 0; index < NTBINDS; index++) {
		strcpy(ttable[index].p_seq,
			fixnull(tgetstr(ttable[index].p_name, &p)));
	}

	
#ifndef	M_TERMINFO

		/* read definitions of local function keys into ttable */
		/* this is used for those terminals which support more */
		/* than 10 function keys.			       */

	if (mgetent(tcbuf,tv_stype)) {
		for (index = 0; index < NTBINDS; index++) {
			if (mgetstr(ttable[index].p_name,&p, tcbuf))
				strcpy(ttable[index].p_seq,
					fixnull(mgetstr(ttable[index].p_name, &p, tcbuf)));
		}
	}

#endif

	
	/* tell unix we are goint to use the terminal */
	ttopen();

	/* make sure we don't over run the buffer (TOO LATE I THINK) */
	if (p >= &tcapbuf[TCAPSLEN]) {
		puts(TEXT187);
/*		     "Terminal description too big!\n" */
		meexit(1);
	}

	/* send init strings if defined */
	if (IS != NULL)
		putpad(IS);
 
	if (KS != NULL)
		putpad(KS);

	/* initialize the input buffer */
	in_init();
}
 
tcapclose()
{
	/* send end-of-keypad-transmit string if defined */
	if (KE != NULL)
		putpad(KE);
	ttclose();
}

tcapkopen()

{
	strcpy(sres, "NORMAL");
}

tcapkclose()

{
}

unsigned int extcode(c)

unsigned int c;

{
	return(c);
}

/*	TCAPGETC:	Get on character.  Resolve and setup all the
			appropriate keystroke escapes as defined in
			the comments at the beginning of input.c
*/

int tcapgetc()

{
	int c;		/* current extended keystroke */

	/* if there are already keys waiting.... send them */
	if (in_check())
		return(in_get());

	/* otherwise... get the char for now */
	c = get1key();

	/* unfold the control bit back into the character */
	if (CTRL & c)
		c = (c & ~ CTRL) - '@';

	/* fold the event type into the input stream as an escape seq */
	if ((c & ~255) != 0) {
		in_put(0);		/* keyboard escape prefix */
		in_put(c >> 8);		/* event type */
		in_put(c & 255);	/* event code */
		return(tcapgetc());
	}

	return(c);
}

/*	GET1KEY:	Get one keystroke. The only prefixs legal here
			are the SPEC and CTRL prefixes.

	Note:

		Escape sequences that are generated by terminal function
		and cursor keys could be confused with the user typing
		the default META prefix followed by other chars... ie

		UPARROW  =  <ESC>A   on some terminals...
		apropos  =  M-A

		The difference is determined by measuring the time between
		the input of the first and second character... if an <ESC>
		is types, and is not followed by another char in 1/30 of
		a second (think 300 baud) then it is a user input, otherwise
		it was generated by an escape sequence and should be SPECed.
*/

int PASCAL NEAR get1key()

{
	register int c;
	register int index;	/* index into termcap binding table */
	char *sp;
#if	BSD | V7 | HPUX
	int fdset;
	struct timeval timeout;
#endif
	char cseq[10];		/* current sequence being parsed */

	c = ttgetc();

	/* if it is not an escape character */
	if (c != 27)
	        return(c);

	/* process a possible escape sequence */
	/* set up to check the keyboard for input */
#if	BSD | V7 | HPUX
	fdset = 1;
	timeout.tv_sec = 0;
	timeout.tv_usec = 35000L;

	/* check to see if things are pending soon */
	if (kbdmode != PLAY &&
		select(1, &fdset, (int *)NULL, (int *)NULL, &timeout) == 0)
		return(CTRL | '[');
#endif

#if XENIX | SUNOS
	if ((kbdmode != PLAY) && (rdchk(0) <= 0)) {
		nap(33L);
		if (rdchk(0) <= 0)
			return(CTRL | '[');
	}
#endif

#if	USG
	/* we don't know how to do this check for a pending char within
	   1/30th of a second machine independantly in the general System V
	   case.... so we don't */
	/*
	 * or... maybe we try it;
	 * very non-portable solution;
	 * hardware-dependent timing loop;
	 * set upper-limit on loop by testing hardware, to get 30 ms;
	 * use typahead() to check for waiting input on exit from loop;
	 */
	{	int i;
		if (kbdmode != PLAY && typahead() <= 0) {
			/* loop limit set by hardware test */
			/* for 30 ms or a bit less */
			for (i = 0; i < 1500; i++)
				;
			if (typahead() <= 0)
				return(CTRL | '[');
		}
	}
	/*-
	 * another way -- using blocking read;
	 * problem... when <esc> used as terminator, as in setup for
	 * searches, need to give it twice, or whatever;
	 * non-portable... assumes ansi standard for function keys and
	 * keypad;
	 */
	/*
	{
		extern char kbdq;
		extern int kbdqp;

		kbdq = ttgetc();
		kbdqp = 1;
		if ((kbdq & 255) != '[' && (kbdq & 255) != 'O')
			return(CTRL | '[');
	}
	*/
#endif

	/* a key is pending within 1/30 of a sec... its an escape sequence */
	cseq[0] = 27;
	sp = &cseq[1];
	*sp = 0;
	while (sp < &cseq[6]) {
		c = ttgetc();
		*sp++ = c;
		*sp = 0;
		for (index = 0; index < NTBINDS; index++) {
			if (strcmp(cseq, ttable[index].p_seq) == 0)
				return(ttable[index].p_code);
		}
	}
	return(SPEC | 0);
}

tcapmove(row, col)
register int row, col;
{
	putpad(tgoto(CM, col, row));
}

tcapeeol()
{
	putpad(CE);
}

tcapeeop()
{
	putpad(CL);
}

tcaprev(state)		/* change reverse video status */

int state;		/* FALSE = normal video, TRUE = reverse video */

{
/*	static int revstate = FALSE;*/

	if (state) {
		if (SO != NULL)
			putpad(SO);
	} else
		if (SE != NULL)
			putpad(SE);
}

tcapcres()	/* change screen resolution */

{
	return(TRUE);
}

spal(dummy)	/* change palette string */

{
	/*	Does nothing here	*/
}

#if	COLOR
tcapfcol()	/* no colors here, ignore this */
{
}

tcapbcol()	/* no colors here, ignore this */
{
}
#endif

tcapbeep()
{
	ttputc(BEL);
}

putpad(str)
char	*str;
{
	tputs(str, 1, ttputc);
}

putnpad(str, n)
char	*str;
{
	tputs(str, n, ttputc);
}


#if	FLABEL
fnclabel(f, n)		/* label a function key */

int f,n;	/* default flag, numeric argument [unused] */

{
	/* on machines with no function keys...don't bother */
	return(TRUE);
}
#endif
#else

hello()
{
}

#endif



#ifndef	M_TERMINFO

char	*TERMEXP = "/etc/termcap.exp";

static	isent (ent, name)
char	*ent;
char	*name;
{
	char	buf[16];
	register int	i;

	while (*ent != ':' && *ent != 0) {
		for (i = 0;*ent != ':' && *ent != '|' && *ent != 0 && i < 15;i++)
			buf[i] = *ent++;

		if (*ent == '|')
			ent++;

		buf[i] = 0;
		if (strcmp (buf, name) == 0)
			return (1);
	}
	return (0);
}

/*
**	reads the termcap.exp file or the environment and returns the 
**	record
*/

mgetent (bp, name)
char	*bp;
char	*name;
{
	char	*buf = bp;
	register char	*cp;
	register FILE	*f;
	register int	i;
	char	*getenv ();


	if ((cp = getenv ("TERMEXP")) != NULL) {
		if (*cp != '/') {
			if (isent (cp, name)) {
				strcpy (buf, cp);
				return (1);
			}
		}
		TERMEXP = cp;
	}
	if ((f = fopen (TERMEXP, "r")) == (FILE *)0)
		return (-1);

	while (fgets (buf, 512, f) != NULL) {
		if (buf[0] == '#')				/* skip all comment lines		*/
			continue;

		i = strlen (buf) - 1;				/* find last character in line		*/
		buf[i] = 0;					/* remove trailing newline		*/
		if (i == 0)					/* ignore blank lines			*/
			continue;

		while (buf[(i = strlen (buf) - 1)] == '\\') {	/* is last character a \\, still more	*/
			cp = &buf[i];				/* find last character			*/
			cp[0] = 0;				/* nullify, end of this part		*/
			if (fgets (cp, 512, f) == NULL)	/* end of file?	...			*/
				break;				/* ... end of entry			*/

			cp[strlen (cp) - 1] = 0;		/* remove trailing newline		*/
			if (cp[0] == '#') {			/* comment line? ...			*/
				cp[0] = 0;			/* remove that line			*/
				continue;			/* go get another line			*/
			}
		}
		if (isent (buf, name)) {
			strcpy (bp, buf);
			fclose (f);
			return (1);
		}
	}
	fclose (f);
	return (0);
}

/*
**	searches the buffer looking for a string flag
*/

char	*mgetstr (id, area, bfr)
register char	*id;
register char	**area;
char		*bfr;
{
	register char	*str = *area;		/* start of current string		*/
	register char	*cp = bfr;

	if (bfr == (char *) 0)			/* has a valid buffer been passed?	*/
		return ((char *) 0);		/* ... no, can't find string	*/

	while (*cp != ':' && *cp != 0)		/* find first entry in cap		*/
		cp++;

	if (*cp == 0)				/* empty entry???			*/
		return ((char *) 0);			/* ... yes, bad acucap entry		*/
	else
		cp++;				/* point to first character in next	*/

	while (*cp != 0) {			/* until entry found or end of entry	*/
		if (strncmp(cp,id, strlen(id)) == 0) {
			if (cp[strlen(id)] != '=')	/* is it a string value???		*/
				return ((char *) 0);	/* no, something else			*/
			else
				break;		/* yes, entry was found			*/
		} else {			/* not entry, skip this entire entry	*/
			while (*cp != ':' && *cp != 0)
				cp++;		/* search for end of current entry	*/

			if (*cp != 0)
				cp++;		/* skip terminating character		*/
		}
	}
	if (*cp == 0)				/* end of buffer	*/
		return ((char *) 0);

	cp += strlen(id) + 1;			/* point to actual string		*/
	while (*cp != ':' && *cp != 0) {	/* for every character in string ...	*/
		if (*cp == '\\') {		/* translate escaped character		*/
			cp++;
			switch (*cp) {
				case 'n':	/* newline			*/
					**area = '\n';
					(*area)++;
					cp++;
					break;
				case 'r':	/* carriage return		*/
					**area = '\r';
					(*area)++;
					cp++;
					break;
				case 'b':	/* backspace			*/
					**area = '\b';
					(*area)++;
					cp++;
					break;
				case 'f':	/* form feed			*/
					**area = '\f';
					(*area)++;
					cp++;
					break;
				case 't':	/* tab				*/
					**area = '\t';
					(*area)++;
					cp++;
					break;
				case 'E':	/* Escape character		*/
					**area = 033;
					(*area)++;
					cp++;
					break;
				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
					**area = ((cp[0] - '0') << 6) +
						 ((cp[1] - '0') << 3) +
						  (cp[2] - '0');
					(*area)++;
					cp += 3;
					break;
				default:
					**area = *cp++;
					(*area)++;
					break;
			}
		} else if (*cp == '^') {	/* some control character		*/
			cp++;
			if (*cp >= '@' && *cp <= '_') {
				**area = *cp - '@';
				(*area)++;
			}
			cp++;
		} else {			/* some normal character		*/
			**area = *cp++;		/* put character in area		*/
			(*area)++;
		}
	}
	*((*area)++) = 0;			/* null terminate area and string	*/
	return (str);				/* return pointer to start of string	*/
}

#endif

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.