[comp.os.minix] POSIX and the future of MINIX C

hardin@eecea.eece.ksu.edu (David Hardin) (02/08/89)

Before I dive in, I would first like to thank AST for the EM interpreter 
source.  It allowed me to get my AAMP code generator (almost) done.  
For any of you writing backends for the MINIX C compiler, the EM interpreter 
is a *must*.  The compiler documentation is just not complete enough.

Anyway, I have been reading the POSIX discussion with some interest.  I got 
the POSIX text a while back, and have recently been scanning the portions 
having to do with C.  Section 2.2.3 is especially interesting (as legalese 
goes, that is):

"Although IEEE Std 1003.1-1988 references parts of the C Standard ... 
conformance to the C Standard is unnecessary for conformance to [POSIX] ....
Any C Language implementation providing the facilities stipulated in 
Chapter 8 may claim conformance -- however, it shall clearly state that its 
C does not conform to the C Standard."

So, in other words, an ANSI Standard C is strongly recommended.  Is an ANSI 
C planned for MINIX 2.0?  If so, will the compiler still use EM as its 
intermediate form, or will another approach be taken?  Those of us who have 
a substantial time investment in EM are curious.  BTW, I now have access to 
ACK, which strengthens my interest in EM.

While we're on the subject of the C compiler, would it be possible to get 
UniPress to agree to sell an "ugrade kit" for future compiler upgrades at 
a reduced cost, as Prentice-Hall will be doing for MINIX Real Soon Now? 

Thanks in advance for any comments,

David

-- 
David Hardin				Rockwell International 
                                       	M/S 124-211, 400 Collins Rd. NE
INTERNET: hardin@eecea.eece.ksu.edu     Cedar Rapids, IA  52498
UUCP: {pyramid,ucsd}!ncr-sd!ncrwic!ksuvax1!eecea!hardin

ast@cs.vu.nl (Andy Tanenbaum) (02/10/89)

In article <552@eecea.eece.ksu.edu> hardin@eecea.eece.ksu.edu (David Hardin) writes:
>So, in other words, an ANSI Standard C is strongly recommended.  Is an ANSI 
>C planned for MINIX 2.0?  If so, will the compiler still use EM
No.  We have one, but it is too big for the PC.  I'll have to stick with the
current compiler.  It does use EM, as do all our other compilers, however.


Andy Tanenbaum (ast@cs.vu.nl)

agc@nixbln.UUCP (02/20/89)

 EM
>No.  We have one, but it is too big for the PC.  I'll have to stick with the
>current compiler.  It does use EM, as do all our other compilers, however.
> 
> 
> Andy Tanenbaum (ast@cs.vu.nl)

Hello everyone,

Here's an (almost) ANSI-C conforming pre-processor. Please note that I
haven't tested it under Minix. Please also note that there are two shell
archives here. Now, how do I post this using notes?

Regards,
Alistair G. Crooks,
Joypace Ltd., 2 Vale Road, Hawkhurst, Kent TN18 4BU, UK. (+44 580 753114)
UUCP Europe:			        ...!mcvax!unido!nixpbe!nixbln!agc   
UUCP the rest of the world:	 ...!uunet!linus!nixbur!nixpbe!nixbln!agc

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./agcpp.1`
then
echo "writing ./agcpp.1"
cat > ./agcpp.1 << '\Rogue\Monster\'
.TH AGCPP 1-local
.SH NAME
agcpp \- a C preprocessor, and ANSI C to Kernighan and Ritchie C translator
.SH SYNOPSIS
.B agcpp [
option ...
.B ]
.B [
ifile
.B [
ofile
.B ] ]
.SH DESCRIPTION
.PP
.I Agcpp\^
can be used as an ordinary C preprocessor, and I have tried to make
it conform to the ANSI C draft specification, as far as I can understand it.
It will also take ANSI C, and turn it into Kernighan and Ritchie C,
with a one exception and one restriction as detailed below.
.PP
.I Agcpp\^
optionally accepts two file names as arguments.
.I Ifile\^
and
.I ofile\^
are respectively the input and output
for the preprocessor.  They default to standard input
and standard output if not supplied.
.PP
The following arguments are recognised:
.TP
.B \-ANSI
produce ansi output from the preprocessor for the underlying compiler -
this means that const, volatile and signed will be passed on, and
that function prototypes and new-style function arguments will be
passed on to the compiler.
.TP
.B \-P
Preprocess the input without producing the line control
information used by the next pass of the C compiler.
.TP
.BI \-U name\^
Remove any initial definition of
.IR name ,
It is not an error if name is not defined.
.TP
.BI \-D name\^
.PD 0
.TP
.BI \-D name=def\^
Define
.I name\^
as if by a
.B #define
directive.  If no
.I =def\^
is given,
.I name\^
is defined as 1.
.PD
.TP
.BI \-I dir\^
Change the algorithm for searching for
.B #include
files
whose names do not begin with \f3/\fP
to look in
.I dir\^
before looking in the directories on the standard list.
Thus,
.B #include
files whose names are enclosed in \f3"\|"\fP
will be searched for
first in the directory of the
.I ifile\^
argument,
then in directories named in 
.B \-I
options,
and last in directories on a standard list.
For
.B #include
files whose names are enclosed in
.BR <> ,
the directory of the
.I ifile\^
argument is not searched.
.PP
ANSI standard definitions that will be recognised by the preprocessor
are __LINE__, __FILE__, __DATE__, __TIME__. These will expand to (respectively),
the current line number in the source file, the current source file, the
current date, and the current time. In addition, the definition __STDC__ will
be expanded to 1.
.PP
.I agcpp
will recognise the following directives :
.TP
.BI #define " name" " " token-string
Replace subsequent instances of
.I name\^
with
.IR token-string .
.TP
\fB#define\fI name\fB(\fI arg\fB, ...,\fI arg\fB )\fI token-string\fR
Notice that there can be no space between
.I name
and the
.BR ( .
Replace subsequent instances of
.I name
followed by a
.BR ( ,
a list of comma separated tokens, and a
.B )
by
.I token-string
where each occurrence of an
.I arg
in the
.I token-string
is replaced by the corresponding token in the comma separated list.
.TP
.BI #undef " name"
Cause the definition of
.I name
(if any) to be forgotten from now on.
.TP
\fB#include\fI "filename"
.PD 0
.TP
.BI #include " " < filename >
Include at this point the contents of
.I filename
(which will then be run through
.IR cpp ).
When the
.BI < filename >
notation is used,
.I filename
is only searched for in the standard places.
See the
.B \-I
option above for more detail.
.PD
.TP
\fB#line\fI integer-constant "filename"
.I agcpp
generates line information for the underlying compiler.
.TP
.B #endif
.br
Ends a section of lines begun by a test directive
.RB ( #if ,
.BR #ifdef ,
or
.BR #ifndef ).
Each #endif must match a previous #if, #ifdef, #ifndef or #elif.
.TP
.BI #ifdef " name"
The lines following will appear in the output if and only if
.I name
is defined.
.BI #ifndef " name"
The lines following will not appear in the output if and only if
.I name
is not defined.
.TP
.BI #if " constant-expression"
Lines following will appear in the output if and only if the
.I constant-expression
evaluates to non-zero.
All binary non-assignment C operators, the
.B ?:
operator, the unary
.BR \(mi ,
.BR ! ,
and
.B ~
operators are all legal in
.IR constant-expression .
There is also a unary operator
.BR defined ,
which can be used in
.I constant-expression
in these two forms:
.BI defined " " ( " name " )
or
.BI defined " name" .
Only these operators, integer constants, and names which
are known by
.I cpp
should be used in
.IR constant-expression .
.TP
.B #else
Reverses the notion of the test directive which
matches this directive.  So if lines previous to
this directive are ignored, the following lines
will appear in the output.
And vice versa.
.TP
.BI #if " constant-expression"
Reverses the notion of the test directive, and calculates the
constant expression given, thereafter acting as a normal #if directive.
.TP
.BI #error " tokens"
reports the error and the
tokens on standard error, and terminates processing.
.TP
.BI #pragma " tokens"
(silently ignores this directive).
.TP
.BI #
Also silently ignores the null directive.
.PP
The test directives and the possible
.B #else
directives can be nested.
.SH FILES
.TP 1.5i
/usr/include
standard directory for
.B #include
files
.SH SEE ALSO
.PP
cpp(1), cc(1).
.SH DIAGNOSTICS
.PP
Various warnings, and fatal errors such as include files which cannot be
found, or running out of memory. They are intended to be self-explanatory.
.SH AUTHOR
.nf
Alistair G. Crooks,
Vale Road, Hawkhurst, Kent TN18 4BU, UK. (+44 580 753114)
(...!uunet!linus!nixbur!nixpbe!nixbln!agc)
.fi
\Rogue\Monster\
else
  echo "will not over write ./agcpp.1"
fi
if `test ! -s ./Makefile.att`
then
echo "writing ./Makefile.att"
cat > ./Makefile.att << '\Rogue\Monster\'
#
#	@(#)Makefile.att	1.4	09/02/89	18:32:51
#
#	Makefile for att unix on Targon 35.
#
#
SRCS = agcpp.c id.c if.c inc.c mac.c parse.c proto.c
OBJS = agcpp.o id.o if.o inc.o mac.o parse.o proto.o
INC = defs.h
CC = mcc
CCFLAGS = -O
CPPFLAGS = -DATT -DPROCESSOR="\"pyr\""
CFLAGS = $(CCFLAGS) $(CPPFLAGS)

agcpp : $(OBJS)
	$(CC) $(CCFLAGS) $(OBJS) -o agcpp

$(OBJS) : $(INC)

lint :
	lint $(CPPFLAGS) $(SRCS)
\Rogue\Monster\
else
  echo "will not over write ./Makefile.att"
fi
if `test ! -s ./Makefile.bsd`
then
echo "writing ./Makefile.bsd"
cat > ./Makefile.bsd << '\Rogue\Monster\'
#
#	@(#)Makefile.bsd	1.4	09/02/89	18:32:51
#
#	Makefile for bsd unix on Targon 35.
#
#
SRCS = agcpp.c getopt.c id.c if.c inc.c mac.c parse.c proto.c
OBJS = agcpp.o getopt.o id.o if.o inc.o mac.o parse.o proto.o
INC = defs.h
CC = mcc
CCFLAGS = -O
CPPFLAGS = -DBSD -DPROCESSOR="\"pyr\""
CFLAGS = $(CCFLAGS) $(CPPFLAGS)

agcpp : $(OBJS)
	$(CC) $(CCFLAGS) $(OBJS) -o agcpp

$(OBJS) : $(INC)

lint :
	lint $(CPPFLAGS) $(SRCS)
\Rogue\Monster\
else
  echo "will not over write ./Makefile.bsd"
fi
if `test ! -s ./Makefile.pws`
then
echo "writing ./Makefile.pws"
cat > ./Makefile.pws << '\Rogue\Monster\'
#
#	@(#)Makefile.pws	1.4	09/02/89	18:32:51
#
#	Makefile for att unix
#
#
OBJS = agcpp.o id.o if.o inc.o macro.o malloc.o parse.o proto.o
INC = defs.h
OPTIM = -O
CPPFLAGS = -DATT -DPROCESSOR="\"i386\"" -DBADMALLOC -DIDENT_DIR
CFLAGS = $(OPTIM) $(CPPFLAGS)

agcpp : $(OBJS)
	cc $(CFLAGS) $(OBJS) -o agcpp

$(OBJS) : $(INC)

\Rogue\Monster\
else
  echo "will not over write ./Makefile.pws"
fi
if `test ! -s ./Makefile.tc`
then
echo "writing ./Makefile.tc"
cat > ./Makefile.tc << '\Rogue\Monster\'
agcpp.exe : agcpp.obj getopt.obj id.obj if.obj inc.obj mac.obj parse.obj proto.obj
	tcc agcpp.obj getopt.obj id.obj if.obj inc.obj mac.obj parse.obj proto.obj

agcpp.obj : agcpp.c defs.h
	tcc -c -DTURBO agcpp.c

getopt.obj : getopt.c
	tcc -c -DTURBO tcgetopt.c

id.obj : id.c defs.h
	tcc -c -DTURBO id.c

if.obj : if.c defs.h
	tcc -c -DTURBO if.c

inc.obj : inc.c defs.h
	tcc -c -DTURBO inc.c

mac.obj : mac.c defs.h
	tcc -c -DTURBO mac.c

parse.obj : parse.c defs.h
	tcc -c -DTURBO parse.c

proto.obj : proto.c defs.h
	tcc -c -DTURBO proto.c

\Rogue\Monster\
else
  echo "will not over write ./Makefile.tc"
fi
if `test ! -s ./Makefile.ztc`
then
echo "writing ./Makefile.ztc"
cat > ./Makefile.ztc << '\Rogue\Monster\'
agcpp.exe : agcpp.obj getopt.obj id.obj if.obj inc.obj mac.obj parse.obj proto.obj
	ztc agcpp.obj getopt.obj id.obj if.obj inc.obj mac.obj parse.obj proto.obj

agcpp.obj : agcpp.c defs.h
	ztc -c -DZORTECH agcpp.c

getopt.obj : getopt.c
	ztc -c -DZORTECH getopt.c

id.obj : id.c defs.h
	ztc -c -DZORTECH id.c

if.obj : if.c defs.h
	ztc -c -DZORTECH if.c

inc.obj : inc.c defs.h
	ztc -c -DZORTECH inc.c

mac.obj : mac.c defs.h
	ztc -c -DZORTECH mac.c

parse.obj : parse.c defs.h
	ztc -c -DZORTECH parse.c

proto.obj : proto.c defs.h
	ztc -c -DZORTECH proto.c

\Rogue\Monster\
else
  echo "will not over write ./Makefile.ztc"
fi
if `test ! -s ./agcpp.c`
then
echo "writing ./agcpp.c"
cat > ./agcpp.c << '\Rogue\Monster\'
/*
 *	@(#)agcpp.c	1.12	09/02/89	18:22:10	agc
 *
 *	Copyright Joypace Ltd, UK, 1989. All rights reserved.
 *	This file may be freely distributed provided that this
 *	notice remains attached.
 *
 *	agcpp - a version of a C pre-processor.
 *
 *	agcpp.c - miscellaneous routines, and main.
 *
 *	Compile time flags:
 *	ATT		Unix System V.[23]
 *	BSD		Unix BSD4.[23]
 *	ZORTECH		Zortech C++, v1.05
 *	TURBOC		Turbo C, 1.5
 *	MSC		Microsoft C, 5.0
 *	MINIX		Minix 1.2
 */
#ifndef lint
char	*agcppnsccsid = "@(#)agcpp.c	1.12 09/02/89 18:22:10 agc";
#endif /* not lint */

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

#define EXTERN
#include "defs.h"

#ifdef ATT
#ifndef STDINCLUDE
#define STDINCLUDE	"/usr/include"
#endif /* STDINCLUDE */
#define OSTYPE		"unix"
#endif /* ATT */

#ifdef BSD
#ifndef STDINCLUDE
#define STDINCLUDE	"/usr/include"
#endif /* STDINCLUDE */
#define OSTYPE		"unix"
#endif /* BSD */

#ifdef ZORTECH
#ifndef STDINCLUDE
#define STDINCLUDE	"c:/zortech/include"
#endif /* STDINCLUDE */
#define OSTYPE		"dos"
#endif /* ZORTECH */

#ifdef TURBOC
#ifndef STDINCLUDE
#define STDINCLUDE	"c:/turboc/include"
#endif /* STDINCLUDE */
#define OSTYPE		"dos"
#endif /* TURBOC */

#ifdef MSC
#ifndef STDINCLUDE
#define STDINCLUDE	"c:/msc/include"
#endif /* STDINCLUDE */
#define OSTYPE		"dos"
#endif /* MSC */

#ifdef MINIX
#ifndef STDINCLUDE
#define STDINCLUDE 	"/usr/include"
#endif /* STDINCLUDE */
#define OSTYPE		"minix"
#endif /* MINIX */

#ifndef PROCESSOR
#define PROCESSOR	"i8088"
#endif /* PROCESSOR */

#define READING	1
#define WRITING	2

typedef struct directive {
	char	*d_name;
	int	d_type;
#define UNKNOWN	0
#define	DEFINE	1
#define	ENDIF	2
#define	IFDEF	3
#define	IFNDEF	4
#define	ELSE	5
#define	INCLUDE	6
#define	IF	7
#define	ELIF	8
#define	UNDEF	9
#define	PRAGMA	10
#define	ERROR	11
#define	LINE	12
#define	IDENT	13
#define EMPTY	14
} DIRECTIVE;

static DIRECTIVE	directives[] = {
	"define",	DEFINE,
	"endif",	ENDIF,
	"ifdef",	IFDEF,
	"ifndef",	IFNDEF,
	"else",		ELSE,
	"include",	INCLUDE,
	"if",		IF,
	"elif",		ELIF,
	"undef",	UNDEF,
	"pragma",	PRAGMA,
	"error",	ERROR,
	"line",		LINE,
#ifdef IDENT_DIR
	"ident",	IDENT,
#endif /* IDENT_DIR */
	"\n",		EMPTY,
	NULL
};

static char	*one = "1";		/* string for definitions */
static char	linedirectives = 1;	/* 1 = line directives are made */

extern char	*optarg;
extern int	optind;


/* report an error on stderr, and exit if n greater than 0 */
void
error(n, fmt, s)
int	n;
char	*fmt;
char	*s;
{
	if (filename[0])
		(void) fprintf(stderr, "\"%s\" ", filename);
	(void) fprintf(stderr, "%d: ", lineno);
	(void) fprintf(stderr, fmt, s);
	(void) fputc('\n', stderr);
	if (n)
		(void) exit(n);
}


/* Minix has no bzero function - to zero n bytes of s */
#ifdef MINIX
void
bzero(s, n)
char	*s;
unsigned int	n;
{
	while (n--)
		*s++ = 0;
}
#endif /* MINIX */


/* save n chars of s in malloc'd memory */
char *
strnsave(s, n)
char	*s;
int	n;
{
	char	*cp;

	NEWARRAY(char, cp, n+1);
	(void) strncpy(cp, s, n);
	cp[n] = 0;
	return(cp);
}


/* put n tokens of s on stdout */
void
output(s, n)
char	*s;
int	n;
{
	static char	obuf[BUFSIZ];
	static char	*op = obuf;
	char		*was;
	char		*cp;

	(void) strncpy(op, s, n);
	op += n;
	*op = 0;
	if (s[n-1] == '\n') {
		for (cp = op = obuf ; *op ; ) {
			while (*op && *op != '"')
				*cp++ = *op++;
			if (*op == 0)
				break;
			for (*cp++ = *op++ ; *op && *op != '"' ; *cp++ = *op++)
				if (*op == '\\')
					*cp++ = *op++;
			if (*op == 0)
				break;
			for (was = op++ ; *op && isspace(*op) ; op++)
				;
			if (*op == 0)
				break;
			if (*op == '"')
				op++;
			else
				op = was;
		}
		for (*cp-- = 0 ; cp != obuf && isspace(*cp) ; --cp)
			;
		if (*cp == '"')
			op = &obuf[strlen(obuf) - 1];
		else {
			(void) fputs(obuf, stdout);
			op = obuf;
		}
	}
}


/* delete an ARGS structure */
void
delargs(ap)
ARGS	*ap;
{
	int	i;

	for (i = 0 ; i < ap->a_argc ; i++)
		(void) nfree((char *) ap->a_argv[i]);
	(void) nfree((char *) ap);
}


/* perform the line directive */
void
doline()
{
	if (linedirectives)
		(void) printf("# %d \"%s\"\n", lineno, filename);
}


#ifdef IDENT_DIR
/* perform the ident directive */
void
doident(fp)
FILE	*fp;
{
	(void) printf("# ident ");
	if (!gettoken(fp, 1, &t))
		error(0, "Unexpected end of file in #ident", (char *) NULL);
	(void) printf("%s\n", t.t_token);
}
#endif /* IDENT_DIR */


/* perform the error directive */
void
doerror(fp)
FILE	*fp;
{
	tmp[0] = 0;
	while (gettoken(fp, 0, &t)) {
		if (t.t_type == T_EOLN)
			break;
		(void) strcat(tmp, t.t_token);
	}
	error(1, "%s", tmp);
}


/* perform the undef directive */
void
doundef(fp)
FILE	*fp;
{
	if (!gettoken(fp, 0, &t))
		error(1, "Bad undef syntax", (char *) NULL);
	delmacro(t.t_token);
}


/* check that we're not at the top level */
int
oklevel(level, directive)
int	level;
char	*directive;
{
	if (level == 0)
		error(0, "Unmatched %s", directive);
	return(level != 0);
}


/* check that we've not seen an else directive yet */
int
okelse(elseln)
int	elseln;
{
	if (elseln >= 0)
		error(0, "Previous #else directive line %d", (char *) elseln);
	return(elseln < 0);
}


/* find out which directive it was from directives despatch table */
int
getdirective(s)
char	*s;
{
	DIRECTIVE	*dp;

	for (dp = directives ; dp->d_name ; dp++)
		if (STREQ(dp->d_name, s))
			return(dp->d_type);
	return(UNKNOWN);
}


/* do a block of the input file - recursive */
void
doblock(fp, doing, level, parent)
FILE	*fp;
int	doing;
int	level;
int	parent;
{
	int	elseln = -1;

	while (gettoken(fp, 0, &t)) {
		switch(t.t_type) {
		case T_HASH :
			if (!gettoken(fp, 1, &t))
				error(1, "Unexpected end of file in directive",
								(char *) NULL);
			switch(getdirective(t.t_token)) {
			case DEFINE :
				if (doing)
					dodefine(fp);
				break;
			case ENDIF :
				clrtoeoln(fp);
				if (oklevel(level, "#endif")) {
					if (!doing)
						doline();
					return;
				}
				break;
			case ELSE :
				if (oklevel(level, "#else") && okelse(elseln)) {
					if (!doing)
						doline();
					if (parent)
						doing = 1 - doing;
					elseln = lineno;
				}
				clrtoeoln(fp);
				break;
			case IFDEF :
				doblock(fp, doifdef(fp, 1, doing), level+1,
									doing);
				break;
			case IFNDEF :
				doblock(fp, doifdef(fp, 0, doing), level+1,
									doing);
				break;
			case IF :
				doblock(fp, doif(fp, doing), level+1, doing);
				break;
			case ELIF :
				if (oklevel(level, "#elif") &&
				    okelse(elseln)) {
					if (!doing)
						doline();
					if (parent)
						doing = 1 - doing;
					doblock(fp, doif(fp, doing), level+1,
									doing);
					if (!doing)
						doline();
					return;
				}
				break;
			case INCLUDE :
				if (doing) {
					doinclude(fp, level);
					doline();
				}
				break;
			case LINE :
				if (doing)
					doline();
				break;
#ifdef IDENT_DIR
			case IDENT :
				if (doing)
					doident(fp);
				break;
#endif /* IDENT_DIR */
			case UNDEF :
				if (doing)
					doundef(fp);
				break;
			case ERROR :
				doerror(fp);
				break;
			case PRAGMA :
				clrtoeoln(fp);
				break;
			case EMPTY :
				break;
			case UNKNOWN :
				error(0, "Unknown directive '%s'", t.t_token);
				break;
			}
			break;
		case T_WORD :
			if (!doing)
				continue;
			expand(t.t_token, fp);
			break;
		default :
			if (t.t_token[0] == '{')
				block++;
			else if (t.t_token[0] == '}')
				block--;
			if (doing)
				output(t.t_token, t.t_len);
			if (doing && clevel == K_AND_R && block == 0 &&
			    t.t_token[0] == '(')
				doargs(fp);
		}
	}
}


/* re-direct the desired io stream to/from a file */
void
openfp(s, mode)
char	*s;
char	mode;
{
	switch(mode) {
	case READING :
		if (freopen(s, "r", stdin) == (FILE *) NULL)
			error(1, "can't read file '%s'", s);
		break;
	case WRITING :
		if (freopen(s, "w+", stdout) == (FILE *) NULL)
			error(1, "can't write to output file '%s'", s);
		break;
	}
}

main(argc, argv)
int	argc;
char	**argv;
{
	char	*eq;
	int	c;

	insdir(STDINCLUDE);
	addmacro(OSTYPE, (ARGS *) NULL, one, 0);
	addmacro(PROCESSOR, (ARGS *) NULL, one, 0);
	addmacro("__FILE__", (ARGS *) NULL, one, 1);
	addmacro("__LINE__", (ARGS *) NULL, one, 1);
	addmacro("__DATE__", (ARGS *) NULL, one, 1);
	addmacro("__TIME__", (ARGS *) NULL, one, 1);
	addmacro("__STDC__", (ARGS *) NULL, one, 1);
	compchars = COMPCHARS;
	clevel = K_AND_R;
	while ((c = getopt(argc, argv, "A:C:D:I:PU:")) != EOF) {
		switch(c) {
		case 'A' :
			if (STREQ(optarg, "NSI"))
				clevel = ANSI;
			break;
		case 'C' :
			if ((compchars = atoi(optarg)) == 0)
				compchars = COMPCHARS;
			break;
		case 'D' :
			if ((eq = index(optarg, '=')) == (char *) NULL)
				eq = one;
			else
				*eq++ = 0;
			addmacro(optarg, (ARGS *) NULL, eq, 0);
			break;
		case 'I' :
			insdir(optarg);
			break;
		case 'P' :
			linedirectives = 0;
			break;
		case 'U' :
			delmacro(optarg);
			break;
		default :
			error(0, "unrecognised argument '%c'", (char *) c);
		}
	}
	if (clevel == K_AND_R) {
		addmacro("const", (ARGS *) NULL, " ", 0);
		addmacro("volatile", (ARGS *) NULL, " ", 0);
		addmacro("signed", (ARGS *) NULL, " ", 0);
	}
	insdir(".");
	lineno = 0;
	t.t_type = T_EOLN;
	if (optind < argc) {
		(void) strcpy(filename, argv[optind]);
#ifdef ZORTECH
/* don't ask me why - this needs to be here, or the freopen of stdin fails */
		printf("\n");
#endif /* ZORTECH */
		openfp(filename, READING);
		if (argv[++optind] != (char *) NULL)
			openfp(argv[optind], WRITING);
	} else
		filename[0] = 0;
	doblock(stdin, 1, 0, 1);
	return(0);
}
\Rogue\Monster\
else
  echo "will not over write ./agcpp.c"
fi
if `test ! -s ./defs.h`
then
echo "writing ./defs.h"
cat > ./defs.h << '\Rogue\Monster\'
/*
 *	@(#)defs.h	1.9	09/02/89	18:22:10	agc
 *
 *	Copyright Joypace Ltd., UK, 1989. All rights reserved.
 *	This code may be freely distributed, provided that this
 *	notice remains attached.
 *
 *	agcpp - a version of a C pre-processor.
 *
 *	defs.h - contains all the definitions for agcpp.
 *
 *	Compile-time flags:
 *	ATT		Unix System V.[23]
 *	BSD		BSD 4.[23] Unix
 *	ZORTECH		Zortech C++, v1.05.
 *	TURBOC		Turbo C 1.5
 *	MSC		Microsoft C 5.0
 */
#define MAXARGS		32

typedef struct tokstr {			/* parsing token */
	char	t_token[BUFSIZ];	/* the token itself */
	char	t_type;			/* its type */
#define T_HASH		1
#define T_WORD		2
#define T_STRING	3
#define T_NUMBER	4
#define T_SPACE		5
#define T_EOLN		6
#define T_PUNCT		7
#define T_HASHHASH	8
	int	t_len;			/* its length */
} TOKEN;

typedef struct argstr {			/* argc, argv style arguments */
	int	a_argc;
	char	*a_argv[MAXARGS];
} ARGS;

typedef struct macstr {			/* a macro */
	char		*m_name;	/* its name */
	char		*m_val;		/* its value */
	ARGS		*m_args;	/* any arguments (NULL if none) */
	char		m_prot;		/* 1 = macro is protected */
	struct macstr	*m_next;	/* next in bucket */
	struct macstr	*m_prev;	/* previous in bucket */
} MACRO;

#define HASHTABLEN	997		/* length of the hash table */

#ifndef SIGCHARS
#define SIGCHARS	32		/* signif. chars in cpp identifier */
#endif /* SIGCHARS */

#ifndef COMPCHARS
#define COMPCHARS	8		/* signif. chars in cc identifier */
#endif /* COMPCHARS */

#ifndef BADMALLOC
#define nfree		free
#define ncalloc		calloc
#define nmalloc		malloc
#endif /* BADMALLOC */

#ifdef ATT
#define index		strchr
#define bzero(s, n)	(void) memset(s, 0, n)
#include <string.h>
#endif /* ATT */

#ifdef ZORTECH
#define index		strchr
#define bzero(s, n)	(void) memset(s, 0, n)
#include <string.h>
#endif /* ZORTECH */

#ifdef TURBOC
#define index		strchr
#define bzero(s, n)	(void) memset(s, 0, n)
#include <string.h>
#endif /* TURBOC */

#ifdef MSC
#define index		strchr
#define bzero(s, n)	(void) memset(s, 0, n)
#include <string.h>
#endif /* MSC */

#ifdef BSD
#include <strings.h>
#endif /* BSD */

#define NEWARRAY(type, ptr, nel) \
	if ((ptr = (type *) ncalloc((unsigned) nel, sizeof(type))) == \
								(type *) NULL) \
		error(1, "newarray: ncalloc failure", (char *) NULL)

#define NEW(type, ptr) { \
	if ((ptr = (type *) nmalloc(sizeof(type))) == (type *) NULL) \
		error(1, "new: nmalloc failure", (char *) NULL); \
	bzero((char *) ptr, sizeof(type)); \
}

#define STREQ(s1, s2)	(*s1 == *s2 && strcmp(&(s1)[1], &(s2)[1]) == 0)

EXTERN TOKEN	t;			/* the token being processed */
EXTERN char	filename[BUFSIZ];	/* current filename */
EXTERN char	buf[BUFSIZ];		/* current input buffer */
EXTERN char	tmp[BUFSIZ];		/* for temporary stuff */
EXTERN char	*here;			/* current place in input buffer */
EXTERN int	lineno;			/* current line number in source file */
EXTERN int	ilevel;			/* current include nesting level */
EXTERN int	block;			/* number of {} pairs found */
EXTERN int	compchars;		/* significant id. chars in cc */
EXTERN int	clevel;			/* what compiler will accept */
#define K_AND_R		0
#define ANSI		1

extern char	*malloc();
extern char	*calloc();

#ifdef ATT
extern void	exit();
extern void	free();
#endif /* ATT */

#ifdef BSD
extern int	exit();
extern int	free();
#endif /* BSD */

extern MACRO	*isdefined();
extern ARGS	*fgetargs();

extern char	*strnsave();
extern char	*nameof();

extern void	error();
extern void	addmacro();
extern void	delmacro();
extern void	dodefine();
extern void	clrtoeoln();
extern void	doinclude();
extern void	expand();
extern void	insdir();
extern void	doblock();
extern void	delargs();
extern void	sgettoken();
extern void	output();
extern void	doargs();
\Rogue\Monster\
else
  echo "will not over write ./defs.h"
fi
if `test ! -s ./getopt.c`
then
echo "writing ./getopt.c"
cat > ./getopt.c << '\Rogue\Monster\'
#include <stdio.h>

#ifndef lint
char	getopt_sccsid[] = "@(#)getopt.c	1.1 17/09/87 12:07:04 agc 1987";
#endif

extern char	*index();

/*
 *	getopt - parse the arguments given.
 *	retrieved from net.sources
 */
int	opterr = 1;
int	optind = 1;
int	optopt;
char	*optarg;

#define BADCH	(int)'?'
#define EMSG	""
#define TELL(s)	(void) fputs(*nargv, stderr); (void) fputs(s, stderr);\
	(void) fputc(optopt, stderr); (void) fputc('\n', stderr);\
	return(BADCH);

int getopt(nargc, nargv, ostr)
int	nargc;
char	**nargv;
char	*ostr;
{
  register char	*oli;
  static char	*place = EMSG;

  if (!*place) {
	if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place)
		return(EOF);
	if (*place == '-') {
		++optind;
		return(EOF);
	}
  }
  if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr, optopt))) {
	if (!*place)
		++optind;
	TELL(": illegal option -- ");
  }
  if (*++oli != ':') {
	optarg = NULL;
	if (!*place)
		++optind;
  } else {
	if (*place)
		optarg = place;
	else if (nargc <= ++optind) {
		place = EMSG;
		TELL(": option requires an argument -- ");
	} else
		optarg = nargv[optind];
	place = EMSG;
	++optind;
  }
  return(optopt);
}

\Rogue\Monster\
else
  echo "will not over write ./getopt.c"
fi
if `test ! -s ./id.c`
then
echo "writing ./id.c"
cat > ./id.c << '\Rogue\Monster\'
/*
 *	@(#)id.c	1.1	09/02/89	18:21:55	agc
 *
 *	Copyright Joypace Ltd, UK, 1989. All rights reserved.
 *	This file may be freely distributed provided that this
 *	notice remains attached.
 *
 *	agcpp - a version of a C pre-processor.
 *
 *	id.c - long identifier name folding.
 *
 *	Compile time flags:
 *	ATT		Unix System V.[23]
 *	BSD		Unix BSD4.[23]
 *	ZORTECH		Zortech C++, v1.05
 *	TURBOC		Turbo C, 1.5
 *	MSC		Microsoft C, 5.0
 *	MINIX		Minix 1.2
 */
#ifndef lint
static char	*idnsccsid = "@(#)id.c	1.1 09/02/89 18:21:55 agc";
#endif /* not lint */

#include <stdio.h>

#define EXTERN extern
#include "defs.h"

typedef struct idstr {
	char		*i_name;
	char		*i_alias;
	struct idstr	*i_next;
	struct idstr	*i_prev;
} ID;

typedef struct hashid {
	ID	*hi_head;
	ID	*hi_tail;
} HID;

static HID	ids[HASHTABLEN];
static int	idnum;

void
addid(old, new)
char	*old;
char	*new;
{
	int	n;
	ID	*ip;

	n = hash(old, compchars);
	for (ip = ids[n].hi_head ; ip ; ip = ip->i_next)
		if (strcmp(old, ip->i_name) == 0)
			return;
	NEW(ID, ip);
	ip->i_name = strnsave(old, strlen(old));
	ip->i_alias = strnsave(new, strlen(new));
	if (ids[n].hi_head == (ID *) NULL)
		ids[n].hi_head = ip;
	else
		ids[n].hi_tail->i_next = ip;
	ip->i_prev = ids[n].hi_tail;
	ids[n].hi_tail = ip;
}

void
delid(old)
char	*old;
{
	int	n;
	ID	*ip;

	n = hash(old, compchars);
	for (ip = ids[n].hi_head ; ip ; ip = ip->i_next)
		if (strcmp(old, ip->i_name) == 0)
			break;
	if (ip == (ID *) NULL)
		return;
	(void) free(ip->i_name);
	(void) free(ip->i_alias);
	if (ip->i_next == (ID *) NULL)
		ids[n].hi_tail = ip->i_prev;
	else
		ip->i_next->i_prev = ip->i_prev;
	if (ip->i_prev == (ID *) NULL)
		ids[n].hi_head = ip->i_next;
	else
		ip->i_prev->i_next = ip->i_next;
	(void) free(ip);
}

char *
getclash(id)
char	*id;
{
	int	n;
	ID	*ip;

	n = hash(id, compchars);
	for (ip = ids[n].hi_head ; ip ; ip = ip->i_next)
		if (strncmp(id, ip->i_name, compchars) == 0)
			return(ip->i_alias);
	return((char *) NULL);
}

char *
getid(id)
char	*id;
{
	int	n;
	ID	*ip;

	n = hash(id, compchars);
	for (ip = ids[n].hi_head ; ip ; ip = ip->i_next)
		if (strcmp(id, ip->i_name) == 0)
			return(ip->i_alias);
	return((char *) NULL);
}

char *
newid()
{
	static char	idname[10];

	for (;;) {
		(void) sprintf(idname, "i%05d", idnum);
		if (getclash(idname) == (char *) NULL)
			return(idname);
		idnum = (idnum == 99999) ? 0 : idnum + 1;
	}
}

char *
nameof(id, len)
char	*id;
int	len;
{
	char	*clashname;
	char	*alias;

	if (len < compchars) {
		if ((alias = getid(id)) == (char *) NULL)
			addid(id, id);
		return(id);
	}
	if ((alias = getid(id)) != (char *) NULL)
		return(alias);
	clashname = strnsave(id, compchars);
	if (getclash(clashname) == (char *) NULL) {
		addid(id, id);
		(void) free(clashname);
		return(id);
	}
	alias = newid();
	addid(id, alias);
	(void) free(clashname);
	return(alias);
}

void
initids()
{
	addid("register", "register");
	addid("unsigned", "unsigned");
	addid("volatile", "volatile");
	addid("continue", "continue");
}
\Rogue\Monster\
else
  echo "will not over write ./id.c"
fi
if `test ! -s ./if.c`
then
echo "writing ./if.c"
cat > ./if.c << '\Rogue\Monster\'
/*
 *	@(#)if.c	1.4	25/01/89	15:45:12	agc
 *
 *	Copyright Joypace Ltd., UK, 1989. All rights reserved.
 *	This code may be freely distributed, provided that this
 *	notice remains attached.
 *
 *	agcpp - a version of a C pre-processor.
 *
 *	if.c - contains all the code for #if directives.
 *
 *	Compile-time flags:
 *	ATT		Unix System V.[23]
 *	BSD		BSD 4.[23] Unix
 *	ZORTECH		Zortech C++, v1.05.
 *	TURBOC		Turbo C 1.5
 *	MSC		Microsoft C 5.0
 */
#ifndef lint
static char	*ifnsccsid = "@(#)if.c	1.4 25/01/89 15:45:12 agc";
#endif /* not lint */

#include <stdio.h>

#define EXTERN	extern
#include "defs.h"

static char	*unaries = "+-~!";

#define NEXTTOKEN(str) \
	if (!gettoken(fp, 1, &t)) \
		error(0, "Unexpected end of file in %s", str)


/*
 *	BNF of an #if directive follows:
 *
 *	ifstatement ::= cond
 *		| cond && cond
 *		| cond || cond
 *
 *	cond ::= unary ( expr )
 *		| unary expr
 *		| unary expr
 *		| ( expr )
 *		expr
 *
 *	expr ::= term
 *		| term == term
 *		| term != term
 *		| term >= term
 *		| term <= term
 *		| term > term
 *		| term < term
 *
 *	term ::= prim
 *		| prim + prim
 *		| prim - prim
 *		| prim * prim
 *		| prim / prim
 *		| prim % prim
 *		| prim & prim
 *		| prim | prim
 *		| prim ^ prim
 *		| prim << prim
 *		| prim >> prim
 *
 *	prim ::= NUMBER
 *		| defined ( macroname )
 *		| defined macroname
 *		| macroname
 *
 *	unary ::= +
 *		| -
 *		| ~
 *		| !
 */


/* recognise a primary symbol */
int
prim(fp)
FILE	*fp;
{
	MACRO	*mp;
	int	val;
	int	b = 0;

	switch(t.t_type) {
	case T_NUMBER :
		val = atoi(t.t_token);
		NEXTTOKEN("#if");
		return(val);
	case T_WORD :
		if (STREQ(t.t_token, "defined")) {
			NEXTTOKEN("#if");
			if (t.t_token[0] == '(') {
				b++;
				NEXTTOKEN("#if");
			}
			val = (isdefined(t.t_token) != (MACRO *) NULL);
			if (b)
				NEXTTOKEN("#if");
			NEXTTOKEN("#if");
			return(val);
		}
		if ((mp = isdefined(t.t_token)) == (MACRO *) NULL)
			return(0);
		NEXTTOKEN("#if");
		return(atoi(mp->m_val));
	default :
		return(0);
	}
}


/* recognise a term */
int
term(fp)
FILE	*fp;
{
	int	left;
	int	zero;

	left = prim(fp);
	if (STREQ(t.t_token, "+")) {
		NEXTTOKEN("#if");
		return(left + prim(fp));
	}
	if (STREQ(t.t_token, "-")) {
		NEXTTOKEN("#if");
		return(left - prim(fp));
	}
	if (STREQ(t.t_token, "*")) {
		NEXTTOKEN("#if");
		return(left * prim(fp));
	}
	if (STREQ(t.t_token, "/")) {
		NEXTTOKEN("#if");
		if ((zero = prim(fp)) == 0)
			return(0);
		return(left / zero);
	}
	if (STREQ(t.t_token, "%")) {
		NEXTTOKEN("#if");
		return(left % prim(fp));
	}
	if (STREQ(t.t_token, "&")) {
		NEXTTOKEN("#if");
		return(left & prim(fp));
	}
	if (STREQ(t.t_token, "|")) {
		NEXTTOKEN("#if");
		return(left | prim(fp));
	}
	if (STREQ(t.t_token, "^")) {
		NEXTTOKEN("#if");
		return(left ^ prim(fp));
	}
	if (STREQ(t.t_token, "<<")) {
		NEXTTOKEN("#if");
		return(left << prim(fp));
	}
	if (STREQ(t.t_token, ">>")) {
		NEXTTOKEN("#if");
		return(left >> prim(fp));
	}
	return(left);
}


/* recognise an expression */
int
expr(fp)
FILE	*fp;
{
	int	left;

	left = term(fp);
	if (STREQ(t.t_token, "==")) {
		NEXTTOKEN("#if");
		return(left == term(fp));
	}
	if (STREQ(t.t_token, "!=")) {
		NEXTTOKEN("#if");
		return(left != term(fp));
	}
	if (STREQ(t.t_token, ">=")) {
		NEXTTOKEN("#if");
		return(left >= term(fp));
	}
	if (STREQ(t.t_token, "<=")) {
		NEXTTOKEN("#if");
		return(left <= term(fp));
	}
	if (STREQ(t.t_token, ">")) {
		NEXTTOKEN("#if");
		return(left > term(fp));
	}
	if (STREQ(t.t_token, "<")) {
		NEXTTOKEN("#if");
		return(left < term(fp));
	}
	return(left);
}


/* recognise an if condition */
int
cond(fp)
FILE	*fp;
{
	int	unary = 0;
	int	result;
	int	b = 0;

	if (index(unaries, t.t_token[0]) != (char *) NULL) {
		unary = t.t_token[0];
		NEXTTOKEN("#if");
	}
	if (t.t_token[0] == '(') {
		b++;
		NEXTTOKEN("#if");
	}
	result = expr(fp);
	if (b)
		NEXTTOKEN("#if");
	switch(unary) {
	case '!' :
		return(!result);
	case '~' :
		return(~result);
	case '-' :
		return(-result);
	case '+' :
	case 0 :
		return(result);
	}
	return(result);
}


/* perform the if directive */
int
doif(fp, doing)
FILE	*fp;
int	doing;
{
	int	left;

	if (!doing)
		return(0);
	NEXTTOKEN("#if");
	left = cond(fp);
	while (t.t_type != T_EOLN) {
		if (STREQ(t.t_token, "&&")) {
			NEXTTOKEN("#if");
			left = left && cond(fp);
		} else if (STREQ(t.t_token, "||")) {
			NEXTTOKEN("#if");
			left = left || cond(fp);
		} else
			NEXTTOKEN("#if");
	}
	return(left);
}


/* perform the ifdef and ifndef directives */
int
doifdef(fp, n, doing)
FILE	*fp;
int	n;
int	doing;
{
	MACRO	*mp;

	if (!doing) {
		while (gettoken(fp, 1, &t))
			if (t.t_type == T_EOLN)
				break;
		return(0);
	}
	NEXTTOKEN((n) ? "#ifdef" : "ifndef");
	mp = isdefined(t.t_token);
	NEXTTOKEN((n) ? "#ifdef" : "ifndef");
	return((n) ? (mp != (MACRO *) NULL) : (mp == (MACRO *) NULL));
}

\Rogue\Monster\
else
  echo "will not over write ./if.c"
fi
if `test ! -s ./inc.c`
then
echo "writing ./inc.c"
cat > ./inc.c << '\Rogue\Monster\'
/*
 *	@(#)inc.c	1.6	07/02/89	15:41:32	agc
 *
 *	Copyright Joypace Ltd., UK, 1989. All rights reserved.
 *	This code may be freely distributed, provided that this
 *	notice remains attached.
 *
 *	agcpp - a version of a C pre-processor.
 *
 *	inc.c - contains all the code for #include directives.
 *
 *	Compile-time flags:
 *	ATT		Unix System V.[23]
 *	BSD		BSD 4.[23] Unix
 *	ZORTECH		Zortech C++, v1.05.
 *	TURBOC		Turbo C 1.5
 *	MSC		Microsoft C 5.0
 */
#ifndef lint
static char	*incnsccsid = "@(#)inc.c	1.6 07/02/89 15:41:32 agc";
#endif /* not lint */

#include <stdio.h>

#define EXTERN	extern
#include "defs.h"

typedef struct dirinc {
	char		*d_dir;
	struct dirinc	*d_next;
} INCDIR;

typedef struct incfile {
	char		*i_file;
	int		i_level;
	struct incfile	*i_next;
} INCFILE;

static INCFILE	*ifilehead;
static INCFILE	*ifiletail;
static INCDIR	*idirhead;


/* insert a directory at the front of the directory list */
void
insdir(s)
char	*s;
{
	INCDIR	*dp;

	NEW(INCDIR, dp);
	dp->d_dir = strnsave(s, strlen(s));
	dp->d_next = idirhead;
	idirhead = dp;
}


/* is it ok to include this file? */
int
okfile(f, level)
char	*f;
int	level;
{
	INCFILE	*ip;

	for (ip = ifilehead ; ip ; ip = ip->i_next) {
		if (STREQ(ip->i_file, f)) {
			error(0, "File '%s' already included", f);
			return(0);
		}
	}
	NEW(INCFILE, ip);
	ip->i_file = strnsave(f, strlen(f));
	ip->i_level = level;
	if (ifilehead == (INCFILE *) NULL)
		ifilehead = ip;
	else
		ifiletail->i_next = ip;
	ifiletail = ip;
	return(1);
}


/* getthe name of the file, put it in fn, and set start of directory search */
void
incname(tp, fn, fp, inp, dpp)
TOKEN	*tp;
char	*fn;
FILE	*fp;
char	*inp;
INCDIR	**dpp;
{
	MACRO	*mp;
	TOKEN	mt;
	char	*cp1;

	switch(tp->t_type) {
	case T_STRING :
		*dpp = idirhead;
		(void) strcpy(fn, &tp->t_token[1]);
		fn[tp->t_len - 2] = 0;
		break;
	case T_WORD :
		if ((mp = isdefined(tp->t_token)) == (MACRO *) NULL)
			error(1, "Bad include syntax", (char *) NULL);
		cp1 = tmp;
		inp = mp->m_val;
		(void) expmac(mp, &cp1, (FILE *) NULL, &inp);
		inp = tmp;
		sgettoken(&inp, 1, &mt);
		incname(&mt, fn, (FILE *) NULL, inp, dpp);
		break;
	default :
		*dpp = idirhead->d_next;
		if (fp != (FILE *) NULL) {
			if (!gettoken(fp, 1, &t))
				error(1, "Bad include syntax", (char *) NULL);
			for (fn[0] = 0 ; t.t_token[0] != '>' ; ) {
				(void) strcat(fn, t.t_token);
				if (!gettoken(fp, 1, &t))
					error(1, "Bad include syntax",
								(char *) NULL);
			}
		} else {
			mt.t_type = T_SPACE;
			sgettoken(&inp, 1, &mt);
			for (fn[0] = 0 ; mt.t_token[0] != '>' ; ) {
				(void) strcat(fn, mt.t_token);
				sgettoken(&inp, 1, &mt);
				if (mt.t_type == T_EOLN)
					error(1, "Bad include syntax",
								(char *) NULL);
			}
		}
	}
}


/* perform the include directive */
void
doinclude(fp, level)
FILE	*fp;
int	level;
{
	INCDIR	*dp;
	FILE	*newfp;
	char	fn[BUFSIZ];
	char	*oldname;
	int	oldline;

	if (!gettoken(fp, 1, &t))
		error(1, "Bad include syntax", (char *) NULL);
	oldname = strnsave(filename, strlen(filename));
	oldline = lineno;
	ilevel += 1;
	incname(&t, fn, fp, (char *) NULL, &dp);
	if (fn[0] == '/') {
		(void) strcpy(filename, fn);
		newfp = fopen(filename, "r");
	} else {
		for ( ; dp ; dp = dp->d_next) {
			(void) sprintf(filename, "%s/%s", dp->d_dir, fn);
			if ((newfp = fopen(filename, "r")) != (FILE *) NULL)
				break;
		}
	}
	if (newfp == (FILE *) NULL) {
		(void) strcpy(filename, oldname);
		error(1, "can't find include file '%s'", fn);
	}
	clrtoeoln(fp);
	lineno = 0;
	if (okfile(filename, ilevel))
		doblock(newfp, 1, level, 1);
	(void) fclose(newfp);
	lineno = oldline;
	ilevel -= 1;
	(void) strcpy(filename, oldname);
	(void) nfree(oldname);
}

\Rogue\Monster\
else
  echo "will not over write ./inc.c"
fi
if `test ! -s ./mac.c`
then
echo "writing ./mac.c"
cat > ./mac.c << '\Rogue\Monster\'
/*
 *	@(#)mac.c	1.11	09/02/89	18:22:10	agc
 *
 *	Copyright Joypace Ltd, UK, 1989. All rights reserved.
 *	This file may be freely distributed provided that this
 *	notice remains attached.
 *
 *	agcpp - a version of a C pre-processor.
 *
 *	mac.c - macro expansion and definition routines.
 *
 *	Compile time flags:
 *	ATT		Unix System V.[23]
 *	BSD		Unix BSD4.[23]
 *	ZORTECH		Zortech C++, v1.05
 *	TURBOC		Turbo C, 1.5
 *	MSC		Microsoft C, 5.0
 *	MINIX		Minix 1.2
 */
#ifndef lint
static char	*macnsccsid = "@(#)mac.c	1.11 09/02/89 18:22:10 agc";
#endif /* not lint */

#include <stdio.h>

#define EXTERN	extern
#include "defs.h"

#ifdef ATT
#define time_t	long
#include <time.h>
extern time_t	time();
#endif

#ifdef BSD
#include <sys/types.h>
#include <sys/time.h>
extern time_t	time();
#endif

#ifdef ZORTECH
#include <time.h>
#endif /* ZORTECH */

#ifdef TURBOC
#include <time.h>
#endif /* TURBOC */

#ifdef MSC
#include <time.h>
#endif /* MSC */

#ifdef MINIX
#define time_t	long
extern time_t	time();
extern char	*ctime();
#endif /* MINIX */

#define STACKSIZE	256

typedef struct bucket {
	MACRO	*h_head;
	MACRO	*h_tail;
} HASH;

typedef struct stack {
	char	*s_name;
	int	s_level;
} STACK;

static HASH	h[HASHTABLEN];
static STACK	stackv[STACKSIZE];
static int	stackc;

extern char	*strnsave();


/* rudimentary, but effective hashing algorithm */
int
hash(s, n)
char	*s;
int	n;
{
	unsigned int	ret;
	int		i;

	for (i = 0, ret = 1 ; *s && i < SIGCHARS && i < n ; i++)
		ret *= *s++;
	return(ret % HASHTABLEN);
}


/* is s defined as a macro? return ptr to it if yes, null otherwise */
MACRO *
isdefined(s)
char	*s;
{
	MACRO	*mp;
	int	n;

	n = hash(s, SIGCHARS);
	for (mp = h[n].h_head ; mp ; mp = mp->m_next)
		if (STREQ(mp->m_name, s))
			return(mp);
	return((MACRO *) NULL);
}


/* stop s being circularly defined - push it on stack */
void
push(s, n)
char	*s;
int	n;
{
	stackv[stackc].s_name = s;
	stackv[stackc++].s_level = n;
}


/* pop the stack */
void
pop()
{
	stackv[--stackc].s_name = (char *) NULL;
}


/* is s being expanded at the moment? */
int
doing(s, n)
char	*s;
int	n;
{
	STACK	*sp;
	int	i;

	for (i = 0, sp = stackv ; i < stackc ; i++, sp++)
		if (STREQ(s, sp->s_name) && sp->s_level < n)
			return(1);
	return(0);
}


/* add a macro */
void
addmacro(name, ap, val, protected)
char	*name;
ARGS	*ap;
char	*val;
char	protected;
{
	MACRO	*mp;
	int	n;

	n = hash(name, SIGCHARS);
	for (mp = h[n].h_head ; mp ; mp = mp->m_next) {
		if (STREQ(mp->m_name, name)) {
			error(mp->m_prot, "redefinition of '%s'", name);
			break;
		}
	}
	if (mp == (MACRO *) NULL) {
		NEW(MACRO, mp);
		mp->m_prev = h[n].h_tail;
		if (h[n].h_head == (MACRO *) NULL)
			h[n].h_head = mp;
		else
			h[n].h_tail->m_next = mp;
		h[n].h_tail = mp;
		mp->m_name = strnsave(name, strlen(name));
	} else
		(void) nfree(mp->m_val);
	mp->m_args = ap;
	mp->m_val = strnsave(val, strlen(val));
	mp->m_prot = protected;
}


/* delete a macro */
void
delmacro(name)
char	*name;
{
	MACRO	*mp;
	int	n;

	n = hash(name, SIGCHARS);
	for (mp = h[n].h_head ; mp ; mp = mp->m_next)
		if (STREQ(mp->m_name, name))
			break;
	if (mp == (MACRO *) NULL)
		return;
	(void) nfree(mp->m_name);
	(void) nfree(mp->m_val);
	if (mp->m_args != (ARGS *) NULL)
		delargs(mp->m_args);
	if (mp == h[n].h_head)
		h[n].h_head = mp->m_next;
	else
		mp->m_prev->m_next = mp->m_next;
	if (mp == h[n].h_tail)
		h[n].h_tail = mp->m_prev;
	else
		mp->m_next->m_prev = mp->m_prev;
	(void) nfree((char *)mp);
}


/* get the arguments from the file */
ARGS *
fgetargs(fp, bracket)
FILE	*fp;
char	bracket;
{
	ARGS	*ap;
	int	n = 0;
	int	b;

	if (bracket) {
		if (*here != '(')
			return((ARGS *) NULL);
		b = 0;
	} else {
		tmp[0] = 0;
		b = 1;
	}
	NEW(ARGS, ap);
	for (;;) {
		if (!gettoken(fp, bracket, &t))
			error(1, "bad macro format", (char *) NULL);
		switch(t.t_token[0]) {
		case ',' :
			if (b == 1) {
				ap->a_argv[ap->a_argc++] = strnsave(tmp, n);
				tmp[0] = 0;
				n = 0;
				continue;
			}
			break;
		case '(' :
			if (b++ == 0) {
				tmp[0] = 0;
				n = 0;
				continue;
			}
			break;
		case ')' :
			if (--b == 0) {
				if (n > 0)
					ap->a_argv[ap->a_argc++] =
							strnsave(tmp, n);
				return(ap);
			}
			break;
		}
		(void) strcat(tmp, t.t_token);
		n += t.t_len;
	}
}


/* get the arguments from the *cpp */
ARGS *
sgetargs(cpp)
char	**cpp;
{
	TOKEN	mt;
	ARGS	*ap;
	char	*start;
	int	b = 0;

	if (**cpp != '(')
		return((ARGS *) NULL);
	NEW(ARGS, ap);
	for (;;) {
		sgettoken(cpp, 1, &mt);
		switch(mt.t_token[0]) {
		case '(' :
			if (b++ == 0)
				start = *cpp;
			break;
		case ')' :
			if (--b == 0) {
				if (*cpp - start > 1)
					ap->a_argv[ap->a_argc++] =
							strnsave(start,
							*cpp - start - 1);
				return(ap);
			}
			break;
		case ',' :
			if (b == 1) {
				ap->a_argv[ap->a_argc++] = strnsave(start,
							*cpp - start - 1);
				start = *cpp;
			}
			break;
		}
	}
}


/* perform the define directive */
void
dodefine(fp)
FILE	*fp;
{
	TOKEN	name;
	ARGS	*ap;

	name.t_type = T_SPACE;
	if (!gettoken(fp, 1, &name))
		error(1, "Bad define syntax", (char *) NULL);
	ap = fgetargs(fp, 1);
	tmp[0] = 0;
	for (;;) {
		if (!gettoken(fp, 0, &t))
			error(1, "Bad define syntax", (char *) NULL);
		if (t.t_type == T_EOLN)
			break;
		if (t.t_type == T_SPACE)
			(void) strcat(tmp, " ");
		else
			(void) strcat(tmp, t.t_token);
	}
	if (name.t_type == T_WORD)
		addmacro(name.t_token, ap, tmp, 0);
	else
		error(0, "illegal macro name '%s'", name.t_token);
}


/* an ansi predefined string - output it */
void
expansi(s, outp)
char	*s;
char	**outp;
{
	time_t	tim;
	char	*cp;

	if (STREQ(s, "__FILE__")) {
		(void) strcpy(*outp, filename);
		*outp += strlen(filename);
		return;
	}
	if (STREQ(s, "__LINE__")) {
		(void) sprintf(tmp, "%d", lineno);
		(void) strcpy(*outp, tmp);
		*outp += strlen(tmp);
		return;
	}
	if (STREQ(s, "__DATE__")) {
		(void) time(&tim);
		cp = ctime(&tim);
		(void) strncpy(*outp, &cp[4], 6);
		*outp += 6;
		(void) strncpy(*outp, &cp[19], 5);
		*outp += 5;
		**outp = 0;
		return;
	}
	if (STREQ(s, "__TIME__")) {
		(void) time(&tim);
		cp = ctime(&tim);
		(void) strncpy(*outp, &cp[11], 8);
		*outp += 8;
		**outp = 0;
		return;
	}
	if (STREQ(s, "__STDC__")) {
		(void) strcpy(*outp, "1");
		outp += 1;
	}
}


/* make the argument s into a string */
void
stringize(s, outp)
char	*s;
char	**outp;
{
	*(*outp)++ = '"';
	while (*s) {
		if (*s == '"' || *s == '\\')
			*(*outp)++ = '\\';
		*(*outp)++ = *s++;
	}
	*(*outp)++ = '"';
}


/* is the string s one of the formal arguments? */
int
isarg(s, formal)
char	*s;
ARGS	*formal;
{
	char	**cpp;
	int	i;

	if (formal == (ARGS *) NULL)
		return(-1);
	for (i = 0, cpp = formal->a_argv ; i < formal->a_argc ; i++, cpp++)
		if (STREQ(s, *cpp))
			return(i);
	return(-1);
}


/* expand the macro mp */
int
expmac(mp, outp, fp, inp)
MACRO	*mp;
char	**outp;
FILE	*fp;
char	**inp;
{
	TOKEN	mt;
	ARGS	*actual;
	char	*cp;
	int	ac;

	if (mp->m_prot) {
		expansi(mp->m_name, outp);
		return(1);
	}
	actual = (mp->m_args) ? (fp) ? fgetargs(fp, 1) : sgetargs(inp) : NULL;
	if (mp->m_args && !actual) {
		error(0, "Arguments to %s needed", mp->m_name);
		return(0);
	}
	if (mp->m_args && mp->m_args->a_argc != actual->a_argc) {
		error(0, "Argument %d mismatch", (char *) mp->m_args->a_argc);
		delargs(actual);
		return(0);
	}
	cp = mp->m_val;
	mt.t_type = T_SPACE;
	for (;;) {
		sgettoken(&cp, 0, &mt);
		if (mt.t_type == T_EOLN)
			break;
		if (mt.t_type == T_WORD) {
			if ((ac = isarg(mt.t_token, mp->m_args)) >= 0) {
				(void) strcpy(*outp, actual->a_argv[ac]);
				*outp += strlen(actual->a_argv[ac]);
				continue;
			}
		}
		if (mt.t_type == T_HASH) {
			sgettoken(&cp, 1, &mt);
			if ((ac = isarg(mt.t_token, mp->m_args)) >= 0) {
				stringize(actual->a_argv[ac], outp);
				continue;
			}
			continue;
		}
		(void) strcpy(*outp, mt.t_token);
		*outp += mt.t_len;
	}
	if (actual != (ARGS *) NULL)
		delargs(actual);
	return(1);
}


/* expand the word s */
void
expand(s, fp)
char	*s;
FILE	*fp;
{
	MACRO	*mp;
	TOKEN	next;
	TOKEN	mt;
	char	one[BUFSIZ];
	char	two[BUFSIZ];
	char	*nextp;
	char	*outp;
	char	*inp;
	char	*cp;
	char	isone;
	int	around;
	int	rescan;

	(void) strcpy(one, s);
	isone = 1;
	around = 0;
	do {
		mt.t_type = next.t_type = T_SPACE;
		rescan = 0;
		inp = (isone) ? one : two;
		*(outp = (isone) ? two : one) = 0;
		isone = 1 - isone;
		for (;;) {
			sgettoken(&inp, 0, &mt);
			nextp = inp;
			sgettoken(&nextp, 1, &next);
			if (mt.t_type == T_EOLN) {
				if (mt.t_token[0] == '\n') {
					*outp++ = '\n';
					*outp = 0;
				}
				break;
			}
			if (next.t_type == T_HASHHASH) {
				(void) strcpy(outp, mt.t_token);
				outp += mt.t_len;
				sgettoken(&inp, 1, &mt);	/* skip ## */
				sgettoken(&inp, 1, &mt);
				if (mt.t_type == T_EOLN)
					break;
				(void) strcpy(outp, mt.t_token);
				outp += mt.t_len;
				rescan = 1;
				continue;
			}
			if (mt.t_type != T_WORD) {
				(void) strcpy(outp, mt.t_token);
				outp += mt.t_len;
				continue;
			}
			if ((mp = isdefined(mt.t_token)) != (MACRO *) NULL &&
			    !doing(mt.t_token, around)) {
				push(mp->m_name, around);
				rescan += expmac(mp, &outp,
					(around == 0) ? fp : (FILE *) NULL,
					(around == 0) ? (char **) NULL : &inp);
			} else {
				cp = nameof(mt.t_token, mt.t_len);
				(void) strcpy(outp, cp);
				outp += strlen(cp);
			}
		}
		around += 1;
	} while (rescan);
	while (stackc)
		pop();
	output((isone) ? one : two, strlen((isone) ? one : two));
}
\Rogue\Monster\
else
  echo "will not over write ./mac.c"
fi
if `test ! -s ./malloc.c`
then
echo "writing ./malloc.c"
cat > ./malloc.c << '\Rogue\Monster\'
/*
 *	@(#)malloc.c	1.1	23/01/89	15:47:28	agc
 *
 *	When will they fix those library routines? Kernighan & Ritchie
 *	memory routines.
 *
 *	Compile-time flags:
 *	ATT		Unix System V.[23]
 *	BSD		BSD 4.[23] Unix
 *	ZORTECH		Zortech C++, v1.05.
 *	TURBOC		Turbo C 1.5
 *	MSC		Microsoft C 5.0
 */
#include <stdio.h>

typedef int	ALIGN;

union header {
	struct {
		union header	*next;
		unsigned	size;
	} s;
	ALIGN	x;
};

typedef union header	HEADER;

static HEADER	base;
static HEADER	*allocp = (HEADER *) NULL;

#define NALLOC	128

void
nfree(ap)
char	*ap;
{
	register HEADER	*p, *q;

	p = (HEADER *) ap - 1;
	for (q = allocp ; !(p >q && p <q->s.next) ; q = q->s.next)
		if (q >= q->s.next && (p > q || p < q->s.next))
			break;
	if (p + p->s.size == q->s.next) {
		p->s.size += q->s.next->s.size;
		p->s.next = q->s.next->s.next;
	} else
		p->s.next = q->s.next;
	if (q + q->s.size == p) {
		q->s.size += p->s.size;
		q->s.next = p->s.next;
	} else
		q->s.next = p;
	allocp = q;
}

static HEADER *
morecore(nu)
unsigned nu;
{
	register HEADER	*up;
	register char	*cp;
	register int	rnu;
	char		*sbrk();

	rnu = NALLOC * ((nu + NALLOC - 1) / NALLOC);
	cp = sbrk(rnu * sizeof(HEADER));
	if ((int) cp == -1)
		return((HEADER *) NULL);
	up = (HEADER *)cp;
	up->s.size = rnu;
	(void) nfree((char *)(up+1));
	return(allocp);
}

char *
nmalloc(nbytes)
unsigned nbytes;
{
	register HEADER	*p;
	register HEADER	*q;
	register int	nunits;

	nunits = 1 + (nbytes+sizeof(HEADER)-1)/sizeof(HEADER);
	if ((q = allocp) == (HEADER *) NULL) {
		base.s.next = allocp = q = &base;
		base.s.size = 0;
	}
	for (p = q->s.next ; ; q = p, p = p->s.next) {
		if (p->s.size >= nunits) {
			if (p->s.size == nunits)
				q->s.next = p->s.next;
			else {
				p->s.size -= nunits;
				p += p->s.size;
				p->s.size = nunits;
			}
			allocp = q;
			return((char *)(p+1));
		}
		if (p == allocp)
			if ((p = morecore(nunits)) == (HEADER *) NULL)
				return((char *) NULL);
	}
}

char *
ncalloc(nel, nbytes)
unsigned nel;
unsigned nbytes;
{
	unsigned	siz = nel * nbytes;
	char		*cp;

	if ((cp = nmalloc(siz)) == (char *) NULL)
		return((char *) NULL);
#ifdef ATT
	memset(cp, 0, siz);
#endif /* ATT */
#ifdef BSD
	bzero(cp, siz);
#endif /* BSD */
	return(cp);
}

\Rogue\Monster\
else
  echo "will not over write ./malloc.c"
fi
if `test ! -s ./parse.c`
then
echo "writing ./parse.c"
cat > ./parse.c << '\Rogue\Monster\'
/*
 *	@(#)parse.c	1.8	07/02/89	15:02:12	agc
 *
 *	Copyright Joypace Ltd., UK, 1989. All rights reserved.
 *	This code may be freely distributed, provided that this
 *	notice remains attached.
 *
 *	agcpp - a version of a C pre-processor.
 *
 *	parse.c - contains all the parser code
 *
 *	Compile-time flags:
 *	ATT		Unix System V.[23]
 *	BSD		BSD 4.[23] Unix
 *	ZORTECH		Zortech C++, v1.05.
 *	TURBOC		Turbo C 1.5
 *	MSC		Microsoft C 5.0
 */
#ifndef lint
static char	*parsensccsid = "@(#)parse.c	1.8 07/02/89 15:02:12 agc";
#endif /* not lint */

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

#define EXTERN	extern
#include "defs.h"

static char	*id1 = /* first characters of an identifier */
	"_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static char	*id2 = /* subsequent characters of an identifier */
	"_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

/* operators of different lengths */
static char	*op3[] = {
	">>=", "<<=", 0
};
static char	*op2[] = {
	"==", "!=", "++", "--", "->", "&&", "||", "+=", "-=",
	">>", "<<", "*=", "/=", "%=", "&=", "|=", "^=", 0
};
static char	*op1 =
	";=+-*(){}[].&/%<>|^,?!~:";

#define ISNL(c)	((c) == '\r' || (c) == '\n')


/* read a line into buf, folding trigraphs, returning 0 at eof, 1 otherwise */
int
readline(fp)
FILE	*fp;
{
	char	*cp;

	if ((here = fgets(buf, sizeof(buf), fp)) == (char *) NULL)
		return(0);
	lineno += 1;
	for (cp = buf ; *cp != 0 ; ) {
		if (strncmp(cp, "??", 2) == 0) {
			cp += 2;
			switch(*cp++) {
			case '=' :
				*here++ = '#';
				break;
			case '(' :
				*here++ = '[';
				break;
			case ')' :
				*here++ = ']';
				break;
			case '<' :
				*here++ = '{';
				break;
			case '>' :
				*here++ = '}';
				break;
			case '/' :
				*here++ = '\\';
				break;
			case '!' :
				*here++ = '|';
				break;
			case '-' :
				*here++ = '-';
				break;
			case '\'' :
				*here++ = '^';
				break;
			default :
				*here++ = '?';
				cp -= 2;
			}
		} else
			*here++ = *cp++;
	}
	*here = 0;
	here = buf;
	return(1);
}


/* get a token from the file, returning 0 at eof, 1 otherwise */
int
gettoken(fp, ignspace, tp)
FILE	*fp;
char	ignspace;
TOKEN	*tp;
{
	char	**cpp;
	char	*start;
	char	*cp;
	int	base;
	int	dig;
	int	num;
	int	i;

	for (;;) {
		if (tp->t_type == T_EOLN) {
			if (!readline(fp))
				return(0);
		}
		if (*here == '#') {
			if (*(here+1) == '#') {
				(void) strcpy(tp->t_token, "##");
				tp->t_type = T_HASHHASH;
				tp->t_len = 2;
				here += 2;
			} else {
				(void) strcpy(tp->t_token, "#");
				tp->t_type = T_HASH;
				tp->t_len = 1;
				here++;
			}
			return(1);
		}
		if (*here == '\\' && ISNL(*(here + 1))) {
			if (!readline(fp))
				return(0);
		}
		if (ISNL(*here)) {
			(void) strcpy(tp->t_token, "\n");
			tp->t_type = T_EOLN;
			tp->t_len = 1;
			return(1);
		}
		if (isspace(*here)) {
			for (start = here, i = 0 ; 
			     *here && isspace(*here) && !ISNL(*here) ;
			     here++, i++)
				;
			if (ignspace)
				continue;
			(void) strncpy(tp->t_token, start, i);
			tp->t_token[here - start] = 0;
			tp->t_type = T_SPACE;
			tp->t_len = i;
			return(1);
		}
		if (*here == '/' && *(here + 1) == '*') {
			here += 2;
			for (;;) {
				while (*here && *here != '*' && !ISNL(*here))
					here++;
				if (*here == '*') {
					if (*(here + 1) == '/')
						break;
					here++;
				}
				if (*here == 0)
					return(0);
				if (ISNL(*here) && !readline(fp))
					return(0);
			}
			here += 2;
			if (ignspace)
				continue;
			(void) strcpy(tp->t_token, " ");
			tp->t_type = T_SPACE;
			tp->t_len = 1;
			return(1);
		}
		if (index(id1, *here)) {
			for (start = here++, i = 1;
			     *here && index(id2, *here) != (char *) NULL &&
			      i < sizeof(tp->t_token) - 1;
			     here++, i++)
				;
			(void) strncpy(tp->t_token, start, i);
			tp->t_token[i] = 0;
			tp->t_type = T_WORD;
			tp->t_len = i;
			return(1);
		}
		if (*here == '"') {
			cp = tp->t_token;
			*cp++ = *here++;
			i = 2;
			while (*here && *here != '"' && i<sizeof(tp->t_token)) {
				if (*here == '\\') {
					switch(*(here+1)) {
					case 'a' :
						*cp++ = '';
						here += 2;
						i++;
						continue;
					case '\n' :
						if (!readline(fp))
							return(0);
						continue;
					default :
						*cp++ = *here++;
						i++;
					}
				}
				*cp++ = *here++;
				i++;
			}
			if (*here == 0) {
				error(0, "%s in string constant", "new line");
				*cp++ = *here;
			} else
				*cp++ = *here++;
			*cp++ = 0;
			tp->t_type = T_STRING;
			tp->t_len = i;
			return(1);
		}
		if (*here == '\'') {
			switch(*++here) {
			case '\\' :
				switch(*++here) {
				case 'a' :
					num = '';
					break;
				case 'n' :
					num = '\n';
					break;
				case 'r' :
					num = '\r';
					break;
				case 'b' :
					num = '\b';
					break;
				case 'f' :
					num = '\f';
					break;
				case 't' :
					num = '\t';
					break;
				case 'v' :
					num = '\v';
					break;
				case '\\' :
					num = '\\';
					break;
				case '\'' :
					num = '\'';
					here++;
					break;
				default :
					(void) sscanf(here, "%o", &num);
					break;
				}
				break;
			default :
				num = *here;
			}
			(void) sprintf(tp->t_token, "%d", num);
			while (*here && *here != '\'')
				here++;
			here++;
			tp->t_type = T_NUMBER;
			tp->t_len = strlen(tp->t_token);
			return(1);
		}
		if (isdigit(*here)) {
			if (*here == '0' &&
			    (*(here+1) == 'x' || *(here+1) == 'X')) {
				here += 2;
				for (num = 0;
				     *here && isxdigit(*here) ;
				     here++) {
					if (index("ABCDEF", *here) != NULL)
						dig = *here - 'A' + 10;
					else if (index("abcdef", *here) != NULL)
						break;
					else
						dig = *here - '0';
					num = num * 16 + dig;
				}
			} else {
				base = (*here == '0') ? 8 : 10;
				for (num = 0; *here && isdigit(*here) ; here++)
					num = num * base + *here - '0';
			}
			(void) sprintf(tp->t_token, "%d", num);
			tp->t_type = T_NUMBER;
			tp->t_len = strlen(tp->t_token);
			return(1);
		}
		for (cpp = op3 ; *cpp ; cpp++) {
			if (strncmp(here, *cpp, 3) == 0) {
				(void) strcpy(tp->t_token, *cpp);
				tp->t_type = T_PUNCT;
				tp->t_len = 3;
				here += 3;
				return(1);
			}
		}
		for (cpp = op2 ; *cpp ; cpp++) {
			if (strncmp(here, *cpp, 2) == 0) {
				(void) strcpy(tp->t_token, *cpp);
				tp->t_type = T_PUNCT;
				tp->t_len = 2;
				here += 2;
				return(1);
			}
		}
		if ((start = index(op1, *here)) != (char *) NULL) {
			(void) strncpy(tp->t_token, here, 1);
			tp->t_token[1] = 0;
			tp->t_type = T_PUNCT;
			tp->t_len = 1;
			here++;
			return(1);
		}
		error(0, "Bad character %d", (char *) *here++);
	}
}


/* get a token from *cpp */
void
sgettoken(cpp, ignspace, tp)
char	**cpp;
char	ignspace;
TOKEN	*tp;
{
	char	**opp;
	char	*cp;
	int	base;
	int	dig;
	int	num;
	int	i;

	for (;;) {
		cp = tp->t_token;
		if (**cpp == '#') {
			if (*(*cpp + 1) == '#') {
				(void) strcpy(tp->t_token, "##");
				tp->t_type = T_HASHHASH;
				tp->t_len = 2;
				(*cpp) += 2;
				return;
			}
			*cp++ = '#';
			*cp = 0;
			tp->t_type = T_HASH;
			tp->t_len = 1;
			(*cpp)++;
			return;
		}
		if (**cpp == 0) {
			*cp = 0;
			tp->t_type = T_EOLN;
			tp->t_len = 0;
			return;
		}
		if (ISNL(**cpp)) {
			*cp++ = **cpp;
			*cp = 0;
			tp->t_type = T_EOLN;
			tp->t_len = 1;
			return;
		}
		if (isspace(**cpp)) {
			for (i = 0;
			     **cpp && isspace(**cpp) && !ISNL(**cpp) ;
			     *cp++ = *(*cpp)++, i++)
				;
			if (ignspace)
				continue;
			*cp = 0;
			tp->t_type = T_SPACE;
			tp->t_len = i;
			return;
		}
		if (**cpp == '/' && *(*cpp + 1) == '*') {
			*cpp += 2;
			while (**cpp && **cpp != '*' && *(*cpp + 1) !='/')
				(*cpp)++;
			*cpp += 2;
			continue;
		}
		if (index(id1, **cpp)) {
			for (*cp++ = *(*cpp)++, i = 1;
			     **cpp && index(id2, **cpp) != (char *) NULL ;
			     *cp++ = *(*cpp)++, i++)
				;
			*cp = 0;
			tp->t_len = i;
			tp->t_type = T_WORD;
			return;
		}
		if (**cpp == '"') {
			for (*cp++ = *(*cpp)++, i = 0;
			     **cpp && **cpp != '"' ;
			     *cp++ = *(*cpp)++, i++)
				if (**cpp == '\\') {
					*cp++ = *(*cpp)++;
					i++;
				}
			*cp++ = *(*cpp)++;
			*cp = 0;
			tp->t_type = T_STRING;
			tp->t_len = i + 2;
			return;
		}
		if (isdigit(**cpp)) {
			if (**cpp == '0' &&
			    (*(*cpp+1) == 'x' || *(*cpp+1) == 'X')) {
				*cpp += 2;
				for (num = 0;
				     **cpp && isxdigit(**cpp) ;
				     (*cpp)++) {
					if (index("ABCDEF", **cpp) != NULL)
						dig = **cpp - 'A' + 10;
					else if (index("abcdef", **cpp) != NULL)
						break;
					else
						dig = **cpp - '0';
					num = num * 16 + dig;
				}
			} else {
				base = (**cpp == '0') ? 8 : 10;
				for (num = 0; **cpp && isdigit(**cpp); (*cpp)++)
					num = num * base + **cpp - '0';
			}
			(void) sprintf(cp, "%d", num);
			tp->t_type = T_NUMBER;
			tp->t_len = strlen(cp);
			return;
		}
		for (opp = op3 ; *opp ; opp++) {
			if (strncmp(*cpp, *opp, 3) == 0) {
				(void) strcpy(cp, *opp);
				tp->t_type = T_PUNCT;
				tp->t_len = 3;
				*cpp += 3;
				return;
			}
		}
		for (opp = op2 ; *opp ; opp++) {
			if (strncmp(*cpp, *opp, 2) == 0) {
				(void) strcpy(cp, *opp);
				tp->t_type = T_PUNCT;
				tp->t_len = 2;
				*cpp += 2;
				return;
			}
		}
		if (index(op1, **cpp) != (char *) NULL) {
			*cp++ = *(*cpp)++;
			*cp = 0;
			tp->t_type = T_PUNCT;
			tp->t_len = 1;
			return;
		}
		error(0, "Bad character %d", (char *) *(*cpp)++);
	}
}


/* flush the rest of the input line */
void
clrtoeoln(fp)
FILE	*fp;
{
	while (t.t_type != T_EOLN)
		if (!gettoken(fp, 1, &t))
			break;
}
\Rogue\Monster\
else
  echo "will not over write ./parse.c"
fi
if `test ! -s ./proto.c`
then
echo "writing ./proto.c"
cat > ./proto.c << '\Rogue\Monster\'
/*
 *	@(#)proto.c	1.5	07/02/89	16:25:33	agc
 *
 *	Copyright Joypace Ltd, UK, 1989. All rights reserved.
 *	This file may be freely distributed provided that this
 *	notice remains attached.
 *
 *	agcpp - a version of a C pre-processor.
 *
 *	proto.c - deal with function prototypes, and new-style argument passing.
 *
 *	Compile time flags:
 *	ATT		Unix System V.[23]
 *	BSD		Unix BSD4.[23]
 *	ZORTECH		Zortech C++, v1.05
 *	TURBOC		Turbo C, 1.5
 *	MSC		Microsoft C, 5.0
 *	MINIX		Minix 1.2
 */
#ifndef lint
static char	*protonsccsid = "@(#)proto.c	1.5 07/02/89 16:25:33 agc";
#endif /* lint */

#include <stdio.h>

#define EXTERN	extern
#include "defs.h"


/* get the last word in s, and put it in out */
void
getname(s, out)
char	*s;
char	*out;
{
	TOKEN	mt;

	mt.t_type = T_SPACE;
	for (;;) {
		sgettoken(&s, 1, &mt);
		if (mt.t_type == T_EOLN)
			return;
		if (mt.t_type == T_WORD)
			(void) strcpy(out, mt.t_token);
	}
}


/* got a function decl/definition - shuffle the args to K & R style */
void
doargs(fp)
FILE	*fp;
{
	TOKEN	mt;
	ARGS	*ap;
	char	**cpp;
	char	*cp;
	int	i;

	ap = fgetargs(fp, 0);
	for (;;) {
		if (!gettoken(fp, 1, &t))
			return;
		if (t.t_type != T_EOLN)
			break;
	}
	switch(t.t_token[0]) {
	case '{' :
		/* ANSI-style args, or no args at all */
		if (ap->a_argc != 1 || strcmp(ap->a_argv[0], "void") != 0) {
			for (i = 0, cpp = ap->a_argv;
			     i < ap->a_argc;
			     cpp++, i++) {
				getname(*cpp, tmp);
				output(tmp, strlen(tmp));
				if (i < ap->a_argc - 1)
					output(", ", 2);
			}
		}
		output(")\n", 2);
		if (ap->a_argc != 1 || strcmp(ap->a_argv[0], "void") != 0) {
			for (i = 0, cpp = ap->a_argv;
			     i < ap->a_argc;
			     cpp++, i++) {
				cp = *cpp;
				mt.t_type = T_SPACE;
				for (;;) {
					sgettoken(&cp, 0, &mt);
					if (mt.t_type == T_EOLN)
						break;
					if (mt.t_type == T_WORD)
						expand(mt.t_token, fp);
					else
						output(mt.t_token, mt.t_len);
				}
				output(";\n", 2);
			}
		}
		block++;
		break;
	case ',' :
	case ';' :
		/* forward declaration */
		output(")", 1);
		break;
	default :
		/* old style args */
		for (i = 0, cpp = ap->a_argv ; i < ap->a_argc ; cpp++, i++) {
			output(*cpp, strlen(*cpp));
			if (i < ap->a_argc - 1)
				output(", ", 2);
		}
		output(")\n", 2);
		do {
			expand(t.t_token, fp);
			if (!gettoken(fp, 0, &t))
				return;
		} while (t.t_token[0] != '{');
		block++;
	}
	output(t.t_token, t.t_len);
	if (ap != (ARGS *) NULL)
		delargs(ap);
}

\Rogue\Monster\
else
  echo "will not over write ./proto.c"
fi
if `test ! -s ./sym.c`
then
echo "writing ./sym.c"
cat > ./sym.c << '\Rogue\Monster\'
#include <stdio.h>

#define EXTERN	extern
#include "defs.h"

#define MAXTYPES	256
#define MAXVARS		128

typedef struct typestr {
	int	t_type;
	int	t_indc;
	char	t_flags;
#define T_UNSIGNED	001
#define T_EXTERN	002
#define T_STATIC	004
#define T_REGISTER	010
#define T_CONST		020
#define T_VOLATILE	040
} TYPE;

typedef struct varstr {
	char	*v_name;
	TYPE	*v_type;
} VAR;

typedef struct funcstr {
	VAR	*f_func;
	int	f_argc;
	VAR	*f_argv[MAXARGS];
	int	f_varargs;
} FUNC;

typedef struct basetype {
	char	*b_base;
	char	*b_name;
} BASE;

static BASE	typev[MAXTYPES];
static int	typec;

static TYPE	*curtyp;

static VAR	*globs[MAXVARS];
static int	globc;
static VAR	*locals[MAXVARS];
static int	localc;
static FUNC	*funcs[MAXVARS];
static int	funcc;

int
findtype(s)
char	*s;
{
	BASE	*bp;
	int	i;

	for (i = 0, bp = typev ; i < typec ; i++, bp++)
		if (strcmp(s, bp->b_name) == 0)
			return(i);
	return(-1);
}

void
inittypes()
{
	typev[typec++].b_name = "int";
	typev[typec++].b_name = "void";
	typev[typec++].b_name = "char";
	typev[typec++].b_name = "short";
	typev[typec++].b_name = "long";
	typev[typec++].b_name = "double";
	typev[typec++].b_name = "float";
}

TYPE *
gettype(s)
char	**s;
{
	char	typ[BUFSIZ];
	TYPE	*tp;
	int	b;
	int	i;

	if (t.t_type != T_WORD) {
		error(0, "bad type syntax '%s'", s);
		return((TYPE *) NULL);
	}
	if (strcmp(t.t_token, "typedef") == 0) {
		sgettoken(s, 1, &t);
		if (strcmp(t.t_token, "struct") == 0) {
			(void) strcpy(typ, "struct ");
			sgettoken(s, 1, &t);
			(void) strcat(typ, t.t_token);
			sgettoken(s, 1, &t);
			if (t.t_token[0] == '{') {
				for (b = 1 ; b != 0 ; ) {
					sgettoken(s, 1, &t);
					if (t.t_token[0] == '{')
						b++;
					else if (t.t_token[0] == '}')
						b--;
				}
			}
		} else
			(void) strcpy(typ, t.t_token);
		sgettoken(s, 1, &t);
		typev[typec].b_base = strnsave(typ, strlen(typ));
		typev[typec++].b_name = strnsave(t.t_token, t.t_len);
		return((TYPE *) NULL);
	}
	NEW(TYPE, tp);
	for (;;) {
		if (strcmp(t.t_token, "extern") == 0) {
			if (tp->t_flags & T_STATIC)
				error(0, "can't be static and external", NULL);
			tp->t_flags |= T_EXTERN;
			sgettoken(s, 1, &t);
		} else if (strcmp(t.t_token, "static") == 0) {
			if (tp->t_flags & T_EXTERN)
				error(0, "can't be static and external", NULL);
			tp->t_flags |= T_STATIC;
			sgettoken(s, 1, &t);
		} else if (strcmp(t.t_token, "unsigned") == 0) {
			tp->t_flags |= T_UNSIGNED;
			sgettoken(s, 1, &t);
		} else if (strcmp(t.t_token, "register") == 0) {
			if (tp->t_flags & T_STATIC)
				error(0, "can't be static and register", NULL);
			else
				tp->t_flags |= T_REGISTER;
			sgettoken(s, 1, &t);
		} else if (strcmp(t.t_token, "volatile") == 0) {
			tp->t_flags |= T_VOLATILE;
			sgettoken(s, 1, &t);
		} else if (strcmp(t.t_token, "const") == 0) {
			tp->t_flags |= T_CONST;
			sgettoken(s, 1, &t);
		} else if (t.t_token[0] == '*') {
			tp->t_indc++;
			sgettoken(s, 1, &t);
		} else if ((i = findtype(t.t_token)) >= 0) {
			tp->t_type = i;
			sgettoken(s, 1, &t);
		} else
			return(tp);
	}
}

VAR *
getvar(s, dotsok)
char	**s;
char	dotsok;
{
	FUNC	*fp;
	VAR	*vp;
	int	i;

	if (curtyp == (TYPE *) NULL || t.t_token[0] != ',') {
		sgettoken(s, 1, &t);
		if (t.t_token[0] == '.' && dotsok) {
			for (i = 0 ; i < 2 ; i++)
				sgettoken(s, 1, &t);
			return((VAR *) NULL);
		}
		curtyp = gettype(s);
	}
	NEW(VAR, vp);
	vp->v_type = curtyp;
	vp->v_name = strnsave(t.t_token, t.t_len);
	sgettoken(s, 1, &t);
	if (t.t_token[0] == ';')
		return(vp);
	if (t.t_token[0] == '(') {
		NEW(FUNC, fp);
		fp->f_varargs = -1;
		fp->f_func = vp;
		for (;;) {
			curtyp == (TYPE *) NULL;
			fp->f_argv[fp->f_argc] = getvar(s, 1);
			if (fp->f_argv[fp->f_argc] == (VAR *) NULL) {
				fp->f_varargs = fp->f_argc;
				sgettoken(s, 1, &t);
				break;
			}
			if (t.t_token[0] == ')')
				break;
			fp->f_argc++;
			sgettoken(s, 1, &t);
		}
		funcs[funcc++] = fp;
	}
	return(vp);
}

\Rogue\Monster\
else
  echo "will not over write ./sym.c"
fi
echo "Finished archive 1 of 2"

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./Readme`
then
echo "writing ./Readme"
cat > ./Readme << '\Rogue\Monster\'
agcpp - ANSI C pre-processor and translator.

Here is an ANSI C conforming pre-processor. It is also a translator from
ANSI C to "K & R C" (with one exception, and one restriction - see below).
There are also, probably, lots of bugs, which my coding style has not
found. Please inform me if you find any of these. Most of the draft
standard's implications, bells and whistles were taken from "The C Book,
featuring the draft ANSI C standard", by Mike Banahan of The Instruction
Set.

This was originally written to replace the old, creaking Minix cpp, because
it was driving me up the wall. As I am working in Berlin, this could get
quite dangerous.

Hopefully, this will allow people to write code in ANSI C, whilst continuing
to use their old compilers - so start writing in ANSI C, folks.

Please note that it's not quick - but I haven't optimised it yet.

1. The directives it will recognise at the moment are :

   #include, #define, #undef, #if, #ifdef, #ifndef,
   #elif, #else, #endif, #line, #error, #pragma, #

   I have also put the #ident processing in there, but default is not to
   have it. If you want it, compile agcpp with -DIDENT_DIR.

2. Token pasting (##) and token stringizing (#arg) are carried out during
   expansion of macros.

3. Comments are recognised as white space within macros.

4. const, volatile and signed will be passed on to the compiler, if ANSI is
   defined (at run-time), or silently forgotten if not.

5. Multiple whitespace within macros is folded to a single space. (Whitespace
   in strings is not touched).

6. Command line arguments (run time) are

   -ANSI for the pre-processor to output ANSI-style C.

   -Cnumber for the pre-processor to fold identifier name longers than
   <number> to an internal format of the name. This is really needed
   for Minix, more than anything else. Default is 8, can be over-ridden
   at compile-time by defining COMPCHARS, and that in term can be
   over-ridden at run-time by this argument.

   -Dsymbol[=value] for a symbol to be defined. This will override any
   previous definition in agcpp, but will be overridden by any definitions
   in the text.

   -Idirectory for an additional include directory to be searched before
   the standard ones.

   -P to suppress line directives for the compiler itself.

   -Usymbol for a symbol to be undefined. It is not an error if symbol is
   not already defined.

7. #if defined(macroname), and #if defined macroname will be recognised.

8. The ANSI standard's __FILE__, __LINE__, __DATE__ and __TIME__ will all
   be recognised and expanded. It will also recognise __STDC__ (it has the
   value 1).

9. It will recognise, and correctly include

   #define NAME	<stdio.h>
   #define INDIRECTNAME	NAME
   #include INDIRECTNAME

   (The number of layers of indirection is unlimited - although why you
   would want to do this is a mystery to me).

10. Character constants are reduced to decimal numbers.

11. Trigraphs are expanded.
   
12. Adjacent strings will be concatenated, even on different lines.

13. Unary '+' is NOT recognised - it was too difficult really, as I'd
    have do a syntax check of the program first, to identify unary '+'
    from (a - b) + (c() / d) etc. Anyway, I don't like unary '+' - I
    consider it ill-conceived, and horrible syntax - so I won't use it.

14. The '\a' (bell) character will be recognised in string and character
    constants.

15. I left "noalias" out - is it still in the standard?

16. Function prototypes. If ANSI is not specified (at run-time), these
    are expanded at the basic level (i.e. not within the definitions in
    a function).

17. New-style argument passing (including const) is performed, and
    translated to old (K & R) style arguments if ANSI is not specified
    (at run-time). Please choose one or the other method of argument
    passing - mixing methods in the same function will not work.

18. I have added code to test the level at which a file was included, and
    if an attempt is made to re-include a file twice, then it will give an
    error message and not include it, if the file was included more deeply
    in the nested includes.

19. Long name identifier folding may or may not be needed - but I took the
    trouble to put it in for Minix's somewhat rudimentary (8 char ids)
    compiler.

It's not as efficient as it could be, but it takes up less space than the
cpp's I've been able to look at. Main target for efficiency is all the
string copying that takes place - I may pass pointers and their lengths when
I get time, but that's some distance away - I'll do it the day after Spurs
win the league, or Rangers do the double.

I may also get around to implementing the run-time library for some systems
sometime, so don't hold your breath.

Constructive comments gratefully received. If you have any flames about
processing time etc, take them somewhere else.

Regards,
Alistair G. Crooks,
Joypace Ltd., 2 Vale Road, Hawkhurst, Kent TN18 4BU, UK. (+44 580 753114)
UUCP Europe:			        ...!mcvax!unido!nixpbe!nixbln!agc   
UUCP the rest of the world:	 ...!uunet!linus!nixbur!nixpbe!nixbln!agc
\Rogue\Monster\
else
  echo "will not over write ./Readme"
fi
echo "Finished archive 2 of 2"
exit
 needed - but I took the
    trouble to put it in for Minix's somewhat rudimentary (8 char ids)
    compiler.

It's not as efficient as it could be, but it takes up less space than the
cpp's I've been able to look at. Main target

Leisner.Henr@xerox.com (marty) (02/23/89)

The preprocessor got munged by the mail system but it seems I was able to
recover it.

In parse.c, line 202 I get "empty character constant" errors and sure
enough, we get a line like:
*cp++ = '';

Is this intentional or did something get lost in transmisssion?

I haven't yet attempt to figure out what really fits in there -- I wanna
see if I can get to compile and run first.

marty
ARPA:	leisner.henr@xerox.com
GV:  leisner.henr
NS:  martin leisner:wbst139:xerox
UUCP:  hplabs!arisia!leisner

droege@infko.UUCP (Detlev Droege) (02/28/89)

In article <11100001@nixbln> agc@nixbln.UUCP writes:
>
>Here's an (almost) ANSI-C conforming pre-processor. Please note that I
>haven't tested it under Minix. Please also note that there are two shell
>archives here. Now, how do I post this using notes?
>
>Regards,
>Alistair G. Crooks,

Well, it's a fine idea, but there seems to be a nasty bug.
I made it run on a SUN (4.2BSD) and another UNIX box (AT&T Sys V),
but in both cases the "squeeze long id-names" feature
didn't work. Example:

	main ()
	{
		int     long_name1;
		int     long_name2;
		int     long_name3;

		exit (0);
	}

yields in

	main ()
	{
		int     long_name1;
		int     i00000;
		int     i00000;         /* <<<=== baaahhh !!! */

		exit (0);
	}

I couldn't trace down the bug in agcpp itself, maybe someone else
did ...

	Waiting for agcpp-patch#1
		Detlev
--
Detlev Droege, Univ. of Koblenz (EWH), Dept. of Computer Sience
	       Rheinau 3-4, D-5400 Koblenz  (West Germany)
UUCP: ..!unido!infko!droege   droege@infko.UUCP   (Voice: +49 261 12156)

n62@np1.hep.nl (Klamer Schutte) (03/02/89)

In article <495@infko.UUCP> droege@infko.UUCP (Detlev Droege) writes:
>In article <11100001@nixbln> agc@nixbln.UUCP writes:
>>
>>Here's an (almost) ANSI-C conforming pre-processor. Please note that I
>>haven't tested it under Minix. Please also note that there are two shell
>>archives here. Now, how do I post this using notes?
>>
>>Regards,
>>Alistair G. Crooks,
>
>Well, it's a fine idea, but there seems to be a nasty bug.
>
  description of the bug involving folding of long names
>Detlev Droege, Univ. of Koblenz (EWH), Dept. of Computer Sience
>	       Rheinau 3-4, D-5400 Koblenz  (West Germany)
>UUCP: ..!unido!infko!droege   droege@infko.UUCP   (Voice: +49 261 12156)

I also did encounter 2 bugs in it:
1 the -ANSI command line flag didn't work; prototyped function came out
  not-prototyped.
2 the following code
#define PARMS(arg) arg
void some_function PARMS((int arg1, int arg2));
  did produce
void some_function (intargs1,intarg2);
  when it should first map the macro to
void some_function (int arg1, int arg2);
  and then make it to
void some_function ();
  I wanted to use this macro to make the same code run with a non-ansi
  compiler; this will use the macro
#define PARMS(arg) /* arg */	

I don't mind about bug 1; when somebody fixes bug 2 i will start using the 
program.

Klamer
ps all running under minix-st with the ACK compiler
-- 
________________________________________________________________________________
Klamer Schutte			mcvax!nikhefh!n62	      n62@nikhefh.hep.nl

agc@nixbln.UUCP (03/03/89)

Well, at least agcpp got out of here - that's about all you can say.

1. Marty Leisner (leisner@arisia.UUCP) said that the BELL characters
   hadn't made it across the pond. Fixes (below) to parse.c should sort
   this. Thanks, Marty. Sorry, everybody.

2. Detlev Droege (droege@infko.UUCP) pointed out the long-name folding
   didn't work correctly. The following fix to id.c should cure it.
   Danke, Detlev.

3. Klamer Schutte (n62@nikhefh.hep.nl) said that the ANSI argument removed
   the ANSI-style arguments. Unfortunately, I can't reproduce this.

Script started on Fri Mar  3 12:22:51 1989
% cat t1
char    *strnsave(char *s, int n);


main()
{
}
% agcpp -ANSI t1
char    *strnsave(char *s, int n);


main()
{
}
% exit
%
script done on Fri Mar  3 12:23:07 1989

   Can you give me some more info, Klamer? Alstublieft.

4. Klamer also pointed out a rather nasty bug which prevented white space
   being expanded within macro arguments. Following fix to mac.c should
   cure this. Dank je wel, Klamer.

5. I have also noticed that ANSI C varargs style functions will be expanded
   wrongly - the fixes to proto.c should cure this.

6. If anyone finds out what the sym.c file does, could they tell me please!

So official fixes(#1) to agcpp follow. Thanks once again to everyone for
bug reports. Please keep them coming - I'm sure that together we can manage
a working space-efficient pre-processor sometime.

Regards, Gruessen, Groetjes...

Alistair G. Crooks.
Joypace Ltd., 2 Vale Road, Hawkhurst, Kent TN18 4BU, UK. (+44 580 753114)
UUCP Europe:			        ...!mcvax!unido!nixpbe!nixbln!agc   
UUCP the rest of the world:	 ...!uunet!linus!nixbur!nixpbe!nixbln!agc

P.S. Anyone want to employ a tall Scot who writes pre-processors in his
     spare time, can speak English and German, and can muddle along  in
     Dutch?

*** id.c.old
--- id.c
**************
*** 1,5
  /*
!  *	@(#)id.c	1.1	09/02/89	18:21:55	agc
   *
   *	Copyright Joypace Ltd, UK, 1989. All rights reserved.
   *	This file may be freely distributed provided that this
--- 1,5 -----
  /*
!  *	@(#)id.c	1.2	03/03/89	12:08:35	agc
   *
   *	Copyright Joypace Ltd, UK, 1989. All rights reserved.
   *	This file may be freely distributed provided that this
**************
*** 18,24
   *	MINIX		Minix 1.2
   */
  #ifndef lint
! static char	*idnsccsid = "@(#)id.c	1.1 09/02/89 18:21:55 agc";
  #endif /* not lint */
  
  #include <stdio.h>
--- 18,24 -----
   *	MINIX		Minix 1.2
   */
  #ifndef lint
! static char	*idnsccsid = "@(#)id.c	1.2 03/03/89 12:08:35 agc";
  #endif /* not lint */
  
  #include <stdio.h>
**************
*** 39,45
  } HID;
  
  static HID	ids[HASHTABLEN];
- static int	idnum;
  
  void
  addid(old, new)
--- 39,44 -----
  } HID;
  
  static HID	ids[HASHTABLEN];
  
  void
  addid(old, new)
**************
*** 122,127
  newid()
  {
  	static char	idname[10];
  
  	for (;;) {
  		(void) sprintf(idname, "i%05d", idnum);
--- 121,127 -----
  newid()
  {
  	static char	idname[10];
+ 	static int	idnum;
  
  	for (;;) {
  		(void) sprintf(idname, "i%05d", idnum);
**************
*** 125,130
  
  	for (;;) {
  		(void) sprintf(idname, "i%05d", idnum);
  		if (getclash(idname) == (char *) NULL)
  			return(idname);
  		idnum = (idnum == 99999) ? 0 : idnum + 1;
--- 125,131 -----
  
  	for (;;) {
  		(void) sprintf(idname, "i%05d", idnum);
+ 		idnum = (idnum == 99999) ? 0 : idnum + 1;
  		if (getclash(idname) == (char *) NULL)
  			return(idname);
  	}
**************
*** 127,133
  		(void) sprintf(idname, "i%05d", idnum);
  		if (getclash(idname) == (char *) NULL)
  			return(idname);
- 		idnum = (idnum == 99999) ? 0 : idnum + 1;
  	}
  }
  
--- 128,133 -----
  		idnum = (idnum == 99999) ? 0 : idnum + 1;
  		if (getclash(idname) == (char *) NULL)
  			return(idname);
  	}
  }
  
*** mac.c.old
--- mac.c
**************
*** 1,5
  /*
!  *	@(#)mac.c	1.11	09/02/89	18:22:10	agc
   *
   *	Copyright Joypace Ltd, UK, 1989. All rights reserved.
   *	This file may be freely distributed provided that this
--- 1,5 -----
  /*
!  *	@(#)mac.c	1.12	03/03/89	12:08:45	agc
   *
   *	Copyright Joypace Ltd, UK, 1989. All rights reserved.
   *	This file may be freely distributed provided that this
**************
*** 18,24
   *	MINIX		Minix 1.2
   */
  #ifndef lint
! static char	*macnsccsid = "@(#)mac.c	1.11 09/02/89 18:22:10 agc";
  #endif /* not lint */
  
  #include <stdio.h>
--- 18,24 -----
   *	MINIX		Minix 1.2
   */
  #ifndef lint
! static char	*macnsccsid = "@(#)mac.c	1.12 03/03/89 12:08:45 agc";
  #endif /* not lint */
  
  #include <stdio.h>
**************
*** 226,232
  	}
  	NEW(ARGS, ap);
  	for (;;) {
! 		if (!gettoken(fp, bracket, &t))
  			error(1, "bad macro format", (char *) NULL);
  		switch(t.t_token[0]) {
  		case ',' :
--- 226,232 -----
  	}
  	NEW(ARGS, ap);
  	for (;;) {
! 		if (!gettoken(fp, 0, &t))
  			error(1, "bad macro format", (char *) NULL);
  		switch(t.t_token[0]) {
  		case ',' :
*** parse.c.old
--- parse.c
**************
*** 1,5
  /*
!  *	@(#)parse.c	1.8	07/02/89	15:02:12	agc
   *
   *	Copyright Joypace Ltd., UK, 1989. All rights reserved.
   *	This code may be freely distributed, provided that this
--- 1,5 -----
  /*
!  *	@(#)parse.c	1.9	03/03/89	12:08:40	agc
   *
   *	Copyright Joypace Ltd., UK, 1989. All rights reserved.
   *	This code may be freely distributed, provided that this
**************
*** 17,23
   *	MSC		Microsoft C 5.0
   */
  #ifndef lint
! static char	*parsensccsid = "@(#)parse.c	1.8 07/02/89 15:02:12 agc";
  #endif /* not lint */
  
  #include <stdio.h>
--- 17,23 -----
   *	MSC		Microsoft C 5.0
   */
  #ifndef lint
! static char	*parsensccsid = "@(#)parse.c	1.9 03/03/89 12:08:40 agc";
  #endif /* not lint */
  
  #include <stdio.h>
**************
*** 44,49
  
  #define ISNL(c)	((c) == '\r' || (c) == '\n')
  
  
  /* read a line into buf, folding trigraphs, returning 0 at eof, 1 otherwise */
  int
--- 44,51 -----
  
  #define ISNL(c)	((c) == '\r' || (c) == '\n')
  
+ #define BELL	007
+ 
  
  /* read a line into buf, folding trigraphs, returning 0 at eof, 1 otherwise */
  int
**************
*** 199,205
  				if (*here == '\\') {
  					switch(*(here+1)) {
  					case 'a' :
! 						*cp++ = '';
  						here += 2;
  						i++;
  						continue;
--- 201,207 -----
  				if (*here == '\\') {
  					switch(*(here+1)) {
  					case 'a' :
! 						*cp++ = BELL;
  						here += 2;
  						i++;
  						continue;
**************
*** 230,236
  			case '\\' :
  				switch(*++here) {
  				case 'a' :
! 					num = '';
  					break;
  				case 'n' :
  					num = '\n';
--- 232,238 -----
  			case '\\' :
  				switch(*++here) {
  				case 'a' :
! 					num = BELL;
  					break;
  				case 'n' :
  					num = '\n';
*** proto.c.old
--- proto.c
**************
*** 1,5
  /*
!  *	@(#)proto.c	1.5	07/02/89	16:25:33	agc
   *
   *	Copyright Joypace Ltd, UK, 1989. All rights reserved.
   *	This file may be freely distributed provided that this
--- 1,5 -----
  /*
!  *	@(#)proto.c	1.6	03/03/89	12:08:47	agc
   *
   *	Copyright Joypace Ltd, UK, 1989. All rights reserved.
   *	This file may be freely distributed provided that this
**************
*** 18,24
   *	MINIX		Minix 1.2
   */
  #ifndef lint
! static char	*protonsccsid = "@(#)proto.c	1.5 07/02/89 16:25:33 agc";
  #endif /* lint */
  
  #include <stdio.h>
--- 18,24 -----
   *	MINIX		Minix 1.2
   */
  #ifndef lint
! static char	*protonsccsid = "@(#)proto.c	1.6 03/03/89 12:08:47 agc";
  #endif /* lint */
  
  #include <stdio.h>
**************
*** 38,45
  	mt.t_type = T_SPACE;
  	for (;;) {
  		sgettoken(&s, 1, &mt);
- 		if (mt.t_type == T_EOLN)
- 			return;
  		if (mt.t_type == T_WORD)
  			(void) strcpy(out, mt.t_token);
  	}
--- 38,43 -----
  	mt.t_type = T_SPACE;
  	for (;;) {
  		sgettoken(&s, 1, &mt);
  		if (mt.t_type == T_WORD)
  			(void) strcpy(out, mt.t_token);
  		if (mt.t_token[0] == '.' && strcmp(s, "..") == 0) {
**************
*** 42,47
  			return;
  		if (mt.t_type == T_WORD)
  			(void) strcpy(out, mt.t_token);
  	}
  }
  
--- 40,51 -----
  		sgettoken(&s, 1, &mt);
  		if (mt.t_type == T_WORD)
  			(void) strcpy(out, mt.t_token);
+ 		if (mt.t_token[0] == '.' && strcmp(s, "..") == 0) {
+ 			(void) strcpy(out, "...");
+ 			return;
+ 		}
+ 		if (mt.t_type == T_EOLN)
+ 			return;
  	}
  }
  
**************
*** 55,60
  	ARGS	*ap;
  	char	**cpp;
  	char	*cp;
  	int	i;
  
  	ap = fgetargs(fp, 0);
--- 59,65 -----
  	ARGS	*ap;
  	char	**cpp;
  	char	*cp;
+ 	int	var = -1;
  	int	i;
  
  	ap = fgetargs(fp, 0);
**************
*** 72,77
  			     i < ap->a_argc;
  			     cpp++, i++) {
  				getname(*cpp, tmp);
  				output(tmp, strlen(tmp));
  				if (i < ap->a_argc - 1)
  					output(", ", 2);
--- 77,87 -----
  			     i < ap->a_argc;
  			     cpp++, i++) {
  				getname(*cpp, tmp);
+ 				if (strcmp(&tmp[strlen(tmp) - 3], "...") == 0) {
+ 					output("va_alist", 8);
+ 					var = i;
+ 					break;
+ 				}
  				output(tmp, strlen(tmp));
  				if (i < ap->a_argc - 1)
  					output(", ", 2);
**************
*** 82,87
  			for (i = 0, cpp = ap->a_argv;
  			     i < ap->a_argc;
  			     cpp++, i++) {
  				cp = *cpp;
  				mt.t_type = T_SPACE;
  				for (;;) {
--- 92,101 -----
  			for (i = 0, cpp = ap->a_argv;
  			     i < ap->a_argc;
  			     cpp++, i++) {
+ 				if (i == var) {
+ 					output("char *va_alist;\n", 16);
+ 					break;
+ 				}
  				cp = *cpp;
  				mt.t_type = T_SPACE;
  				for (;;) {