/************************************************************************
 *									*
 *			Copyright (c) 1982, Fred Fish			*
 *			    All Rights Reserved				*
 *									*
 *	This software and/or documentation is released for public	*
 *	distribution for personal, non-commercial use only.		*
 *	Limited rights to use, modify, and redistribute are hereby	*
 *	granted for non-commercial purposes, provided that all		*
 *	copyright notices remain intact and all changes are clearly	*
 *	documented.  The author makes no warranty of any kind with	*
 *	respect to this product and explicitly disclaims any implied	*
 *	warranties of merchantability or fitness for any particular	*
 *	purpose.							*
 *									*
 ************************************************************************
 */


/*
 *  LIBRARY FUNCTION
 *
 *	tgetent   load buffer with entry for specified terminal
 *
 *  KEY WORDS
 *
 *	termcap functions
 *	utility routines
 *
 *  SYNOPSIS
 *
 *	int tgetent(bp,name)
 *	char *bp;
 *	char *name;
 *
 *  DESCRIPTION
 *
 *	Extracts the entry for terminal <name> from the termcap file
 *	and places it in the character buffer <bp>.   It is currently
 *	assumed that bp is at least 1024 characters.  If the entry in
 *	the termcap file is larger than 1023 characters the excess
 *	characters will be discarded and appropriate status will
 *	be returned.
 *
 *	Also note that since bp is used by other termcap
 *	routines, the storage associated with the termcap entry
 *	cannot be freed until all termcap calls are completed.
 *
 *	Tgetent can be directed to look in a file other than
 *	the default (/etc/termcap) by defining an environment
 *	variable called TERMCAP to be the pathname of the desired
 *	termcap file.  This is useful for debugging new entries.
 *	NOTE: the pathname MUST begin with a '/' character.
 *      (Atari ST specific change: the pathname may begin with '\',
 *       or with a drive letter followed by ':').
 *
 *	Also, if the string assigned to TERMCAP does not begin with
 *	a '/' and if the environment variable TERM matches <name> then
 *	the string assigned to TERMCAP is copied to buffer <bp> 
 *	instead of reading a termcap file.
 *      (Atari ST specific change: TERM is no longer checked (the
 *       check was buggy).
 *
 *	Modification by ERS: if no termcap file can be found, then
 *	a default termcap is used (this is for GEMDOS).
 *	
 *  RETURNS
 *
 *	-1  if the termcap file cannot be opened
 *	 0  if no entry in termcap file matches <name>
 *	 1  if extraction is successful with no errors
 *	 2  if extraction is successful but entry truncated
 *
 *  SEE ALSO
 *
 *	tgetnum   extract numeric type capability
 *	tgetflag  test boolean type capability
 *	tgetstr   get string value of capability
 *
 *  AUTHOR
 *
 *	Fred Fish
 *
 */

#include <stdio.h>
#include <string.h>
#include <termcap.h>

#ifndef _COMPILER_H
#  include <compiler.h>
#endif

#define TRUE 1
#define FALSE 0
#define BUFSIZE 1024			/* Assumed size of external buffer */

#define NO_FILE	 -1			/* Returned if can't open file */
#define NO_ENTRY  0			/* Returned if can't find entry */
#define SUCCESS   1			/* Returned if entry found ok */
#define TRUNCATED 2			/* Returned if entry found but trunc */

# ifdef DGK
# define DEFAULT_ROOT "termcap"		/* name without path component */
  static FILE *fopenp __PROTO((char *name, char *mode, char *pathname));
# define DEFAULT_FILE "\\etc\\termcap"
# else
# define DEFAULT_FILE "/etc/termcap"	/* default termcap filename */
# endif
__EXTERN char *fgetlr __PROTO((char *bp, int bpsize, FILE *fp));
static FILE *find_file __PROTO((char *));
static int gotcha __PROTO((char *bp, char *name));

char *_tcpbuf;				/* Place to remember buffer pointer */

/*
 *  PSEUDO CODE
 *
 *	Begin tgetent
 *	    Erase any previous buffer contents.
 *	    Remember the buffer pointer.
 *	    If termcap file is not found then
 *		If buffer was filled anyway then
 *		    Return SUCCESS.
 *		Else
 *		    Return NO_FILE.
 *		End if
 *	    Else
 *		While records left to process
 *		    If this is entry is what we want then
 *			Close the termcap file.
 *			If entry was truncated then
 *			    Return TRUNCATED status
 *			Else
 *			    Return SUCCESS status.
 *			End if
 *		    End if
 *		End while
 *		Return NO_ENTRY status.
 *	    End if
 *	End tgetent
 *			
 */

int tgetent(bp,name)
char *bp;				/* Pointer to buffer (1024 char min) */
char *name;				/* Pointer to terminal entry to find */
{
    FILE *fp;

    *bp = '\0';
    _tcpbuf = bp;
    if ((fp = find_file(bp)) == NULL) {
	if (*bp != '\0') {
	    return(SUCCESS);
	} else {
	    return(NO_FILE);
	}
    } else {
	while (fgetlr(bp,BUFSIZE,fp)) {
	    if (gotcha(bp,name)) {
		fclose(fp);
		if (bp[(int)strlen(bp)-1] != '\n') {
		    return(TRUNCATED);
		} else {
		    return(SUCCESS);
		}
	    }
	}
	return(NO_ENTRY);
    }
}

/*
 *  INTERNAL FUNCTION
 *
 *	find_file    find the termcap file and open it if possible
 *
 *  KEY WORDS
 *
 *	internal functions
 *	find_file
 *
 *  SYNOPSIS
 *
 *	static FILE *find_file(bp)
 *	char *bp;
 *
 *  DESCRIPTION
 *
 *	Attempts to locate and open the termcap file.  Also handles
 *	using the environment TERMCAP string as the actual buffer
 *	(that's why bp has to be an input parameter).
 *
 *	If TERMCAP is defined an begins with a '/' character then
 *	it is taken to be the pathname of the termcap file and
 *	an attempt is made to open it.  If this fails then
 *	the default termcap file is used instead.
 *
 *	If TERMCAP is defined but does not begin with a '/' then
 *	it is assumed to be the actual buffer contents provided
 *	that <name> matches the environment variable TERM.
 *
 *  BUGS
 *
 *	There is currently no way to be sure which termcap
 *	file was opened since the default will always be
 *	tried.
 *
 */

/*
 *  PSEUDO CODE
 *
 *	Begin find_file
 *	    If there is a TERMCAP environment string then
 *		If the string is not null then
 *		    If the string is a pathname then
 *			If that file is opened successfully then
 *			    Return its pointer.
 *			End if
 *		    Else
 *			If there is a TERM environment string then
 *			    If TERM matches <name> then
 *				Copy TERMCAP string to buffer.
 *				Return NULL for no file.
 *			    End if
 *			End if
 *		    End if
 *		End if
 *	    End if
 *	    Open default termcap file and return results.
 *	End find_file
 *
 */

static char term_default[] = "df|default|Atari default\
:al=\\EL:am:bs:cd=\\EJ:ce=\\EK:cl=\\EE:cm=\\EY%+ %+ :co#80:dl=\\EM\
:do=\\EB:eo:ho=\\EH:is=\\Eq\\EE\\Ee\\Ev:it#8:le=^H:li#25:ll=\\EY9!\
:me=\\Eq:mr=\\Ep:nd=\\EC:rc=\\Ek:sc=\\Ej:se=\\Eq:so=\\Ep:ta=^I\
:up=\\EA:ve=\\Ee:vi=\\Ef:";

static FILE *find_file(bp)
char *bp;
{
    FILE *fp;
    char *cp, *ncp;
    __EXTERN char *getenv __PROTO((const char *));

    if ((cp = getenv("TERMCAP")) != NULL) {
	if (*cp != '\0') {
	    if (*cp == '/' || *cp == '\\' || (cp[1] == ':')) {
		if ((fp = fopen(cp,"r")) != NULL) {
		    return(fp);
		}
	    } else {
		if ((ncp = getenv("TERM")) != NULL) {
			strcpy(bp,cp);
			return((FILE *)NULL);
		}
	    }
	}
    }
# ifdef DGK
	/* Try current directory, then /etc/termcap, then along the path
	 */
	if (fp = fopen(DEFAULT_ROOT, "r"))
		return fp;
	else if (fp = fopen(DEFAULT_FILE, "r"))
		return fp;
	else if (fp = fopenp(DEFAULT_ROOT, "r", NULL))
		return fp;
	else {
#  ifdef GEMDOS
		strcpy (bp, term_default);
#  endif
		return (FILE *) NULL;
	}
# else
    return(fopen(DEFAULT_FILE,"r"));
# endif
}

/*
 *  INTERNAL FUNCTION
 *
 *	gotcha   test to see if entry is for specified terminal
 *
 *  SYNOPSIS
 *
 *	gotcha(bp,name)
 *	char *bp;
 *	char *name;
 *
 *  DESCRIPTION
 *
 *	Tests to see if the entry in buffer bp matches the terminal
 *	specified by name.  Returns TRUE if match is detected, FALSE
 *	otherwise.
 *
 */

/*
 *  PSEUDO CODE
 *
 *	Begin gotcha
 *	    If buffer character is comment character then
 *		Return FALSE since remainder is comment
 *	    Else
 *		Initialize name scan pointer.
 *		Compare name and buffer until end or mismatch.
 *		If valid terminators for both name and buffer strings
 *		    Return TRUE since a match was found.
 *		Else
 *		    Find next non-name character in buffer.
 *		    If not an alternate name separater character
 *			Return FALSE since no more names to check.
 *		    Else
 *			Test next name and return results.
 *		    End if
 *		End if
 *	    End if
 *	End gotcha
 *
 */

static int gotcha(bp,name)
char *bp;
char *name;
{
    char *np;
 
    if (*bp == '#') {
	return(FALSE);
    } else {
	np = name;
	while (*np == *bp && *np != '\0') {np++; bp++;}
	if (*np == '\0' && (*bp == '\0' || *bp == '|' || *bp == ':')) {
	    return(TRUE);
	} else {
	    while (*bp != '\0' && *bp != ':' && *bp != '|') {bp++;}
	    if (*bp != '|') {
		return(FALSE);
	    } else {
		return(gotcha(++bp,name));
	    }
	}
    }
}

#ifdef DGK
# ifdef MSDOS
# define PATHSEP ';'
# endif
# ifdef GEMDOS
# define PATHSEP ','
# endif

/* Follow the PATH, trying to fopen the file.  Takes one additional
 * argument which can be NULL.  Otherwise this argument gets filled
 * in the full path to the file.  Returns as does fopen().
 */
static FILE *
fopenp(name, mode, pathname)
char *name, *mode, *pathname;
{
	char buffer[BUFSIZ], *buf, *bufp, *pathp, lastch;
	FILE *fp;
	__EXTERN char *getenv __PROTO((const char *));

	/* If pathname is given, use it instead of buf so the calling
	 * process knows the path we found name under
	 */
	if (pathname)
		buf = pathname;
	else
		buf = buffer;

	strcpy(buf, name);
	pathp = getenv("PATH");
	while (pathp && *pathp) {
		bufp = buf;
		while (*pathp && *pathp != PATHSEP)
			lastch = *bufp++ = *pathp++;
		if (lastch != '\\')
			*bufp++ = '\\';
		strcpy(bufp, name);
		if (fp = fopen(buf, mode))
			return fp;
		if (*pathp)
			pathp++;
	}
	return NULL;
}
#endif
