Subject:  Terminfo/Curses Part 4 of 11

: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
if test ! -d =src
then
    echo 'Making directory "=src"'
    mkdir =src
fi
echo 'x - =src/comp_captab.c'
sed 's/^X//' <<'//go.sysin dd *' >=src/comp_captab.c
X/*
 *	comp_captab.c -- The names of the capabilities in a form ready for
 *		         the making of a hash table for the compiler.
 *
 */


#include "compiler.h"
#include "term.h"


struct name_table_entry	cap_table[] =
{
	0,           "bw",	BOOLEAN,	  0,
	0,           "am",	BOOLEAN,	  1,
	0,          "xsb",	BOOLEAN,	  2,
	0,          "xhp",	BOOLEAN,	  3,
	0,         "xenl",	BOOLEAN,	  4,
	0,           "eo",	BOOLEAN,	  5,
	0,           "gn",	BOOLEAN,	  6,
	0,           "hc",	BOOLEAN,	  7,
	0,           "km",	BOOLEAN,	  8,
	0,           "hs",	BOOLEAN,	  9,
	0,           "in",	BOOLEAN,	 10,
	0,           "da",	BOOLEAN,	 11,
	0,           "db",	BOOLEAN,	 12,
	0,          "mir",	BOOLEAN,	 13,
	0,         "msgr",	BOOLEAN,	 14,
	0,           "os",	BOOLEAN,	 15,
	0,        "eslok",	BOOLEAN,	 16,
	0,           "xt",	BOOLEAN,	 17,
	0,           "hz",	BOOLEAN,	 18,
	0,           "ul",	BOOLEAN,	 19,
	0,          "xon",	BOOLEAN,	 20,
	0,         "cols",	NUMBER,		  0,
	0,           "it",	NUMBER,		  1,
	0,        "lines",	NUMBER,		  2,
	0,           "lm",	NUMBER,		  3,
	0,          "xmc",	NUMBER,		  4,
	0,           "pb",	NUMBER,		  5,
	0,           "vt",	NUMBER,		  6,
	0,          "wsl",	NUMBER,		  7,
	0,         "nlab",	NUMBER,		  8,
	0,           "lh",	NUMBER,		  9,
	0,           "lw",	NUMBER,		 10,
	0,          "cbt",	STRING,		  0,
	0,          "bel",	STRING,		  1,
	0,           "cr",	STRING,		  2,
	0,          "csr",	STRING,		  3,
	0,          "tbc",	STRING,		  4,
	0,        "clear",	STRING,		  5,
	0,           "el",	STRING,		  6,
	0,           "ed",	STRING,		  7,
	0,          "hpa",	STRING,		  8,
	0,           "CC",	STRING,		  9,
	0,          "cup",	STRING,		 10,
	0,         "cud1",	STRING,		 11,
	0,         "home",	STRING,		 12,
	0,        "civis",	STRING,		 13,
	0,         "cub1",	STRING,		 14,
	0,        "mrcup",	STRING,		 15,
	0,        "cnorm",	STRING,		 16,
	0,         "cuf1",	STRING,		 17,
	0,           "ll",	STRING,		 18,
	0,         "cuu1",	STRING,		 19,
	0,        "cvvis",	STRING,		 20,
	0,         "dch1",	STRING,		 21,
	0,          "dl1",	STRING,		 22,
	0,          "dsl",	STRING,		 23,
	0,           "hd",	STRING,		 24,
	0,        "smacs",	STRING,		 25,
	0,        "blink",	STRING,		 26,
	0,         "bold",	STRING,		 27,
	0,        "smcup",	STRING,		 28,
	0,         "smdc",	STRING,		 29,
	0,          "dim",	STRING,		 30,
	0,         "smir",	STRING,		 31,
	0,        "invis",	STRING,		 32,
	0,         "prot",	STRING,		 33,
	0,          "rev",	STRING,		 34,
	0,         "smso",	STRING,		 35,
	0,         "smul",	STRING,		 36,
	0,          "ech",	STRING,		 37,
	0,        "rmacs",	STRING,		 38,
	0,         "sgr0",	STRING,		 39,
	0,        "rmcup",	STRING,		 40,
	0,         "rmdc",	STRING,		 41,
	0,         "rmir",	STRING,		 42,
	0,         "rmso",	STRING,		 43,
	0,         "rmul",	STRING,		 44,
	0,        "flash",	STRING,		 45,
	0,           "ff",	STRING,		 46,
	0,          "fsl",	STRING,		 47,
	0,          "is1",	STRING,		 48,
	0,          "is2",	STRING,		 49,
	0,          "is3",	STRING,		 50,
	0,           "if",	STRING,		 51,
	0,         "ich1",	STRING,		 52,
	0,          "il1",	STRING,		 53,
	0,           "ip",	STRING,		 54,
	0,          "kbs",	STRING,		 55,
	0,         "ktbc",	STRING,		 56,
	0,         "kclr",	STRING,		 57,
	0,        "kctab",	STRING,		 58,
	0,        "kdch1",	STRING,		 59,
	0,         "kdl1",	STRING,		 60,
	0,        "kcud1",	STRING,		 61,
	0,        "krmir",	STRING,		 62,
	0,          "kel",	STRING,		 63,
	0,          "ked",	STRING,		 64,
	0,          "kf0",	STRING,		 65,
	0,          "kf1",	STRING,		 66,
	0,         "kf10",	STRING,		 67,
	0,          "kf2",	STRING,		 68,
	0,          "kf3",	STRING,		 69,
	0,          "kf4",	STRING,		 70,
	0,          "kf5",	STRING,		 71,
	0,          "kf6",	STRING,		 72,
	0,          "kf7",	STRING,		 73,
	0,          "kf8",	STRING,		 74,
	0,          "kf9",	STRING,		 75,
	0,        "khome",	STRING,		 76,
	0,        "kich1",	STRING,		 77,
	0,         "kil1",	STRING,		 78,
	0,        "kcub1",	STRING,		 79,
	0,          "kll",	STRING,		 80,
	0,          "knp",	STRING,		 81,
	0,          "kpp",	STRING,		 82,
	0,        "kcuf1",	STRING,		 83,
	0,         "kind",	STRING,		 84,
	0,          "kri",	STRING,		 85,
	0,         "khts",	STRING,		 86,
	0,        "kcuu1",	STRING,		 87,
	0,         "rmkx",	STRING,		 88,
	0,         "smkx",	STRING,		 89,
	0,          "lf0",	STRING,		 90,
	0,          "lf1",	STRING,		 91,
	0,         "lf10",	STRING,		 92,
	0,          "lf2",	STRING,		 93,
	0,          "lf3",	STRING,		 94,
	0,          "lf4",	STRING,		 95,
	0,          "lf5",	STRING,		 96,
	0,          "lf6",	STRING,		 97,
	0,          "lf7",	STRING,		 98,
	0,          "lf8",	STRING,		 99,
	0,          "lf9",	STRING,		100,
	0,          "rmm",	STRING,		101,
	0,          "smm",	STRING,		102,
	0,          "nel",	STRING,		103,
	0,          "pad",	STRING,		104,
	0,          "dch",	STRING,		105,
	0,           "dl",	STRING,		106,
	0,          "cud",	STRING,		107,
	0,          "ich",	STRING,		108,
	0,         "indn",	STRING,		109,
	0,           "il",	STRING,		110,
	0,          "cub",	STRING,		111,
	0,          "cuf",	STRING,		112,
	0,          "rin",	STRING,		113,
	0,          "cuu",	STRING,		114,
	0,        "pfkey",	STRING,		115,
	0,        "pfloc",	STRING,		116,
	0,          "pfx",	STRING,		117,
	0,          "mc0",	STRING,		118,
	0,          "mc4",	STRING,		119,
	0,          "mc5",	STRING,		120,
	0,          "rep",	STRING,		121,
	0,          "rs1",	STRING,		122,
	0,          "rs2",	STRING,		123,
	0,          "rs3",	STRING,		124,
	0,           "rf",	STRING,		125,
	0,           "rc",	STRING,		126,
	0,          "vpa",	STRING,		127,
	0,           "sc",	STRING,		128,
	0,          "ind",	STRING,		129,
	0,           "ri",	STRING,		130,
	0,          "sgr",	STRING,		131,
	0,          "hts",	STRING,		132,
	0,         "wind",	STRING,		133,
	0,           "ht",	STRING,		134,
	0,          "tsl",	STRING,		135,
	0,           "uc",	STRING,		136,
	0,           "hu",	STRING,		137,
	0,        "iprog",	STRING,		138,
	0,          "ka1",	STRING,		139,
	0,          "ka3",	STRING,		140,
	0,          "kb2",	STRING,		141,
	0,          "kc1",	STRING,		142,
	0,          "kc3",	STRING,		143,
	0,         "mc5p",	STRING,		144,
	0,          "rmp",	STRING,		145,
	0,         "acsc",	STRING,		146,
	0,          "pln",	STRING,		147,
};

struct name_table_entry *cap_hash_table[360];

int	Hashtabsize = 360;
int	Captabsize = 180;


#if (BOOLCOUNT!=21)||(NUMCOUNT!=11)||(STRCOUNT!=148)
	--> term.h and comp_captab.c disagree about the <--
	--> numbers of booleans, numbers and/or strings <--
#endif
//go.sysin dd *
echo 'x - =src/comp_error.c'
sed 's/^X//' <<'//go.sysin dd *' >=src/comp_error.c
X/*********************************************************************
*                         COPYRIGHT NOTICE                           *
**********************************************************************
*        This software is copyright (C) 1982 by Pavel Curtis         *
*                                                                    *
*        Permission is granted to reproduce and distribute           *
*        this file by any means so long as no fee is charged         *
*        above a nominal handling fee and so long as this            *
*        notice is always included in the copies.                    *
*                                                                    *
*        Other rights are reserved except as explicitly granted      *
*        by written permission of the author.                        *
*                Pavel Curtis                                        *
*                Computer Science Dept.                              *
*                405 Upson Hall                                      *
*                Cornell University                                  *
*                Ithaca, NY 14853                                    *
*                                                                    *
*                Ph- (607) 256-4934                                  *
*                                                                    *
*                Pavel.Cornell@Udel-Relay   (ARPAnet)                *
*                decvax!cornell!pavel       (UUCPnet)                *
*********************************************************************/

X/*
 *	comp_error.c -- Error message routines
 *
 *  $Log:	RCS/comp_error.v $
 * Revision 2.1  82/10/25  14:45:31  pavel
 * Added Copyright Notice
 * 
 * Revision 2.0  82/10/24  15:16:32  pavel
 * Beta-one Test Release
 * 
 * Revision 1.3  82/08/23  22:29:31  pavel
 * The REAL Alpha-one Release Version
 * 
 * Revision 1.2  82/08/19  19:09:44  pavel
 * Alpha Test Release One
 * 
 * Revision 1.1  82/08/12  18:36:02  pavel
 * Initial revision
 * 
 *
 */

static char RCSid[] =
	"$Header:   RCS/comp_error.v  Revision 2.1  82/10/25  14:45:31  pavel  Exp$";

#include "compiler.h"

extern char *string_table;
extern short term_names;

warning(fmt, a1, a2, a3, a4, a5, a6)
char	*fmt, *a1, *a2, *a3, *a4, *a5, *a6;
{
    fprintf (stderr, "compile: Warning: near line %d: ", curr_line);
    fprintf (stderr, "terminal '%s', ", string_table+term_names);
    fprintf (stderr, fmt, a1, a2, a3, a4, a5, a6);
    fprintf (stderr, "\n");
}


err_abort(fmt, a1, a2, a3, a4, a5, a6)
char	*fmt, *a1, *a2, *a3, *a4, *a5, *a6;
{
    fprintf (stderr, "compile: Line %d: ", curr_line);
    fprintf (stderr, "terminal '%s', ", string_table+term_names);
    fprintf (stderr, fmt, a1, a2, a3, a4, a5, a6);
    fprintf (stderr, "\n");
    exit(1);
}


syserr_abort(fmt, a1, a2, a3, a4, a5, a6)
char	*fmt, *a1, *a2, *a3, *a4, *a5, *a6;
{
    fprintf (stderr, "PROGRAM ERROR: Line %d: ", curr_line);
    fprintf (stderr, "terminal '%s', ", string_table+term_names);
    fprintf (stderr, fmt, a1, a2, a3, a4, a5, a6);
    fprintf (stderr, "\n");
    abort();
}
//go.sysin dd *
echo 'x - =src/comp_hash.c'
sed 's/^X//' <<'//go.sysin dd *' >=src/comp_hash.c
X/*********************************************************************
*                         COPYRIGHT NOTICE                           *
**********************************************************************
*        This software is copyright (C) 1982 by Pavel Curtis         *
*                                                                    *
*        Permission is granted to reproduce and distribute           *
*        this file by any means so long as no fee is charged         *
*        above a nominal handling fee and so long as this            *
*        notice is always included in the copies.                    *
*                                                                    *
*        Other rights are reserved except as explicitly granted      *
*        by written permission of the author.                        *
*                Pavel Curtis                                        *
*                Computer Science Dept.                              *
*                405 Upson Hall                                      *
*                Cornell University                                  *
*                Ithaca, NY 14853                                    *
*                                                                    *
*                Ph- (607) 256-4934                                  *
*                                                                    *
*                Pavel.Cornell@Udel-Relay   (ARPAnet)                *
*                decvax!cornell!pavel       (UUCPnet)                *
*********************************************************************/

X/*
 *	comp_hash.c --- Routines to deal with the hashtable of capability
 *			names.
 *
 *  $Log:	RCS/comp_hash.v $
 * Revision 2.1  82/10/25  14:45:34  pavel
 * Added Copyright Notice
 * 
 * Revision 2.0  82/10/24  15:16:34  pavel
 * Beta-one Test Release
 * 
 * Revision 1.3  82/08/23  22:29:33  pavel
 * The REAL Alpha-one Release Version
 * 
 * Revision 1.2  82/08/19  19:09:46  pavel
 * Alpha Test Release One
 * 
 * Revision 1.1  82/08/12  18:36:23  pavel
 * Initial revision
 * 
 *
 */

static char RCSid[] =
	"$Header:   RCS/comp_hash.v  Revision 2.1  82/10/25  14:45:34  pavel  Exp$";

#include "compiler.h"
#include "term.h"



X/*
 *	make_hash_table()
 *
 *	Takes the entries in cap_table[] and hashes them into cap_hash_table[]
 *	by name.  There are Captabsize entries in cap_table[] and Hashtabsize
 *	slots in cap_hash_table[].
 *
 */

make_hash_table()
{
	int	i;
	int	hashvalue;
	int	collisions = 0;

	for (i=0; i < Captabsize; i++)
	{
	    hashvalue = hash_function(cap_table[i].nte_name);       
	    DEBUG(9, "%d\n", hashvalue);

	    if (cap_hash_table[hashvalue] != (struct name_table_entry *) 0)
		collisions++;

	    cap_table[i].nte_link = cap_hash_table[hashvalue];
	    cap_hash_table[hashvalue] = &cap_table[i];
	}

	DEBUG(3, "Hash table complete\n%d collisions ", collisions);
	DEBUG(3, "out of %d entries\n", Captabsize);
}



X/*
 *	int hash_function(string)
 *
 *	Computes the hashing function on the given string.
 *
 *	The current hash function is the sum of each consectutive pair
 *	of characters, taken as two-byte integers, mod Hashtabsize.
 *
 */

static
int
hash_function(string)
char	*string;
{
	long	sum = 0;

	while (*string)
	{
	    sum += *string + (*(string + 1) << 8);
	    string++;
	}

	return (sum % Hashtabsize);
}



X/*
 *	struct name_table_entry *
 *	find_entry(string)
 *
 *	Finds the entry for the given string in the hash table if present.
 *	Returns a pointer to the entry in the table or 0 if not found.
 *
 */

struct name_table_entry *
find_entry(string)
char	*string;
{
	int	hashvalue;
	struct name_table_entry	*ptr;

	hashvalue = hash_function(string);

	ptr = cap_hash_table[hashvalue];

	while (ptr != (struct name_table_entry *) 0  &&
			       	           strcmp(ptr->nte_name, string) != 0)
	    ptr = ptr->nte_link;

	return (ptr);
}
//go.sysin dd *
echo 'x - =src/comp_main.c'
sed 's/^X//' <<'//go.sysin dd *' >=src/comp_main.c
X/*********************************************************************
*                         COPYRIGHT NOTICE                           *
**********************************************************************
*        This software is copyright (C) 1982 by Pavel Curtis         *
*                                                                    *
*        Permission is granted to reproduce and distribute           *
*        this file by any means so long as no fee is charged         *
*        above a nominal handling fee and so long as this            *
*        notice is always included in the copies.                    *
*                                                                    *
*        Other rights are reserved except as explicitly granted      *
*        by written permission of the author.                        *
*                Pavel Curtis                                        *
*                Computer Science Dept.                              *
*                405 Upson Hall                                      *
*                Cornell University                                  *
*                Ithaca, NY 14853                                    *
*                                                                    *
*                Ph- (607) 256-4934                                  *
*                                                                    *
*                Pavel.Cornell@Udel-Relay   (ARPAnet)                *
*                decvax!cornell!pavel       (UUCPnet)                *
*********************************************************************/

X/*
 *	comp_main.c --- Main program for terminfo compiler
 *
 *  $Log:	RCS/comp_main.v $
 * Revision 2.1  82/10/25  14:45:37  pavel
 * Added Copyright Notice
 * 
 * Revision 2.0  82/10/24  15:16:37  pavel
 * Beta-one Test Release
 * 
 * Revision 1.3  82/08/23  22:29:36  pavel
 * The REAL Alpha-one Release Version
 * 
 * Revision 1.2  82/08/19  19:09:49  pavel
 * Alpha Test Release One
 * 
 * Revision 1.1  82/08/12  18:36:55  pavel
 * Initial revision
 * 
 *
 */

static char RCSid[] =
	"$Header:   RCS/comp_main.v  Revision 2.1  82/10/25  14:45:37  pavel  Exp$";


#include <sys/types.h>
#include <sys/stat.h>
#include "compiler.h"

char	*source_file = "/etc/terminfo";
char	*destination = SRCDIR;
char	*usage_string = "\tcompile [-v[n]] source-file\n";
char	check_only = 0;


main (argc, argv)
int	argc;
char	*argv[];
{
	int	i;
	int	argflag = FALSE;

	debug_level = 0;

	for (i=1; i < argc; i++)
	{
	    if (argv[i][0] == '-')
	    {
		switch (argv[i][1])
		{
		    case 'c':
			check_only = 1;
			break;

		    case 'v':
			debug_level = argv[i][2]  ?  atoi(&argv[i][2])  :  1;
			break;

		    default:
			fprintf(stderr, "%s: Unknown option. Usage is:\n\t%s\n",
						       argv[0], usage_string);
			exit(1);
		}
	    }
	    else if (argflag)
	    {
		fprintf(stderr, "%s: Too many file names.  Usage is:\n\t%s\n",
							argv[0], usage_string);
		exit(1);
	    }
	    else
	    {
		argflag = TRUE;
		source_file = argv[i];
	    }
	}

	init(argv[0]);
	make_hash_table();
	compile();

	exit(0);
}




X/*
 *	init(progname)
 *
 *	Miscelaneous initialisations
 *
 *	Open source file as standard input
 *	Check for access rights to destination directories
 *	Create any directories which don't exist.
 *
 */

init(progname)
char	*progname;
{
	struct stat	statbuf;
	char		*dirnames = "abcdefghijklmnopqrstuvwxyz0123456789";
	char		*getenv();
	char		dir[2];

	start_time = time(0);

	curr_line = 0;

	if (freopen(source_file, "r", stdin) == NULL)
	{
	    fprintf(stderr, "%s: Can't open %s\n", progname, source_file);
	    exit(1);
	}

	if (getenv("TERMINFO") != NULL)
	    destination = getenv("TERMINFO");

	if (access(destination, 7) < 0)
	{
	    fprintf(stderr, "%s: %s non-existant or permission denied\n",
							progname, destination);
	    exit(1);
	}

	if (chdir(destination) < 0)
	{
	    fprintf(stderr, "%s: %s is not a directory\n",
							progname, destination);
	    exit(1);
	}
	
	dir[1] = '\0';
	for (dir[0] = *dirnames; *dirnames != '\0'; dir[0] = *(++dirnames))
	{
	    if (stat(dir, &statbuf) < 0)
	    {
		mkdir(dir);
		chmod(dir, 0755);
	    }
	    else if (access(dir, 7) < 0)
	    {
		fprintf(stderr, "%s: %s/%s: Permission denied\n",
						    progname, destination, dir);
		exit(1);
	    }
	    else if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
	    {
		fprintf(stderr, "%s: %s/%s: Not a directory\n",
						    progname, destination, dir);
		exit(1);
	    }
	}
}



X/*
 *	mkdir(dirname)
 *
 *	forks and execs the mkdir program to create the given directory
 *
 */

mkdir(dirname)
char	*dirname;
{
	int	fork_rtn;
	int	status;

	fork_rtn = fork();

	switch (fork_rtn)
	{
	    case 0:		/* Child */
		execl("/bin/mkdir", "mkdir", dirname, 0);
		exit(1);

	    case -1:		/* Error */
		fprintf(stderr, "compile: SYSTEM ERROR!! Fork failed!!!\n");
		abort();

	    default:
		wait(&status);
		if (status != 0)
		    syserr_abort("mkdir returned bad status");
		break;
	}
}
//go.sysin dd *
echo 'x - =src/comp_parse.c'
sed 's/^X//' <<'//go.sysin dd *' >=src/comp_parse.c
X/*********************************************************************
*                         COPYRIGHT NOTICE                           *
**********************************************************************
*        This software is copyright (C) 1982 by Pavel Curtis         *
*                                                                    *
*        Permission is granted to reproduce and distribute           *
*        this file by any means so long as no fee is charged         *
*        above a nominal handling fee and so long as this            *
*        notice is always included in the copies.                    *
*                                                                    *
*        Other rights are reserved except as explicitly granted      *
*        by written permission of the author.                        *
*                Pavel Curtis                                        *
*                Computer Science Dept.                              *
*                405 Upson Hall                                      *
*                Cornell University                                  *
*                Ithaca, NY 14853                                    *
*                                                                    *
*                Ph- (607) 256-4934                                  *
*                                                                    *
*                Pavel.Cornell@Udel-Relay   (ARPAnet)                *
*                decvax!cornell!pavel       (UUCPnet)                *
*********************************************************************/

X/*
 *	comp_parse.c -- The high-level (ha!) parts of the compiler,
 *			that is, the routines which drive the scanner,
 *			etc.
 *
 *   $Log:	comp_parse.c,v $
 * Revision 3.1  84/12/13  11:19:32  john
 * Revisions by Mark Horton
 * 
 * Revision 2.1  82/10/25  14:45:43  pavel
 * Added Copyright Notice
 * 
 * Revision 2.0  82/10/24  15:16:39  pavel
 * Beta-one Test Release
 * 
 * Revision 1.3  82/08/23  22:29:39  pavel
 * The REAL Alpha-one Release Version
 * 
 * Revision 1.2  82/08/19  19:09:53  pavel
 * Alpha Test Release One
 * 
 * Revision 1.1  82/08/12  18:37:12  pavel
 * Initial revision
 * 
 *
 */

static char RCSid[] =
	"$Header: comp_parse.c,v 3.1 84/12/13 11:19:32 john Exp $";

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <ctype.h>
#include "compiler.h"
#include "term.h"
#include "object.h"


char	*string_table;
int	next_free;	/* next free character in string_table */
int	table_size = 0; /* current string_table size */
short	term_names;	/* string table offset - current terminal */
int	part2 = 0;	/* set to allow old compiled defns to be used */
int	complete = 0;	/* 1 if entry done with no forward uses */

struct use_item
{
	long	offset;
	struct use_item	*fptr, *bptr;
};

struct use_header
{
	struct use_item	*head, *tail;
};

struct use_header	use_list = {NULL, NULL};
int			use_count = 0;

X/*
 *  The use_list is a doubly-linked list with NULLs terminating the lists:
 *
 *	   use_item    use_item    use_item
 *	  ---------   ---------   ---------
 *	  |       |   |       |   |       |   offset
 *        |-------|   |-------|   |-------|
 *	  |   ----+-->|   ----+-->|  NULL |   fptr
 *	  |-------|   |-------|   |-------|
 *	  |  NULL |<--+----   |<--+----   |   bptr
 *	  ---------   ---------   ---------
 *	  ^                       ^
 *	  |  ------------------   |
 *	  |  |       |        |   |
 *	  +--+----   |    ----+---+
 *	     |       |        |
 *	     ------------------
 *	       head     tail
 *	          use_list
 *
 */


X/*
 *	compile()
 *
 *	Main loop of the compiler.
 *
 *	get_token()
 *	if curr_token != NAMES
 *	    err_abort()
 *	while (not at end of file)
 *	    do an entry
 *
 */

compile()
{
	char			line[1024];
	int			token_type;
	struct use_item	*ptr;
	int			old_use_count;

	token_type = get_token();

	if (token_type != NAMES)
	    err_abort("File does not start with terminal names in column one");
	
	while (token_type != EOF)
	    token_type = do_entry(NULL);

	DEBUG(2, "Starting handling of forward USE's\n", "");

	for (part2=0; part2<2; part2++) {
	    old_use_count = -1;
	DEBUG(2, "\n\nPART %d\n\n", part2);
	    while (use_list.head != NULL  &&  old_use_count != use_count)
	    {
		old_use_count = use_count;
		for (ptr = use_list.tail; ptr != NULL; ptr = ptr->bptr)
		{
		    fseek(stdin, ptr->offset, 0);
		    reset_input();
		    if ((token_type = get_token()) != NAMES)
			syserr_abort("Token after a seek not NAMES");
		    (void) do_entry(ptr);
		    if (complete)
			dequeue(ptr);
		}

		for (ptr = use_list.head; ptr != NULL; ptr = ptr->fptr)
		{
		    fseek(stdin, ptr->offset, 0);
		    reset_input();
		    if ((token_type = get_token()) != NAMES)
			syserr_abort("Token after a seek not NAMES");
		    (void) do_entry(ptr);
		    if (complete)
			dequeue(ptr);
		}
		
		DEBUG(2, "Finished a pass through enqueued forward USE's\n", "");
	    }
	}

	if (use_list.head != NULL)
	{
	    fprintf(stderr, "\nError in following up use-links.  Either there is\n");
	    fprintf(stderr, "a loop in the links or they reference non-existant\n");
	    fprintf(stderr, "terminals.  The following is a list of the entries\n");
	    fprintf(stderr, "involved:\n\n");

	    for (ptr = use_list.head; ptr != NULL; ptr = ptr->fptr)
	    {
		fseek(stdin, ptr->offset, 0);
		fgets(line, 1024, stdin);
		fprintf(stderr, "%s", line);
	    }

	    exit(1);
	}
}

dump_list(str)
char *str;
{
	struct use_item *ptr;
	char line[512];

	fprintf(stderr, "dump_list %s\n", str);
	for (ptr = use_list.head; ptr != NULL; ptr = ptr->fptr)
	{
		fseek(stdin, ptr->offset, 0);
		fgets(line, 1024, stdin);
		fprintf(stderr, "ptr %x off %d bptr %x fptr %x str %s",
		ptr, ptr->offset, ptr->bptr, ptr->fptr, line);
	}
	fprintf(stderr, "\n");
}



X/*
 *	int
 *	do_entry(item_ptr)
 *
 *	Compile one entry.  During the first pass, item_ptr is NULL.  In pass
 *	two, item_ptr points to the current entry in the use_list.
 *
 *	found-forward-use = FALSE
 *	re-initialise internal arrays
 *	save names in string_table
 *	get_token()
 *	while (not EOF and not NAMES)
 *	    if found-forward-use
 *		do nothing
 *	    else if 'use'
 *		if handle_use() < 0
 *		    found-forward-use = TRUE
 *          else
 *	        check for existance and type-correctness
 *	        enter cap into structure
 *	        if STRING
 *	            save string in string_table
 *	    get_token()
 *      if ! found-forward-use
 *	    clear CANCELS out of the structure
 *	    dump compiled entry into filesystem
 *
 */

int
do_entry(item_ptr)
struct use_item	*item_ptr;
{
	long					entry_offset;
	int					i;
	register int				token_type;
	register struct name_table_entry	*entry_ptr;
	int					found_forward_use = FALSE;
	char					Booleans[BOOLCOUNT];
	short					Numbers[NUMCOUNT],
						Strings[STRCOUNT];

	init_structure(Booleans, Numbers, Strings);
	complete = 0;
	term_names = save_str(curr_token.tk_name);
	DEBUG(2, "Starting '%s'\n", curr_token.tk_name);
	entry_offset = curr_file_pos;

	for (token_type = get_token();
		token_type != EOF  &&  token_type != NAMES;
		token_type = get_token())
	{
	    if (found_forward_use)
		/* do nothing */ ;
	    else if (strcmp(curr_token.tk_name, "use") == 0)
	    {
		if (handle_use(item_ptr, entry_offset,
					Booleans, Numbers, Strings) < 0)
		    found_forward_use = TRUE;
	    }
	    else
	    {
		entry_ptr = find_entry(curr_token.tk_name);

		if (entry_ptr == NOTFOUND) {
		    warning("Unknown Capability - '%s'",
                                                          curr_token.tk_name);
		    continue;
		}


		if (token_type != CANCEL
                                        &&  entry_ptr->nte_type != token_type)
		    warning("Wrong type used for capability '%s'",
							  curr_token.tk_name);
		switch (token_type)
		{
		    case CANCEL:
			switch (entry_ptr->nte_type)
			{
			    case BOOLEAN:
				Booleans[entry_ptr->nte_index] = -2;
				break;

			    case NUMBER:
				Numbers[entry_ptr->nte_index] = -2;
				break;

			    case STRING:
				Strings[entry_ptr->nte_index] = -2;
				break;
			}
			break;
		
		    case BOOLEAN:
			Booleans[entry_ptr->nte_index] = TRUE;
			break;
		    
		    case NUMBER:
			Numbers[entry_ptr->nte_index] =
                                                      curr_token.tk_valnumber;
			break;

		    case STRING:
			Strings[entry_ptr->nte_index] =
                                            save_str(curr_token.tk_valstring);
			break;

		    default:
			warning("Unknown token type");
			panic_mode(',');
			continue;
		}
	    } /* end else cur_token.name != "use" */

	} /* endwhile (not EOF and not NAMES) */

	if (found_forward_use)
	    return(token_type);

	for (i=0; i < BOOLCOUNT; i++)
	{
	    if (Booleans[i] == -2)
		Booleans[i] = FALSE;
	}

	for (i=0; i < NUMCOUNT; i++)
	{
	    if (Numbers[i] == -2)
		Numbers[i] = -1;
	}

	for (i=0; i < STRCOUNT; i++)
	{
	    if (Strings[i] == -2)
		Strings[i] = -1;
	}

	dump_structure(term_names, Booleans, Numbers, Strings);

	complete = 1;
	return(token_type);
}




X/*
 *	enqueue(offset)
 *
 *      Put a record of the given offset onto the use-list.
 *
 */

enqueue(offset)
long	offset;
{
	struct use_item	*item;
	char			*malloc();

	item = (struct use_item *) malloc(sizeof(struct use_item));

	if (item == NULL)
	    syserr_abort("Not enough memory for use_list element");

	item->offset = offset;

	if (use_list.head != NULL)
	{
	    item->bptr = use_list.tail;
	    use_list.tail->fptr = item;
	    item->fptr = NULL;
	    use_list.tail = item;
	}
	else
	{
	    use_list.tail = use_list.head = item;
	    item->fptr = item->bptr = NULL;
	}

	use_count ++;
}




X/*
 *	dequeue(ptr)
 *
 *	remove the pointed-to item from the use_list
 *
 */

dequeue(ptr)
struct use_item	*ptr;
{
	if (ptr->fptr == NULL)
	    use_list.tail = ptr->bptr;
	else
	    (ptr->fptr)->bptr = ptr->bptr;

	if (ptr->bptr == NULL)
	    use_list.head = ptr->fptr;
	else
	    (ptr->bptr)->fptr = ptr->fptr;
	
	use_count --;
}



X/*
 *	dump_structure()
 *
 *	Save the compiled version of a description in the filesystem.
 *
 *	make a copy of the name-list
 *	break it up into first-name and all-but-last-name
 *	creat(first-name)
 *	write object information to first-name
 *	close(first-name)
 *      for each name in all-but-last-name
 *	    link to first-name
 *
 */

dump_structure(term_names, Booleans, Numbers, Strings)
short	term_names;
char	Booleans[];
short	Numbers[];
short	Strings[];
{
	struct stat	statbuf;
	FILE		*fp;
	char		name_list[1024];
	register char	*first_name, *other_names;
	register char	*ptr;
	char		filename[50];
	char		linkname[50];
	extern char check_only;

	strcpy(name_list, term_names + string_table);
	DEBUG(7, "Name list = '%s'\n", name_list);

	first_name = name_list;

	ptr = &name_list[strlen(name_list) - 1];
	other_names = ptr + 1;

	while (ptr > name_list  &&  *ptr != '|')
	    ptr--;

	if (ptr != name_list)
	{
	    *ptr = '\0';

	    for (ptr = name_list; *ptr != '\0'  &&  *ptr != '|'; ptr++)
		;
	    
	    if (*ptr == '\0')
		other_names = ptr;
	    else
	    {
		*ptr = '\0';
		other_names = ptr + 1;
	    }
	}

	if (check_only) {
		DEBUG(1, "Checked %s\n", first_name);
		return;
	}

	DEBUG(7, "First name = '%s'\n", first_name);
	DEBUG(7, "Other names = '%s'\n", other_names);

	if (strlen(first_name) > 100)
	    warning("'%s': terminal name too long.", first_name);

	check_name(first_name);

	sprintf(filename, "%c/%s", first_name[0], first_name);

	if (stat(filename, &statbuf) >= 0  &&  statbuf.st_mtime >= start_time)
	{
	    warning("'%s' defined in more than one entry.", first_name);
	    fprintf(stderr, "Entry being used is '%s'.\n",
			    (unsigned) term_names + string_table);
	}

	unlink(filename);
	fp = fopen(filename, "w");
	if (fp == NULL)
	{
	    perror(filename);
	    syserr_abort("Can't open %s/%s\n", destination, filename);
	}
	DEBUG(1, "Created %s\n", filename);

	if (write_object(fp, term_names, Booleans, Numbers, Strings) < 0)
	{
	    syserr_abort("Error in writing %s/%s", destination, filename);
	}
	fclose(fp);

	while (*other_names != '\0')
	{
	    ptr = other_names++;
	    while (*other_names != '|'  &&  *other_names != '\0')
		other_names++;

	    if (*other_names != '\0')
		*(other_names++) = '\0';

	    if (strlen(ptr) > 100)
	    {
		warning("'%s': terminal name too long.", ptr);
		continue;
	    }

	    sprintf(linkname, "%c/%s", ptr[0], ptr);

	    if (strcmp(filename, linkname) == 0)
	    {
		warning("Terminal name '%s' synonym for itself", first_name);
	    }
	    else if (stat(linkname, &statbuf) >= 0  &&
						statbuf.st_mtime >= start_time)
	    {
		warning("'%s' defined in more than one entry.", ptr);
		fprintf(stderr, "Entry being used is '%s'.\n",
			    (unsigned) term_names + string_table);
	    }
	    else
	    {
		unlink(linkname);
		if (link(filename, linkname) < 0)
		    syserr_abort("Can't link %s to %s", filename, linkname);
		DEBUG(1, "Linked %s\n", linkname);
	    }
	}
}




X/*
 *	int
 *	write_object(fp, term_names, Booleans, Numbers, Strings)
 *
 *	Write out the compiled entry to the given file.
 *	Return 0 if OK or -1 if not.
 *
 */

#define swap(x)		(((x >> 8) & 0377) + 256 * (x & 0377))

#define might_swap(x)	(must_swap()  ?  swap(x)  :  (x))


int
write_object(fp, term_names, Booleans, Numbers, Strings)
XFILE	*fp;
short	term_names;
char	Booleans[];
short	Numbers[];
short	Strings[];
{
    	struct header	header;
	char		*namelist;
	short		namelen;
	char		zero = '\0';
	int		i;

	namelist = term_names + string_table;
	namelen = strlen(namelist) + 1;

	if (must_swap())
	{
	    header.magic = swap(MAGIC);
	    header.name_size = swap(namelen);
	    header.bool_count = swap(BOOLCOUNT);
	    header.num_count = swap(NUMCOUNT);
	    header.str_count = swap(STRCOUNT);
	    header.str_size = swap(next_free);
	}
	else
	{
	    header.magic = MAGIC;
	    header.name_size = namelen;
	    header.bool_count = BOOLCOUNT;
	    header.num_count = NUMCOUNT;
	    header.str_count = STRCOUNT;
	    header.str_size = next_free;
	}

	if (fwrite(&header, sizeof(header), 1, fp) != 1
		||  fwrite(namelist, sizeof(char), namelen, fp) != namelen
		||  fwrite(Booleans, sizeof(char), BOOLCOUNT, fp) != BOOLCOUNT)
	    return(-1);
	
	if ((namelen+BOOLCOUNT) % 2 != 0  &&  fwrite(&zero, sizeof(char), 1, fp) != 1)
	    return(-1);

	if (must_swap())
	{
	    for (i=0; i < NUMCOUNT; i++)
		Numbers[i] = swap(Numbers[i]);
	    for (i=0; i < STRCOUNT; i++)
		Strings[i] = swap(Strings[i]);
	}

	if (fwrite(Numbers, sizeof(short), NUMCOUNT, fp) != NUMCOUNT
	       ||  fwrite(Strings, sizeof(short), STRCOUNT, fp) != STRCOUNT
	       ||  fwrite(string_table, sizeof(char), next_free, fp)
								  != next_free)
	    return(-1);

}



X/*
 *	check_name(name)
 *
 *	Generate an error message if given name does not begin with a
 *	digit or lower-case letter.
 *
 */

check_name(name)
char	*name;
{
	if (! isdigit(name[0])  &&  ! islower(name[0]))
	{
	    fprintf(stderr, "compile: Line %d: Illegal terminal name - '%s'\n",
							    curr_line, name);
	    fprintf(stderr,
			"Terminal names must start with lowercase or digit\n");
	    exit(1);
	}
}



X/*
 *	int
 *	save_str(string)
 *
 *	copy string into next free part of string_table, doing a realloc()
 *	if necessary.  return offset of beginning of string from start of
 *	string_table.
 *
 */

int
save_str(string)
char	*string;
{
	char	*malloc(), *realloc();
	int	old_next_free = next_free;

	if (table_size == 0)
	{
	    if ((string_table = malloc(1024)) == NULL)
		syserr_abort("Out of memory");
	    table_size = 1024;
	    DEBUG(5, "Made initial string table allocation.  Size is %d\n",
								    table_size);
	}

	while (table_size < next_free + strlen(string))
	{
	    if ((string_table = realloc(string_table, table_size + 1024))
									== NULL)
		syserr_abort("Out of memory");
	    table_size += 1024;
	    DEBUG(5, "Extended string table.  Size now %d\n", table_size);
	}

	strcpy(&string_table[next_free], string);
	DEBUG(7, "Saved string '%s' ", string);
	DEBUG(7, "at location %d\n", next_free);
	next_free += strlen(string) + 1;

	return(old_next_free);
}



X/*
 *	init_structure(Booleans, Numbers, Strings)
 *
 *	Initialise the given arrays
 *	Reset the next_free counter to zero.
 *
 */

init_structure(Booleans, Numbers, Strings)
char	Booleans[];
short	Numbers[], Strings[];
{
	int	i;

	for (i=0; i < BOOLCOUNT; i++)
	    Booleans[i] = FALSE;
	
	for (i=0; i < NUMCOUNT; i++)
	    Numbers[i] = -1;

	for (i=0; i < STRCOUNT; i++)
	    Strings[i] = -1;

	next_free = 0;
}



X/*
**	int
**	handle_use(item_ptr, entry_offset, Booleans, Numbers, Strings)
**
**	Merge the compiled file whose name is in cur_token.valstring
**	with the current entry.
**
**		if it's a forward use-link
**	    	    if item_ptr == NULL
**		        queue it up for later handling
**	            else
**		        ignore it (we're already going through the queue)
**	        else it's a backward use-link
**	            read in the object file for that terminal
**	            merge contents with current structure
**
**	Returned value is 0 if it was a backward link and we
**	successfully read it in, -1 if a forward link.
*/

int
handle_use(item_ptr, entry_offset, Booleans, Numbers, Strings)
long		entry_offset;
struct use_item	*item_ptr;
char		Booleans[];
short		Numbers[];
short		Strings[];
{
	struct term	use_term;
	struct stat	statbuf;
	char		filename[50];
        int             i;

	check_name(curr_token.tk_valstring);

	sprintf(filename, "%c/%s", curr_token.tk_valstring[0],
                                                     curr_token.tk_valstring);

	if (stat(filename, &statbuf) < 0  ||  part2==0 && statbuf.st_mtime < start_time)
	{
	    DEBUG(2, "Forward USE to %s", curr_token.tk_valstring);

 	    if (item_ptr == NULL)
 	    {
 		DEBUG(2, " (enqueued)\n", "");
 		enqueue(entry_offset);
 	    }
 	    else 
 		DEBUG(2, " (skipped)\n", "");
	    
	    return(-1);
	}
	else
	{
	    DEBUG(2, "Backward USE to %s\n", curr_token.tk_valstring);
	    if (read_entry(filename, &use_term) < 0)
		syserr_abort("Error in re-reading compiled file %s", filename);

	    for (i=0; i < BOOLCOUNT; i++)
	    {
		if (Booleans[i] == FALSE  &&  use_term.Booleans[i] == TRUE)
		    Booleans[i] = TRUE;
	    }

	    for (i=0; i < NUMCOUNT; i++)
	    {
		if (Numbers[i] == -1  &&  use_term.Numbers[i] != -1)
		    Numbers[i] = use_term.Numbers[i];
	    }

	    for (i=0; i < STRCOUNT; i++)
	    {
		if (Strings[i] == -1  &&  use_term.Strings[i] != (char *) 0)
		    Strings[i] = save_str(use_term.Strings[i]);
	    }

	}
}
//go.sysin dd *
echo 'x - =src/comp_scan.c'
sed 's/^X//' <<'//go.sysin dd *' >=src/comp_scan.c
X/*********************************************************************
*                         COPYRIGHT NOTICE                           *
**********************************************************************
*        This software is copyright (C) 1982 by Pavel Curtis         *
*                                                                    *
*        Permission is granted to reproduce and distribute           *
*        this file by any means so long as no fee is charged         *
*        above a nominal handling fee and so long as this            *
*        notice is always included in the copies.                    *
*                                                                    *
*        Other rights are reserved except as explicitly granted      *
*        by written permission of the author.                        *
*                Pavel Curtis                                        *
*                Computer Science Dept.                              *
*                405 Upson Hall                                      *
*                Cornell University                                  *
*                Ithaca, NY 14853                                    *
*                                                                    *
*                Ph- (607) 256-4934                                  *
*                                                                    *
*                Pavel.Cornell@Udel-Relay   (ARPAnet)                *
*                decvax!cornell!pavel       (UUCPnet)                *
*********************************************************************/

X/*
 *	comp_scan.c --- Lexical scanner for terminfo compiler.
 *
 *   $Log:	RCS/comp_scan.v $
 * Revision 2.1  82/10/25  14:45:55  pavel
 * Added Copyright Notice
 * 
 * Revision 2.0  82/10/24  15:17:12  pavel
 * Beta-one Test Release
 * 
 * Revision 1.3  82/08/23  22:30:03  pavel
 * The REAL Alpha-one Release Version
 * 
 * Revision 1.2  82/08/19  19:10:06  pavel
 * Alpha Test Release One
 * 
 * Revision 1.1  82/08/12  18:37:46  pavel
 * Initial revision
 * 
 *
 */

static char RCSid[] =
	"$Header:   RCS/comp_scan.v  Revision 2.1  82/10/25  14:45:55  pavel  Exp$";

#include <stdio.h>
#include <ctype.h>
#include "compiler.h"

#define iswhite(ch)	(ch == ' '  ||  ch == '\t')


static int	first_column;		/* See 'next_char()' below */



X/*
 *	int
 *	get_token()
 *
 *	Scans the input for the next token, storing the specifics in the
 *	global structure 'curr_token' and returning one of the following:
 *
 *		NAMES		A line beginning in column 1.  'name'
 *				will be set to point to everything up to
 *				but not including the first comma on the line.
 *		BOOLEAN		An entry consisting of a name followed by
 *				a comma.  'name' will be set to point to the
 *				name of the capability.
 *		NUMBER		An entry of the form
 *					name#digits,
 *				'name' will be set to point to the capability
 *				name and 'valnumber' to the number given.
 *		STRING		An entry of the form
 *					name=characters,
 *				'name' is set to the capability name and
 *				'valstring' to the string of characters, with
 *				input translations done.
 *		CANCEL		An entry of the form
 *					name@,
 *				'name' is set to the capability name and
 *				'valnumber' to -1.
 *		EOF		The end of the file has been reached.
 *
 */

int
get_token()
{
	long		number;
	int		type;
	register char	ch;
	static char	buffer[1024];
	register char	*ptr;
	int		dot_flag = FALSE;

	while ((ch = next_char()) == '\n'  ||  iswhite(ch))
	    ;
	
	if (ch == EOF)
	    type = EOF;
	else
	{
	    if (ch == '.')
	    {
		dot_flag = TRUE;

		while ((ch = next_char()) == ' '  ||  ch == '\t')
		    ;
	    }

	    if (! isalnum(ch))
	    {
		 warning("Illegal character - '%c'", ch);
		 panic_mode(',');
	    }

	    ptr = buffer;
	    *(ptr++) = ch;

	    if (first_column)
	    {
		while ((ch = next_char()) != ',' && ch != '\n' && ch != EOF)
		    *(ptr++) = ch;
		
		if (ch == EOF)
		    err_abort("Premature EOF");
		else if (ch == '\n') {
		    warning("Newline in middle of terminal name");
		    panic_mode(',');
		}
		
		*ptr = '\0';
		curr_token.tk_name = buffer;
		type = NAMES;
	    }
	    else
	    {
		ch = next_char();
		while (isalnum(ch))
		{
		    *(ptr++) = ch;
		    ch = next_char();
		}

		*ptr++ = '\0';
		switch (ch)
		{
		    case ',':
			curr_token.tk_name = buffer;
			type = BOOLEAN;
			break;

		    case '@':
			if (next_char() != ',')
			    warning("Missing comma");
			curr_token.tk_name = buffer;
			type = CANCEL;
			break;

		    case '#':
			number = 0;
			while (isdigit(ch = next_char()))
			    number = number * 10 + ch - '0';
			if (ch != ',')
			    warning("Missing comma");
			curr_token.tk_name = buffer;
			curr_token.tk_valnumber = number;
			type = NUMBER;
			break;
		    
		    case '=':
			ch = trans_string(ptr);
			if (ch != ',')
			    warning("Missing comma");
			curr_token.tk_name = buffer;
			curr_token.tk_valstring = ptr;
			type = STRING;
			break;

		    default:
			warning("Illegal character - '%c'", ch);
		}
	    } /* end else (first_column == FALSE) */
	} /* end else (ch != EOF) */

	if (dot_flag == TRUE)
	    DEBUG(8, "Commented out ", "");

	if (debug_level >= 8)
	{
	    fprintf(stderr, "Token: ");
	    switch (type)
	    {
		case BOOLEAN:
		    fprintf(stderr, "Boolean;  name='%s'\n",
                                                          curr_token.tk_name);
		    break;
		
		case NUMBER:
		    fprintf(stderr, "Number; name='%s', value=%d\n",
				curr_token.tk_name, curr_token.tk_valnumber);
		    break;
		
		case STRING:
		    fprintf(stderr, "String; name='%s', value='%s'\n",
				curr_token.tk_name, curr_token.tk_valstring);
		    break;
		
		case CANCEL:
		    fprintf(stderr, "Cancel; name='%s'\n",
                                                          curr_token.tk_name);
		    break;
		
		case NAMES:

		    fprintf(stderr, "Names; value='%s'\n",
                                                          curr_token.tk_name);
		    break;

		case EOF:
		    fprintf(stderr, "End of file\n");
		    break;

		default:
		    warning("Bad token type");
	    }
	}

	if (dot_flag == TRUE)		/* if commented out, use the next one */
	    type = get_token();

	return(type);
}



X/*
 *	char
 *	next_char()
 *
 *	Returns the next character in the input stream.  Comments and leading
 *	white space are stripped.  The global state variable 'firstcolumn' is
 *	set TRUE if the character returned is from the first column of the input
 * 	line.  The global variable curr_line is incremented for each new line.
 *	The global variable curr_file_pos is set to the file offset of the
 *	beginning of each line.
 *
 */

int	curr_column = -1;
char	line[1024];

char
next_char()
{
	char	*rtn_value;
	long	ftell();

	if (curr_column < 0  ||  curr_column > 1023  ||
						    line[curr_column] == '\0')
	{
	    do
	    {
		curr_file_pos = ftell(stdin);

		if ((rtn_value = fgets(line, 1024, stdin)) != NULL)
		    curr_line++;
	    } while (rtn_value != NULL  &&  line[0] == '#');

	    if (rtn_value == NULL)
		return (EOF);

	    curr_column = 0;
	    while (iswhite(line[curr_column]))
		curr_column++;
	}

	if (curr_column == 0  &&  line[0] != '\n')
	    first_column = TRUE;
	else
	    first_column = FALSE;
	
	return (line[curr_column++]);
}


backspace()
{
	curr_column--;

	if (curr_column < 0)
	    syserr_abort("Backspaced off beginning of line");
}



X/*
 *	reset_input()
 *
 *	Resets the input-reading routines.  Used after a seek has been done.
 *
 */

reset_input()
{
	curr_column = -1;
}



X/*
 *	char
 *	trans_string(ptr)
 *
 *	Reads characters using next_char() until encountering a comma, newline
 *	or end-of-file.  The returned value is the character which caused
 *	reading to stop.  The following translations are done on the input:
 *
 *		^X  goes to  ctrl-X (i.e. X & 037)
 *		{\E,\n,\r,\b,\t,\f}  go to
 *			{ESCAPE,newline,carriage-return,backspace,tab,formfeed}
 *		{\^,\\}  go to  {carat,backslash}
 *		\ddd (for ddd = up to three octal digits)  goes to
 *							the character ddd
 *
 *		\e == \E
 *		\0 == \200
 *
 */

char
trans_string(ptr)
char	*ptr;
{
	register int	count = 0;
	int		number;
	int		i;
        char		ch;

	while ((ch = next_char()) != ','  &&  ch != EOF)
	{
	    if (ch == '^')
	    {
		ch = next_char();
		if (ch == EOF)
		    err_abort("Premature EOF");

		if (! isprint(ch))
		{
		    warning("Illegal ^ character - '%c'", ch);
		}

		*(ptr++) = ch & 037;
	    }
	    else if (ch == '\\')
	    {
		ch = next_char();
		if (ch == EOF)
		    err_abort("Premature EOF");
		
		if (ch >= '0'  &&  ch <= '7')
		{
		    number = ch - '0';
		    for (i=0; i < 2; i++)
		    {
			ch = next_char();
			if (ch == EOF)
			    err_abort("Premature EOF");
			
			if (ch < '0'  ||  ch > '7')
			{
			    backspace();
			    break;
			}

			number = number * 8 + ch - '0';
		    }

		    if (number == 0)
			number = 0200;
		    *(ptr++) = (char) number;
		}
		else
		{
		    switch (ch)
		    {
			case 'E':
			case 'e':	*(ptr++) = '\033';	break;
			
			case 'l':
			case 'n':	*(ptr++) = '\n';	break;
			
			case 'r':	*(ptr++) = '\r';	break;
			
			case 'b':	*(ptr++) = '\008';	break;

			case 's':	*(ptr++) = ' ';		break;
			
			case 'f':	*(ptr++) = '\014';	break;
			
			case 't':	*(ptr++) = '\t';	break;
			
			case '\\':	*(ptr++) = '\\';	break;
			
			case '^':	*(ptr++) = '^';		break;

			case ',':	*(ptr++) = ',';		break;

			case ':':	*(ptr++) = ':';		break;

			default:
			    warning("Illegal character in \\ sequence");
			    *(ptr++) = ch;
		    } /* endswitch (ch) */
		} /* endelse (ch < '0' ||  ch > '7') */
	    } /* end else if (ch == '\\') */
	    else
	    {
		*(ptr++) = ch;
	    }
	    
	    count ++;

	    if (count > 500)
		warning("Very long string found.  Missing comma?");
	} /* end while */

	*ptr = '\0';

	return(ch);
}

X/*
 * Panic mode error recovery - skip everything until a "ch" is found.
 */
panic_mode(ch)
char ch;
{
	int c;

	for (;;) {
		c = next_char();
		if (c == ch)
			return;
		if (c == EOF);
			return;
	}
}
//go.sysin dd *
echo 'x - =src/compiler.h'
sed 's/^X//' <<'//go.sysin dd *' >=src/compiler.h
X/*********************************************************************
*                         COPYRIGHT NOTICE                           *
**********************************************************************
*        This software is copyright (C) 1982 by Pavel Curtis         *
*                                                                    *
*        Permission is granted to reproduce and distribute           *
*        this file by any means so long as no fee is charged         *
*        above a nominal handling fee and so long as this            *
*        notice is always included in the copies.                    *
*                                                                    *
*        Other rights are reserved except as explicitly granted      *
*        by written permission of the author.                        *
*                Pavel Curtis                                        *
*                Computer Science Dept.                              *
*                405 Upson Hall                                      *
*                Cornell University                                  *
*                Ithaca, NY 14853                                    *
*                                                                    *
*                Ph- (607) 256-4934                                  *
*                                                                    *
*                Pavel.Cornell@Udel-Relay   (ARPAnet)                *
*                decvax!cornell!pavel       (UUCPnet)                *
*********************************************************************/

X/*
 *	compiler.h - Global variables and structures for the terminfo
 *			compiler.
 *
 *  $Header:   RCS/compiler.v  Revision 2.1  82/10/25  14:46:04  pavel  Exp$
 *
 *  $Log:	RCS/compiler.v $
Revision 2.1  82/10/25  14:46:04  pavel
Added Copyright Notice

Revision 2.0  82/10/24  15:17:20  pavel
Beta-one Test Release

Revision 1.3  82/08/23  22:30:09  pavel
The REAL Alpha-one Release Version

Revision 1.2  82/08/19  19:10:10  pavel
Alpha Test Release One

Revision 1.1  82/08/12  18:38:11  pavel
Initial revision

 *
 */

#include <stdio.h>

#ifndef TRUE
#define TRUE	1
#define FALSE	0
#endif

#define SINGLE			/* only one terminal (actually none) */

char	*destination;		/* destination directory for object files */

long	start_time;		/* time at start of compilation */
long	time();

int	curr_line;		/* current line # in input */
long	curr_file_pos;		/* file offset of current line */

int	debug_level;		/* level of debugging output */

#define DEBUG(level, fmt, a1) \
		if (debug_level >= level)\
		    fprintf(stderr, fmt, a1);

	/*
	 *	These are the types of tokens returned by the scanner.
	 *	The first three are also used in the hash table of capability
	 *	names.  The scanner returns one of these values after loading
	 *	the specifics into the global structure curr_token.
	 *
	 */

#define BOOLEAN 0		/* Boolean capability */
#define NUMBER 1		/* Numeric capability */
#define STRING 2		/* String-valued capability */
#define CANCEL 3		/* Capability to be cancelled in following tc's */
#define NAMES  4		/* The names for a terminal type */

	/*
	 *	The global structure in which the specific parts of a
	 *	scanned token are returned.
	 *
	 */

struct token
{
	char	*tk_name;		/* name of capability */
	int	tk_valnumber;	/* value of capability (if a number) */
	char	*tk_valstring;	/* value of capability (if a string) */
};

struct token	curr_token;

	/*
	 *	The file comp_captab.c contains an array of these structures,
	 *	one per possible capability.  These are then made into a hash
	 *	table array of the same structures for use by the parser.
	 *
	 */

struct name_table_entry
{
	struct name_table_entry *nte_link;
	char	*nte_name;	/* name to hash on */
	int	nte_type;	/* BOOLEAN, NUMBER or STRING */
	short	nte_index;	/* index of associated variable in its array */
};

extern struct name_table_entry	cap_table[];
extern struct name_table_entry	*cap_hash_table[];

extern int	Captabsize;
extern int	Hashtabsize;

#define NOTFOUND	((struct name_table_entry *) 0)
	/*
	 *	Function types
	 *
	 */

struct name_table_entry	*find_entry();	/* look up entry in hash table */

char	next_char();
char	trans_string();
//go.sysin dd *
exit
