[comp.sources.amiga] v89i099: cc - unix-like front end for lattice 5.x

page%rishathra@Sun.COM (Bob Page) (04/27/89)

Submitted-by: bader+@andrew.cmu.edu (Miles Bader)
Posting-number: Volume 89, Issue 99
Archive-name: languages/cc.1

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	Makefile
#	README
#	builtins.make
#	cc.c
#	cc.doc
#	config.h
#	dstr.c
#	dstr.h
#	err.c
#	list.c
#	list.h
#	op.c
#	op.h
#	options.c
#	options.h
# This is archive 1 of a 1-part kit.
# This archive created: Wed Apr 26 14:31:28 1989
echo "extracting Makefile"
sed 's/^X//' << \SHAR_EOF > Makefile
XDEBUG=	-O
XOPTS=	+no-stack-check
XFLAGS=	$(DEBUG) $(OPTS)
XCFLAGS= $(FLAGS) $(DEFINES)
XLFLAGS= $(FLAGS)
X
XLIBS=
X
XTARGET=	cc
XOBJS=	cc.o list.o dstr.o err.o op.o options.o
X
X$(TARGET):	$(OBJS)
X	${CC} $(LFLAGS) -o $(TARGET) $(OBJS) $(LIBS)
X
X$(OBJS): common.h
Xcc.o:	list.h dstr.h op.h options.h config.h
Xcommon.h: dbug.h
Xoptions.o: options.h
Xdstr.o: dstr.h
Xlist.o: list.h
Xop.o: op.h
SHAR_EOF
echo "extracting README"
sed 's/^X//' << \SHAR_EOF > README
XSimple changes to cc's defaults can be made in config.h.  If you make a not-
Xso-simple change, to implement some new feature, please send me back the
Xchanges.  My email address is bader+@andrew.cmu.edu.
X
XThe Makefile and builtins.make (which goes in s: and defines default rules)
Xare for the version of make that comes with pcc 3.0 (although I just noticed,
Xit's ignoring time-stamps!  Anyone got a better make?)
X
X-Miles
SHAR_EOF
echo "extracting builtins.make"
sed 's/^X//' << \SHAR_EOF > builtins.make
XCC=cc
X
X.SUFFIXES: .c .o
X
X.c.o:
X	${CC} -c ${CFLAGS} $<
SHAR_EOF
echo "extracting cc.c"
sed 's/^X//' << \SHAR_EOF > cc.c
X/*
X * cc -- unix-like compiler driver for amiga lattice c
X *
X * adapted for lattice version 5.0 and extensively modified
X *   by Miles Bader, from the original by Fred Fish (copyright
X *   follows).
X */
X
X/************************************************************************
X *									*
X *			Copyright (c) 1985, Fred Fish			*
X *			    All Rights Reserved				*
X *									*
X *	This software and/or documentation is released into the		*
X *	public domain for personal, non-commercial use only.		*
X *	Limited rights to use, modify, and redistribute are hereby	*
X *	granted for non-commercial purposes, provided that all		*
X *	copyright notices remain intact and all changes are clearly	*
X *	documented.  The author makes no warranty of any kind with	*
X *	respect to this product and explicitly disclaims any implied	*
X *	warranties of merchantability or fitness for any particular	*
X *	purpose.							*
X *									*
X ************************************************************************
X */
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X
X#include <dos.h>
X#include <proto/dos.h>
X#include <ios1.h> /* magic */
X
X#include "common.h"
X#include "list.h"
X#include "dstr.h"
X#include "op.h"
X#include "options.h"
X
X#include "config.h"
X
Xstatic char *locate(char *file,struct list *list);	/* find a file */
Xstatic void cleanObjects(int mustExist);	/* Remove .o for link and go mode */
Xstatic int makeObjs();			/* Reduce to list of object files */
Xstatic int parseCommandLine();		/* Deal with command line */
Xstatic int compile(struct op *op);	/* Translate from .c to .o */
Xstatic int assemble(struct op *op);	/* Translate from .s to .o */
Xstatic int link();			/* Gather .o's into executable */
Xstatic int runCmd(struct dstr *cmd);
X
X#ifdef amiga
X#define CHECK_ABORT chkabort()
X#else
X#define CHECK_ABORT				/* NULL expansion */
X#endif	/* amiga */
X 
XDBUG_GLOBALS
X
X/*
X *	flags set by command line arguments
X */
Xstatic int debugLevel=DEFAULT_DEBUGLEVEL;	/* -g (debugging level) */
X
Xstruct list *libDirs=NULL;
Xstruct list *incDirs=NULL;
Xstruct list *binDirs=NULL;
Xstruct list *defines=NULL;
Xstruct list *undefines=NULL;
Xstruct list *libs=NULL;
X
Xstruct list *pass1PassThrus=NULL;
Xstruct list *pass2PassThrus=NULL;
Xstruct list *optPassThrus=NULL;
Xstruct list *linkPassThrus=NULL;
X
Xstruct list *ops=NULL;
X
Xstatic char *outfile=DEFAULT_EXEC;	/* output file name from linker */
Xstatic char *tempDir=TEMPDIR;		/* where to keep quad files */
Xstatic char *sinkFile=SINKFILE;		/* where to put output from passes */
X
Xstruct dstr *cmdLine=NULL;
X 
Xstatic int abortmsg()
X{
X    if(options_IsSet(OPT_ECHO))
X	fprintf(stderr,"cc: aborting\n");
X    return 1; /* abort */
X}
X
Xstatic int cleanup(status)
Xint status;
X{
X    if(cmdLine!=NULL)	dstr_Free(cmdLine);
X
X    if(libDirs!=NULL)	list_Free(libDirs);
X    if(incDirs!=NULL)	list_Free(incDirs);
X    if(binDirs!=NULL)	list_Free(binDirs);
X    if(defines!=NULL)	list_Free(defines);
X    if(undefines!=NULL)	list_Free(undefines);
X    if(libs!=NULL)	list_Free(libs);
X
X    if(pass1PassThrus!=NULL)	list_Free(pass1PassThrus);
X    if(pass2PassThrus!=NULL)	list_Free(pass2PassThrus);
X    if(optPassThrus!=NULL)	list_Free(optPassThrus);
X    if(linkPassThrus!=NULL)	list_Free(linkPassThrus);
X
X    if(ops!=NULL)	list_Free(ops);
X
X    return status;
X}
X
Xstatic void init()
X{
X    int *opt;
X
X    options_Init();
X    for(opt=defaultOptions; *opt!=0; opt++)
X	options_Set(*opt);
X
X    cmdLine=dstr_Create(30);		/* global command buffer */
X
X    libDirs=list_Create((void **)libDirsInit);
X    incDirs=list_Create((void **)incDirsInit);
X    binDirs=list_Create((void **)binDirsInit);
X    defines=list_Create((void **)definesInit);
X    undefines=list_Create((void **)undefinesInit);
X    libs=list_Create((void **)libsInit);
X
X    pass1PassThrus=list_Create(NULL);
X    pass2PassThrus=list_Create(NULL);
X    optPassThrus=list_Create(NULL);
X    linkPassThrus=list_Create(NULL);
X
X    ops=list_Create(NULL);
X    list_SetFree(ops,op_Free);
X}
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X    int status;
X
X    DBUG_ENTER("main");
X
X    onexit(cleanup);
X    init();
X
X    onbreak(abortmsg);
X
X    if(parseCommandLine(argc,argv)==0)
X	fatal("no files specified");
X
X    cleanObjects(FALSE);	/* get rid of existing object files if any */
X
X    status=makeObjs();
X    if(status==0 && options_IsSet(OPT_LINK)){
X	status=link();
X	if(list_GetLen(ops)==1)
X	    cleanObjects(TRUE);
X    }
X
X    exit(status);
X}
X
X/*
X *	The following macro is used to allow optional whitespace between
X *	an option and it's argument.  Argp is left pointing at the option
X *	and argv and argc are adjusted accordingly if necessary.
X *
X *	Note that there is no check for missing option arguments.  In
X *	particular, -o -V will blindly take -V as the output file name.
X *
X */
X
X#define XARG(argc,argv,argp) {if(*++argp=='\0'){argp=(*argv++);argc--;}}
X
Xstatic int parseCommandLine(argc,argv)
Xint argc;
Xchar **argv;
X{
X    register char *argp;    
X
X    DBUG_ENTER("parseCommandLine");
X
X    argc--;
X    argv++;
X    while(argc-- > 0){
X	CHECK_ABORT;
X
X	argp=*argv++;
X
X	if(*argp=='+')
X	    options_SetByName(argp+1);
X	else if(*argp!='-')    
X	    list_Add(ops,(void *)op_Create(argp));
X	else
X	    switch(*++argp){
X		case 'c':
X		    options_Clear(OPT_LINK);	/* don't link object modules */
X		    break;
X		case 'p':			/* pass thru args to a pass */
X		    switch(*++argp){
X			case '1':		/* pass 1 */
X			    XARG(argc,argv,argp);			
X			    list_Add(pass1PassThrus,argp);
X			    break;
X			case '2':		/* pass 2 */
X			    XARG(argc,argv,argp);			
X			    list_Add(pass2PassThrus,argp);
X			    break;
X			case 'o':		/* optimizer */
X			    XARG(argc,argv,argp);			
X			    list_Add(optPassThrus,argp);
X			    break;
X			case 'l':		/* linking */
X			    XARG(argc,argv,argp);			
X			    list_Add(linkPassThrus,argp);
X			    break;
X			default:
X			    fatal("unknown pass '%c'; must be one of [12ol]",argp[-1]);
X		    }
X		    break;
X		case 'D':
X		    XARG(argc,argv,argp);
X		    list_Add(defines,(void *)argp);
X		    break;
X		case 'E':
X		    warning("-E unimplemented, converted to -P instead");
X		    /* fall through */
X		case 'P':
X		    options_Clear(OPT_COMPILE);
X		    options_Clear(OPT_ASSEMBLE);
X		    options_Clear(OPT_LINK);
X		    break;
X		case 'g':
X		    if(*++argp!='\0') /* optional debuggin level */
X			debugLevel=atoi(argp);
X		    options_Set(OPT_DEBUG);
X		    break;
X		case 'I':
X		    XARG(argc,argv,argp);
X		    list_Add(incDirs,(void *)argp);
X		    break;
X		case 'l':
X		    XARG(argc,argv,argp);
X		    list_Add(libs,(void *)argp);
X		    break;
X		case 'L':
X		    XARG(argc,argv,argp);
X		    list_Add(libDirs,(void *)argp);
X		    break;
X		case 'B':
X		    XARG(argc,argv,argp);
X		    list_Add(binDirs,(void *)argp);
X		    break;
X		case 'O':
X		    options_Set(OPT_OPTIMIZE);
X		    break;
X		case 'o':
X		    XARG(argc,argv,argp);
X		    outfile=argp;
X		    break;
X		case 't':		/* warning, non-standard */
X		    XARG(argc,argv,argp);
X		    tempDir=argp;
X		    break;
X		case 'S':
X		    warning("-S option not yet implemented, ignored");
X		    options_Clear(OPT_ASSEMBLE);
X		    break;
X		case 'U':
X		    XARG(argc,argv,argp);
X		    list_Add(undefines,(void *)argp);
X		    break;
X		default:
X		    fatal("unknown option '%c'",*argp);
X		    break;
X	    }
X    }
X
X    DBUG_RETURN(int,list_GetLen(ops));
X}
X
X/*
X *	For each operand, do compilation or assembly as necessary, to
X *	reduce to an object file in the current directory.
X */
Xstatic int makeObjs()
X{
X    int n;
X    void **els;
X    int numOps=list_GetLen(ops);
X    int status=0;
X
X    DBUG_ENTER("makeObjs");
X
X    for(n=numOps,els=list_GetEls(ops); n>0; n--,els++){
X	struct op *op=(struct op *)*els;
X
X	CHECK_ABORT;
X
X	if(numOps>1 && (op_IsC(op) || op_IsS(op)))
X	    printf("%s.%s:\n",op->rootname,op->suffix);
X
X	if(op_IsC(op))
X	    status=compile(op);
X	else if(op_IsS(op))
X	    status=assemble(op);
X    }
X
X    DBUG_RETURN(int,status);
X}
X
X/* handy little routine */
Xvoid addfList(ds,fmt,list)
Xstruct dstr *ds;
Xchar *fmt;
Xstruct list *list;
X{
X    int n;
X    void **els;
X
X    for(n=list_GetLen(list),els=list_GetEls(list); n>0; n--,els++)
X	dstr_Addf(ds,fmt,(char *)*els);
X}
X
X/*
X *	Note that commands to cc of the form "-l<name>" get interpreted
X *	to mean use a library called "name.lib" from the library
X *	directory.
X *      -lm is specially interpreted to be the appropriate math library.
X */
Xstatic int link()
X{
X    int n;
X    void **els;
X
X    DBUG_ENTER("link");
X
X    dstr_Clear(cmdLine);
X
X    dstr_Addf(cmdLine,"%s ",locate("blink",binDirs));
X
X    if(options_IsSet(OPT_DETACH))
X	dstr_Append(cmdLine,locate("cback.o",libDirs));
X    else if(options_IsSet(OPT_RESIDENT)){
X	if(options_IsSet(OPT_CATCH))
X	    dstr_Append(cmdLine,locate("catchres.o",libDirs));
X	else
X	    dstr_Append(cmdLine,locate("cres.o",libDirs));
X    }else if(options_IsSet(OPT_CATCH))
X	dstr_Append(cmdLine,locate("catch.o",libDirs));
X    else
X	dstr_Append(cmdLine,locate("c.o",libDirs));
X
X    for(n=list_GetLen(ops),els=list_GetEls(ops); n>0; n--,els++){
X	struct op *op=(struct op *)*els;
X	char *name=(op_IsO(op) ? op->rootname : op->basename);
X
X	dstr_Addf(cmdLine,"+%s.o",name);
X    }
X
X    if(options_IsSet(OPT_TINYMAIN))
X	dstr_Addf(cmdLine," define __main=__tinymain ");
X
X    dstr_Addf(cmdLine," library ");
X    for(n=list_GetLen(libs),els=list_GetEls(libs); n>0; n--,els++){
X	char buffer[50];
X	char *lib=(char *)*els;
X
X	if(strcmp(lib,"m")==0){
X	    /* map -lm to appropiate library */
X
X	    strcpy(buffer,"lib:lcm");
X
X	    if(options_IsSet(OPT_FFP))
X	        strcat(buffer,"ffp");
X	    else if(options_IsSet(OPT_IEEE))
X	 	strcat(buffer,"ieee");
X	    else if(options_IsSet(OPT_881))
X		strcat(buffer,"881");
X
X	    /*
X	     * there are only r and s libraries for lcm.lib in the lattice
X	     * distribution; if there is a way to get the lcmieee, lcmffp,
X	     * & lcm881 libraries to work with reg-args & short-ints, I
X	     * couldn't find it.
X	     */
X	    if(options_IsSet(OPT_SHORTINTS))
X	        strcat(buffer,"s");
X	    if(options_IsSet(OPT_REGARGS))
X	        strcat(buffer,"r");
X
X	    strcat(buffer,".lib");
X	}else if(strcmp(lib,"lc")==0){
X	    /* do the standard c library */
X
X	    strcpy(buffer,"lib:lc");
X
X	    if(options_IsSet(OPT_SHORTINTS))
X	        strcat(buffer,"s");
X	    if(options_IsSet(OPT_REGARGS))
X	    	strcat(buffer,"r");
X	    if(options_IsSet(OPT_ABSDATA))
X	        strcat(buffer,"nb");
X
X	    strcat(buffer,".lib");
X
X	    if(options_IsSet(OPT_REGARGS)){
X	        /*
X	         * Now, do it AGAIN, but without registers, to catch any missing refs.
X	         * I don't think this is exactly the right thing to do, but there seem
X	         * to be internal functions missing from the register-fied libraries
X	         */
X
X	        strcat(buffer,"+lib:lc");
X
X	        if(options_IsSet(OPT_SHORTINTS))
X	            strcat(buffer,"s");
X	        if(options_IsSet(OPT_ABSDATA))
X	            strcat(buffer,"nb");
X
X	        strcat(buffer,".lib");
X	    }
X	}else{
X	    sprintf(buffer,"%s.lib",lib);
X	    strcpy(buffer,locate(buffer,libDirs));
X	}	    
X
X        if(n==1)
X	    dstr_Append(cmdLine,buffer);
X	else
X	    dstr_Addf(cmdLine,"%s+",buffer);
X    }
X
X    if(outfile==NULL)
X	/* there better be at least one source file! */
X	outfile=((struct op *)list_GetEls(ops))->basename;
X
X    dstr_Addf(cmdLine," to %s map nil:",outfile);
X
X    addfList(cmdLine," %s",linkPassThrus);
X
X    DBUG_RETURN(int,runCmd(cmdLine));
X}
X
X/*
X *	compile one operand from a C source program to an object module.
X */
Xstatic int compile(op)
Xstruct op *op;
X{
X    int status=0;
X
X    DBUG_ENTER("compile");
X
X    if(options_IsSet(OPT_ASSEMBLE)){
X	status=pass1(op);
X	if(status==0 && options_IsSet(OPT_COMPILE)){
X	    CHECK_ABORT;
X	    if(options_IsSet(OPT_OPTIMIZE))
X		status=optimize(op);
X	    if(status==0)
X	        status=pass2(op);
X	}
X    }
X
X    DBUG_RETURN(int,status);
X}
X
X/*
X *	Note that because of brain-damage in the fact that -p to lc1 removes
X *	all predefined defs, we must add them so replacing -c with -P in the
X *	cc command line will result in the same set of predefined symbols.
X *	This is rather ugly and leaves a hole for future problems if we
X *	get out of sync with respect to what names the compiler predefines.
X */
Xstatic int pass1(op)
Xregister struct op *op;
X{
X    char tmpFile[MAXPATH];
X    int status;
X    int n;
X    void **els;
X
X    DBUG_ENTER("pass1");
X
X    dstr_Clear(cmdLine);
X
X    dstr_Append(cmdLine,locate((options_IsSet(OPT_BIGLC1) ? "lc1b" : "lc1"),binDirs));
X
X    if(options_IsSet(OPT_DEBUG)){
X	dstr_Addf(cmdLine," -d%d",debugLevel);
X	if(options_IsSet(OPT_OPTIMIZE)){
X	    warning("-g incompatible with -O, -O turned off");
X	    options_Clear(OPT_OPTIMIZE);
X	}
X    }
X
X    if(options_IsSet(OPT_FFP))
X	dstr_Addf(cmdLine," -ff");
X    else if(options_IsSet(OPT_881))
X	dstr_Addf(cmdLine," -f8");
X    else if(options_IsSet(OPT_IEEE))
X	dstr_Addf(cmdLine," -fi");
X    else
X	dstr_Addf(cmdLine," -fl");
X
X    if(options_IsSet(OPT_SHORTINTS))
X	dstr_Addf(cmdLine," -w");
X    if(options_IsSet(OPT_LONGALIGN))
X	dstr_Addf(cmdLine," -l");
X
X    if(options_IsSet(OPT_020))
X	dstr_Addf(cmdLine," -m2");
X    else if(options_IsSet(OPT_030))
X	dstr_Addf(cmdLine," -m3");
X
X    if(options_IsSet(OPT_CATCH) && !options_IsSet(OPT_ABSDATA)){
X	warning("+catch implies +abs-data");
X	options_Set(OPT_ABSDATA);
X    }
X
X    dstr_Addf(cmdLine," -b%d",options_IsSet(OPT_ABSDATA) ? 0 : 1);
X    dstr_Addf(cmdLine," -r%d",options_IsSet(OPT_ABSCODE) ? 0 : 1);
X
X    if(options_IsSet(OPT_REGARGS))
X	dstr_Addf(cmdLine,"r"); /* part of -r switch */
X
X    {
X	char buf[15], *p=buf;
X
X	if(options_IsSet(OPT_ANSI))		*p++='a';
X	if(options_IsSet(OPT_CPP))		*p++='+';
X	if(options_IsSet(OPT_TRAD))		*p++='l', *p++='o';
X	if(options_IsSet(OPT_REGARGS))		*p++='r';
X	if(options_IsSet(OPT_PURESTRINGS))	*p++='s';
X	
X	if(p>buf){
X	    *p='\0';
X	    dstr_Addf(cmdLine," -c%s",buf);
X	}
X    }
X
X    if(options_IsSet(OPT_COMPILE)){
X	strcpy(tmpFile,tempDir);
X	strcat(tmpFile,op->basename);
X	strcat(tmpFile,".q");
X	dstr_Addf(cmdLine," -o%s",tmpFile);
X    }else{
X	strcpy(tmpFile,op->basename);
X	strcat(tmpFile,".pp");
X
X	dstr_Addf(cmdLine," -o%s -p",tmpFile);
X    }
X
X    for(n=list_GetLen(undefines),els=list_GetEls(undefines); n>0; n--,els++){
X	/*************************
X	dstr_Addf(cmdLine," -u%s",(char *)*els);
X	**************************/
X	warning("-U%s ignored! (unimplemented)",(char *)*els);
X    }
X
X    addfList(cmdLine," -d%s",defines);
X    addfList(cmdLine," %s",pass1PassThrus);
X
X    for(n=list_GetLen(incDirs),els=list_GetEls(incDirs); n>0; n--,els++){
X	char *id=(*els);
X	int len=strlen(id);
X
X	dstr_Addf(cmdLine," -i%s",*els);
X
X	if(len>0 && id[len-1]!=':' && id[len-1]!='/')
X	    dstr_Addf(cmdLine,"/");
X    }
X
X    dstr_Addf(cmdLine," %s",op->rootname);
X
X    status=runCmd(cmdLine);
X    if(status==0 && options_IsSet(OPT_EXEC) && !readable(tmpFile))
X	status=1;
X
X    DBUG_RETURN(int,status);
X}
X
X/* run the optimizer */
Xstatic int optimize(op)
Xstruct op *op;
X{
X    DBUG_ENTER("optimize");
X
X    dstr_Clear(cmdLine);
X    dstr_Addf(cmdLine,"%s %s%s",locate("go",binDirs),tempDir,op->basename);
X
X    addfList(cmdLine," %s",optPassThrus);
X
X    DBUG_RETURN(int,runCmd(cmdLine));
X}
X
X/*
X *	Run second pass of compiler on a single operand.
X */
Xstatic int pass2(op)
Xstruct op *op;
X{
X    char objFile[MAXPATH];
X    int status;
X
X#ifdef DBUG
X    fprintf(stderr,"Entering pass2...\n");
X#endif
X
X    DBUG_ENTER("pass2");
X
X    dstr_Clear(cmdLine);
X
X    dstr_Append(cmdLine,locate("lc2",binDirs));
X
X    if(!options_IsSet(OPT_STACKCHECK))
X	dstr_Addf(cmdLine," -v");
X
X    strcpy(objFile,op->basename);
X    strcat(objFile,".o");
X
X    dstr_Addf(cmdLine," -o%s",objFile);
X
X    dstr_Addf(cmdLine," %s%s",tempDir,op->basename);
X
X    addfList(cmdLine," %s",pass2PassThrus);
X
X    status=runCmd(cmdLine);
X    if(status==0 && options_IsSet(OPT_EXEC) && !readable(objFile))
X	status=1;
X
X    DBUG_RETURN(int,status);
X}
X
X/*
X *	I have not yet had occasion to use the macro assembler,so this
X *	part is not yet implemented.  If anyone wants to send me the
X *	appropriate code, I will be glad to install it.
X */
Xstatic int assemble(op)
Xstruct op *op;
X{
X    DBUG_ENTER("assemble");
X    warning("assembly pass not yet implemented");
X    DBUG_RETURN(int,1);
X}
X
Xstatic void filteredOutputFrom(source,filter)
XFILE *source;
Xchar **filter;
X{
X    char buf[200];
X
X    DBUG_ENTER("FilteredOutputFrom");
X
X    while(!feof(source)){
X	char **ignore;
X
X	fgets(buf,sizeof(buf),source);
X
X	for(ignore=filter; *ignore!=NULL; ignore++)
X	    if(strncmp(*ignore,buf,strlen(*ignore))==0)
X	        break;
X
X	if(*ignore==NULL)
X	    fputs(buf,stdout);
X    }
X
X    DBUG_VOID_RETURN;
X}
X
X#ifdef AMIGA
X
Xstatic int execToFile(cmd,sink)
Xchar *cmd;
XFILE *sink;
X{
X    /* this is a dopey version that uses Execute, since I can't get fork to work */
X    long fh;
X
X    DBUG_ENTER("execToFile");
X
X    if(sink==NULL)
X	fh=0;
X    else
X	fh=chkufb(fileno(sink))->ufbfh;
X
X    DBUG_RETURN(int,Execute(cmd,0L,fh)!=(-1));
X
X#if 0
X    char *argv[50],**argp=argv;
X    struct ProcID child;
X    static struct FORKENV env={0,0,0,0,0,NULL};
X    int i;
X
X    DBUG_ENTER("execToFile");
X
X    if(cmd==NULL)
X    	DBUG_RETURN(int,1);
X
X    /* this is sort of stupid, cause forkv will just put them back together,
X     * but oh well...
X     */
X    *argp=strtok(cmd," \t");
X    while(*argp!=NULL)
X    	*++argp=strtok(NULL," \t");
X
X    if(sink==NULL)
X        env.std_out=0;
X    else{
X    	struct UFB *ufb=chkufb(fileno(sink));
X	int i;
X
X	printf("argv[%d]:",argp-argv);
X	for(argp=argv;*argp!=NULL;argp++)
X	    printf(" %s",*argp);
X	putchar('\n');
X
X	printf("env: %d, %d, %d, %d, %d, %d\n",
X		env.priority, env.stack, env.std_in, env.std_out,
X		env.console, env.msgport);
X
X	printf("ufb==0x%x, fh==0x%x, go? ",ufb,ufb->ufbfh);
X
X	fflush(stdout);
X
X	env.std_out=ufb->ufbfh; /* magic to get amigados handle from FILE */
X    }
X
X    if((i=forkv(argv[0],argv,&env,&child))==-1){
X        poserr("forkv");
X    	DBUG_RETURN(int,1);
X    }
X
X    printf("Fork returns: %d\n",i);
X
X    DBUG_RETURN(int,wait(&child));
X#endif
X}
X
X#endif
X 
Xstatic int runCmd(cmd)
Xstruct dstr *cmd;
X{
X    int status;
X    char *buf=dstr_GetBuf(cmd);
X    
X    DBUG_ENTER("RunCommand");
X
X    DBUG_3("cmd","execute '%s'",buf);
X    if(options_IsSet(OPT_ECHO)){
X	puts(buf);
X	fflush(stdout);
X    }
X
X    CHECK_ABORT;
X
X    if(options_IsSet(OPT_EXEC)){
X	FILE *sink;
X
X	if(sinkFile!=NULL && options_IsSet(OPT_FILTER)){
X	    sink=fopen(sinkFile,"w+");
X	    if(sink==NULL)
X		perror(sinkFile);
X	}else
X	    sink=NULL;
X
X	status=execToFile(buf,sink);
X	DBUG_3("sys","subcommand returns status %d",status);
X
X	if(sink!=NULL){
X	    rewind(sink);
X	    filteredOutputFrom(sink,filteredPrefixes);
X	    fclose(sink);
X	    unlink(sinkFile);
X	}
X
X	DBUG_RETURN(int,status);
X    }else
X	DBUG_RETURN(int,0);
X}
X
X/*
X *	Look through the list of paths pointed to by "vec" until we find
X *	a file with name given pointed to by "namep".  If none is found,
X *	the name pointed to by namep is returned.
X */
Xstatic char *locate(name,paths)
Xchar *name;
Xstruct list *paths;
X{
X    static char namebuf[MAXPATH];
X    void **els;
X    int n;
X    
X    DBUG_ENTER("locate");
X
X    if(strchr(name,':')!=NULL || *name=='/')
X	return name;	/* absolute */
X	
X    for(n=list_GetLen(paths),els=list_GetEls(paths); n>0; n--,els++){
X	int len=strlen((char *)*els);
X
X	strcpy(namebuf,(char *)*els);
X	if(len>0 && namebuf[len-1]!=':' && namebuf[len-1]!='/')
X	    strcat(namebuf,"/");
X	strcat(namebuf,name);
X
X	DBUG_3("try","look for '%s'",namebuf);
X	if(readable(namebuf)){
X	    name=namebuf;
X	    break;
X	}
X    }
X
X    DBUG_RETURN(char *,name);
X}
X
X/*
X *	Check to see if the file exists and is readable.
X */
Xstatic int readable(name)
Xchar *name;
X{
X    register int status=0;
X    register long fildes;
X    
X    DBUG_ENTER("readable");
X
X#ifdef unix
X    fildes=open(name,O_RDONLY);
X    if(fildes >= 0){
X	(void) close(fildes);
X	status=1;
X    }
X#else
X    fildes=Lock(name,ACCESS_READ);
X    if(fildes != 0){
X    	UnLock(fildes);
X	status=1;
X    }
X#endif
X
X    DBUG_RETURN(int,status);
X}
X
X/*
X *	If an executable is made from a single C file, the normal behavior
X *	for the unix environment is to treat the .o file as an intermediate
X *	file and remove it, so we follow suit.
X */
Xstatic void cleanObjects(mustExist)
Xint mustExist;
X{
X    int n;
X    void **els;
X
X    DBUG_ENTER("cleanObjects");
X	
X    for(n=list_GetLen(ops),els=list_GetEls(ops); n>0; n--,els++){
X	char buf[MAXPATH];
X        struct op *op=(struct op *)*els;
X
X	if(!op_IsO(op)){
X	    strcpy(buf,op->basename);
X	    strcat(buf,".o");
X	    if(unlink(buf)!=0 && mustExist)
X	        warning("can't delete '%s'",buf);
X        }
X    }
X
X    DBUG_VOID_RETURN;
X}
SHAR_EOF
echo "extracting cc.doc"
sed 's/^X//' << \SHAR_EOF > cc.doc
X	CC: a unix-like compiler driver for amiga lattice-c (that also
X	    filters out stupid messages!)
X
X    USAGE:
X	cc [args] file...
X
X      Arguments are ([x] means x is optional):
X
X	file		A file to compile or link.  Currently, only .c and .o
X			are understood, although supporting .s files would
X			probably be pretty simple.
X
X	-o execfile	Write the resulting executable to EXECFILE (only
X			meaningful when linking).
X
X	-c		Don't link the object file, just leave it there.
X
X	-g[num]		Compile in debugging info, using debug-level NUM.
X	-O		Use the global optimizer (incompatible with -g).
X	-P		Just pre-process the file, creating a .pp file.
X
X	-l libname	Add LIBNAME.lib to the list of libraries.
X
X	-I dir		Add the directory DIR to the path searched for include
X			files.
X	-D define	Add DEFINE a pre-processor define; it can be just a name
X			or name=value.
X	-U undefin	Undefine the symbol UNDEFINE (this really doesn't work).
X	-L libdir	Add the directory LIBDIR to the path searched for
X			libraries.
X	-B bindir	Add the directory BINDIR to the path searched for
X			binaries.
X
X	-px string	Put STRING on the command line of compiler pass X, where
X			X is one of: 1-- pass1; 2-- pass2; o-- optimizer;
X			and l-- linker.  This switch can be used to get at
X			compiler features that cc doesn't directly support,
X			although it'd be better to just add the feature to cc
X			(it shouldn't be too hard)-- and send the change
X			back to me (bader+@andrew.cmu.edu)!
X
X	-t tempdir	Use TEMPDIR as the place to put temporary files.
X
X	+ansi			Enforce ansi fascism.
X	+cpp			Compat with c++.
X	+trad			Use traditional style cpp.
X
X	+[no-]abs-code		Use long (absolute) addressing for function
X				calls.
X	+[no-]abs-data		Use long (absolute) addressing for data.
X
X	+[no-]reload-a4		Reload reg a4 in each function.
X	+[no-]short-ints	Use short integers.
X	+[no-]reg-args		Use register argument passing.
X	+[no-]long-align	Align everything to long boundaries.
X	+[no-]stack-check	Put stack-checking into the func prolog.
X	+[no-]pure-strings	Put strings in the text segment.
X
X	+ffp			Use motorola fast floating point.
X	+881			Compile for a 68881.
X	+ieee			Ieee floating point.
X
X	+68k			Compile for a 68000 and up.
X	+020			Compile for a 68020 and up.
X	+030			Compile for a 68030.
X
X	+[no-]detach		Make a program that runs in the background.
X	+[no-]tiny-main		Use tinymain (this doesn't work).
X	+[no-]resident		Try and make resident-able.
X	+[no-]catch		Compile in code to try and catch exceptions.
X
X	+[no-]optimize		Optimize the obj module.
X	+[no-]link		Link the object modules.
X	+[no-]compile		(Otherwise, just pre-process).
X	+[no-]assemble		Emit object-modules (else assembly).
X	+[no-]debug		Produce debugging info.
X
X	+[no-]echo		Echo what we execute.
X	+[no-]filter		Filter out yucky message from passes.
X	+[no-]exec		Actually run each pass.
X
X	+[no-]big-lc1		Run lc1b instead of lc1.
X
X    DEFAULTS:
X        The default options are: +compile +link +stack-check +exec +filter
X
X	The default output file is "a.out".
X
X	The default temp directory is "t:".
X
X	The default debug level when just -g (or +debug) is specified is 3.
X
X	The default libraries are: "-lc", "-lamiga".
X
X    NOTES:
X	The library -lm is replaced by whichever math library is appropiate
X	given other switches (like +ieee or +ffp), and -lc is replaced by
X	the appropiate c library-- so be and sure to pass the same set of
X	switches to cc when linking as you do when compiling (with -c) the
X	object files!
X
X	This version of cc is intended for use with lattice c version 5.
X
X    BUGS:
X	I haven't nearly tested all the possible combinations of options.
X
X	The libraries supplied by lattice aren't complete, so some combos
X	of switches may not be possible (e.g., +reg-args and +ieee-- lattice
X	doesn't supply a libieeer.lib, and so linking fails in this case).
X
X	-U doesn't work.
X
X	-S doesn't work (and isn't ever likely too unless lattice makes
X	omd a much better program).
X
X	Compiling .s (assembly) files isn't implemented, even though it's
X	probably pretty simple, using asm.  I just never needed it...
X
X    AUTHOR:
X	Miles Bader (bader+@andrew.cmu.edu)
X	   from an earlier program by Fred Fish.
SHAR_EOF
echo "extracting config.h"
sed 's/^X//' << \SHAR_EOF > config.h
X/*
X * configuration file for cc; easily re-configurable stuff goes here.
X * March 1989, Miles Bader
X */
X
X/*
X * this file contains declarations, so it can only be included in one source file
X */
X
X#define MAXPATH 200		/* max length of a path */
X
X/* What to call executable if not specified.  If NULL, named after 1st source file */
X#define DEFAULT_EXEC "a.out"
X 
X/* must be a prefix; i.e., needs a slash or a colon on the end */
X#define TEMPDIR	"T:"		/* Keep intermediate files in temp directory */
X/* #define TEMPDIR "" */	/* Keep intermediate files in current dir */
X
X/* The file for filtering compiler pass output.  If NULL, no filtering is done */
X#define SINKFILE "T:__cc_sink"
X
X#define DEFAULT_DEBUGLEVEL 3	/* default debug level if just -g is given */
X
X/* Listf of default options.  Note that not having _EXEC, _COMPILE, _ASSEMBLE,
X * and _LINK set by default would be very wierd
X */
Xint defaultOptions[]={
X    OPT_COMPILE,	/* compile things! */
X    OPT_ASSEMBLE,	/* make object files! */
X    OPT_EXEC,		/* execute passes! */
X    OPT_LINK,		/* link into executable! */
X    OPT_FILTER,		/* filter out obnoxious messages */
X    OPT_STACKCHECK,	/* enable stack checking */
X    0
X};
X
X/* initial contents of some lists; &insertMark is where additional elements go */
Xchar *libDirsInit[]={"",&insertMark,"lib:",NULL};
Xchar *incDirsInit[]={&insertMark,"include:",NULL};
Xchar **binDirsInit=NULL;
Xchar **definesInit=NULL;
Xchar **undefinesInit=NULL;
Xchar *libsInit[]={&insertMark,"lc","amiga",NULL};
X
X/* prefixes that are filtered out of the compiler output stream */
Xchar *filteredPrefixes[]={
X    "\n",			/* blank lines */
X    "Copyright",		/* copyright noticed */
X    "Lattice",			/* lattice advertisements */
X
X    /* lc2 */
X    "Module size",
X
X    /* blink */
X    "Blink - Version",
X    "Enter a DEFINE value", 	/* input is impossible anyway... */
X    "BLINK Complete",
X    "Final output file size",
X    NULL
X};
SHAR_EOF
echo "extracting dstr.c"
sed 's/^X//' << \SHAR_EOF > dstr.c
X/*
X * dynamic strings
X * March 1989, Miles Bader
X */
X
X#include "common.h"
X#include "dstr.h"
X
Xstruct dstr *dstr_Create(initsize)
Xint initsize;
X{
X    struct dstr *n=NEW(struct dstr);
X    
X    DBUG_ENTER("dstr_Create");
X
X    if(n==NULL)
X	fatal("couldn't allocate a dstr");
X
X    n->buf=malloc(initsize+1);
X
X    if(n->buf==NULL)
X	fatal("couldn't allocate dstr of size %d",initsize);
X
X    n->max=initsize;
X    n->len=0;
X    *n->buf='\0';
X
X    DBUG_RETURN(struct dstr *,n);
X}
X
Xvoid dstr_Free(ds)
Xstruct dstr *ds;
X{
X    DBUG_ENTER("dstr_Free");
X
X    if(ds->buf!=NULL)
X	FREE(ds->buf);
X    FREE(ds);
X
X    DBUG_VOID_RETURN;
X}
X
Xvoid dstr_Clear(ds)
Xstruct dstr *ds;
X{
X   ds->len=0;
X   *ds->buf='\0';
X}
X
Xvoid dstr_Append(ds,str)
Xstruct dstr *ds;
Xchar *str;
X{
X    int len=strlen(str);
X    
X    DBUG_ENTER("dstr_Append");
X
X    if(len+ds->len>ds->max){
X	ds->max+=len+len;
X	ds->buf=(char *)realloc((void *)ds->buf,ds->max);
X
X	if(ds->buf==NULL)
X	    fatal("couldn't extend a dstr to %d chars",ds->max);
X    }
X
X    strcpy(ds->buf+ds->len,str);
X    ds->len+=len;
X
X    DBUG_VOID_RETURN;
X}
X
Xvoid dstr_Set(ds,str)
Xstruct dstr *ds;
Xchar *str;
X{
X    DBUG_ENTER("dstr_Set");
X
X    ds->len=0;
X    dstr_Append(ds,str);
X
X    DBUG_VOID_RETURN;
X}
X
Xvoid dstr_Addf(ds,fmt,a1,a2,a3,a4,a5,a6,a7)
Xstruct dstr *ds;
Xchar *fmt;
Xchar *a1,*a2,*a3,*a4,*a5,*a6,*a7;
X{
X    char buf[500];
X
X    DBUG_ENTER("dstr_Addf");
X
X    sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7);
X
X    DBUG_2("buf",buf);
X
X    dstr_Append(ds,buf);
X
X    DBUG_VOID_RETURN;
X}
SHAR_EOF
echo "extracting dstr.h"
sed 's/^X//' << \SHAR_EOF > dstr.h
X/*
X * dynamic strings
X * March 1989, Miles Bader
X */
X
Xstruct dstr {
X    int max,len;
X    char *buf;
X};
X
Xstruct dstr *dstr_Create();
Xvoid dstr_Free();
Xvoid dstr_Clear();
Xvoid dstr_Set();
Xvoid dstr_Append();
Xvoid dstr_Addf();
X
X#define dstr_GetBuf(d) ((d)->buf)
X#define dstr_GetLen(d) ((d)->len)
SHAR_EOF
echo "extracting err.c"
sed 's/^X//' << \SHAR_EOF > err.c
X/*
X * these are in a separate file so the compiler doesn't bitch about mismatched
X * arguments
X */
X
X#include <stdio.h>
X
X#include "common.h"
X
X/*VARARGS1*/
Xvoid warning(fmt,a1,a2,a3,a4,a5,a6,a7)
Xchar *fmt;
Xchar *a1,*a2,*a3,*a4,*a5,*a6,*a7;
X{
X    fputs("cc: warning: ",stderr);
X    fprintf(stderr,fmt,a1,a2,a3,a4,a5,a6,a7);
X    putc('\n',stderr);
X    (void) fflush(stderr);
X}
X
X/*VARAS1*/
Xvoid fatal(fmt,a1,a2,a3,a4,a5,a6,a7)
Xchar *fmt;
Xchar *a1,*a2,*a3,*a4,*a5,*a6,*a7;
X{
X    fputs("cc: error: ",stderr);
X    fprintf(stderr,fmt,a1,a2,a3,a4,a5,a6,a7);
X    putc('\n',stderr);
X    (void) fflush(stderr);
X    exit(1);
X}
SHAR_EOF
echo "extracting list.c"
sed 's/^X//' << \SHAR_EOF > list.c
X/*
X * expandable lists
X * March 1989, Miles Bader
X */
X
X#include "common.h"
X#include "list.h"
X
X#define BUMPSIZE 5			/* grow list this much at a time */
X
Xchar insertMark;			/* dummy used for its address */
X
Xstruct list *list_Create(init)
Xvoid **init;
X{
X    void **p,**q;
X    struct list *l=NEW(struct list);
X    
X    DBUG_ENTER("list_Create");
X
X    if(l==NULL)
X	fatal("couldn't allocate a list");
X
X    l->num=0;
X
X    l->insertionPoint=(-1);
X
X    for(p=init; p!=NULL && *p!=NULL; p++)
X	if(*p==&insertMark)
X	    l->insertionPoint=l->num;
X	else
X	    l->num++;
X
X    l->els=(void **)malloc(l->num*sizeof(void *));
X
X    if(l->els==NULL && l->num>0 /* ANSI compat */)
X	fatal("couldn't allocate initial list elements");
X
X    for(p=init,q=l->els; p!=NULL && *p!=NULL; p++)
X	if(*p!=&insertMark)
X	    *q++=(*p);
X
X    l->max=l->num;
X    if(l->insertionPoint<0)
X	l->insertionPoint=l->num; 	/* default is at end */
X
X    l->freeProc=NULL;
X
X    DBUG_RETURN(struct list *,l);
X}
X
Xvoid list_Free(l)
Xstruct list *l;
X{
X    DBUG_ENTER("list_Free");
X
X    if(l->freeProc!=NULL){
X    	void **els;
X	int n;
X	
X	DBUG_4("free","using freeProc on %d els: 0x%x",l->num,l->freeProc);
X
X	for(n=l->num,els=l->els; n>0; n--,els++){
X	    DBUG_3("free","freeProc(0x%x)",*els);
X	    (*l->freeProc)(*els);
X	}
X    }
X
X    if(l->els!=NULL){
X        DBUG_3("free","freeing els: 0x%x",l->els);
X	FREE(l->els);
X    }
X
X    DBUG_3("free","freeing list: 0x%x",l);
X
X    FREE(l);
X
X    DBUG_VOID_RETURN;
X}
X
Xvoid list_Add(l,e)
Xstruct list *l;
Xvoid *e;
X{
X    int i;
X    
X    DBUG_ENTER("list_Add");
X
X    if(l->num>=l->max){
X        l->max+=BUMPSIZE;
X	l->els=(void **)realloc((void *)l->els,l->max*sizeof(void *));
X
X	if(l->els==NULL)
X	    fatal("couldn't extend a list to %d elements",l->max);
X    }
X
X    for(i=l->num; i>l->insertionPoint; i--)
X	l->els[i]=l->els[i-1];
X
X    l->els[l->insertionPoint++]=e;
X
X    l->num++;
X
X    DBUG_VOID_RETURN;
X}
SHAR_EOF
echo "extracting list.h"
sed 's/^X//' << \SHAR_EOF > list.h
X/*
X * expandable lists
X * March 1989, Miles Bader
X */
X
Xextern char insertMark;
X
Xstruct list {
X    int num,max;
X    int insertionPoint;			/* where a new element gets added */
X    void **els;
X    void (*freeProc)();			/* if non-NULL, used to free elements */
X};
X
Xstruct list *list_Create(void **initEls);
Xvoid list_Free(struct list *l);
Xvoid list_Add(struct list *l,void *el);
X
X#define list_GetEls(l) ((l)->els)
X#define list_GetLen(l) ((l)->num)
X
X#define list_SetFree(l,fp) ((l)->freeProc=fp)
SHAR_EOF
echo "extracting op.c"
sed 's/^X//' << \SHAR_EOF > op.c
X/*
X * file operands
X * March 1989, Miles Bader (orig from cc.c by fred fish)
X */
X
X#include "common.h"
X#include "op.h"
X
X/*
X *	Split an operand name into rootname, basename, and suffix
X *	components.  The rootname is the full name, minus any suffix,
X *	but including any prefix.  The basename is the rootname minus
X *	any prefix.  The suffix is anything after the last '.' character.
X *	Only the suffix is allowed to be the null string.
X */
Xstruct op *op_Create(filename)
Xchar *filename;
X{
X    char *split;
X    extern char *strrchr();
X    struct op *op=NEW(struct op);
X
X    DBUG_ENTER("op_Create");
X
X    DBUG_3("ops", "create op '%s'",filename);
X
X    if(op==NULL)
X	fatal("couldn't allocate an op");
X
X    op->rootname=filename;
X
X    split=strrchr(filename,'/');
X    if(split==NULL)
X	split=strrchr(filename,':');
X
X    if(split==NULL)
X	op->basename=filename;
X    else
X	op->basename=++split;
X
X    split=strrchr(filename,'.');
X    if(split==NULL)
X	op->suffix="";
X    else{
X	*split++='\0';
X	op->suffix=split;
X    }
X
X    DBUG_3("ops","rootname '%s'",op->rootname);
X    DBUG_3("ops","basename '%s'",op->basename);
X    DBUG_3("ops","suffix '%s'",op->suffix);
X
X    DBUG_RETURN(struct op *,op);
X}
X
Xvoid op_Free(op)
Xstruct op *op;
X{
X    FREE(op);
X}
SHAR_EOF
echo "extracting op.h"
sed 's/^X//' << \SHAR_EOF > op.h
X/*
X * file operands
X * March 1989, Miles Bader (orig from cc.c by fred fish)
X */
X
X/*
X *	Command line arguments that represent files to be compiled, assembled,
X *	or linked, are kept track of as "ops".  If, for example,
X *	the file name is "df0:mydir/junk.c", then the rootname is
X *	"df0:mydir/junk", the basename is "junk", and the suffix is "c".
X *	String suffixes are used, rather than single character suffixes, to
X *	allow use of names with multicharacter suffixes.
X */
X
Xstruct op{		/* Info about each operand (non option) */
X    char *rootname;		/* Name minus any suffix */
X    char *basename;		/* Name minus any prefix or suffix */
X    char *suffix;		/* suffix of operand */
X};
X
X/*
X *	macros to determine the suffix type of a file given a pointer to
X *	its operand structure.
X */
X#define op_IsC(op) (strcmp(op->suffix,"c")==0)
X#define op_IsS(op) (strcmp(op->suffix,"s")==0)
X#define op_IsO(op) (strcmp(op->suffix,"o")==0)
X
Xstruct op *op_Create(char *name);
Xvoid op_Free(struct op *op);
SHAR_EOF
echo "extracting options.c"
sed 's/^X//' << \SHAR_EOF > options.c
X/*
X * compiler options processing
X * March 1989, Miles Bader
X */
X
X#include "common.h"
X#include "options.h"
X
Xlong globalOpts[MAXOPTS/BITSPERLONG];
X
Xstruct option {
X    char *name;
X    int opt;
X    int *set;
X};
X
X/* pre-processor compatibility modes */
Xint ppOptSet[]={OPT_TRAD, OPT_ANSI, OPT_CPP, 0};
X
X/* cpu-types */
Xint cpuOptSet[]={OPT_68K, OPT_020, OPT_030, 0};
X
X/* types of floating point support */
Xint floatOptSet[]={OPT_FFP, OPT_IEEE, OPT_881, 0};
X
Xstruct option optionlist[]={
X/*   name		mask		excludes	*/
X
X    /* parsing */
X    {"ansi",		OPT_ANSI,	ppOptSet},
X    {"c++",		OPT_CPP,	ppOptSet},
X    {"traditional",	OPT_TRAD,	ppOptSet},
X
X    /* code gen */
X    {"abs-code",	OPT_ABSCODE},
X    {"abs-data",	OPT_ABSDATA},
X
X    {"reg-args",	OPT_REGARGS},
X    {"reload-a4",	OPT_RELOADA4},
X    {"short-ints",	OPT_SHORTINTS},
X    {"long-align",	OPT_LONGALIGN},
X    {"stack-check",	OPT_STACKCHECK},
X
X    {"pure-strings",	OPT_PURESTRINGS},
X
X    {"68k",		OPT_68K,	cpuOptSet},
X    {"020",		OPT_020,	cpuOptSet},
X    {"030",		OPT_030,	cpuOptSet},
X
X    {"881",		OPT_881,	floatOptSet},
X    {"ffp",		OPT_FFP,	floatOptSet},
X    {"ieee",		OPT_IEEE,	floatOptSet},
X
X    /* linking */
X    {"detach",		OPT_DETACH},
X    {"resident",	OPT_RESIDENT},
X    {"tiny-main",	OPT_TINYMAIN},
X    {"catch",		OPT_CATCH},
X
X    {"optimize",	OPT_OPTIMIZE},
X    {"link",		OPT_LINK},
X    {"compile",		OPT_COMPILE},
X    {"assemble",	OPT_ASSEMBLE},
X    {"debug",		OPT_DEBUG},
X
X    {"echo",		OPT_ECHO},
X    {"filter",		OPT_FILTER},
X    {"exec",		OPT_EXEC},
X
X    {"big-lc1",		OPT_BIGLC1},
X
X    NULL
X};
X
Xvoid options_SetByName(optname)
Xchar *optname;
X{
X    struct option *opt;
X    int not=FALSE;
X
X    if(strncmp(optname,"no-",3)==0){
X	optname+=3;
X	not=TRUE;
X    }
X
X    for(opt=optionlist; opt->name!=NULL; opt++)
X	if(strcmp(optname,opt->name)==0){
X	    if(not){
X		if(opt->set!=NULL)
X		    fatal("%s is not a boolean option",opt);
X		else
X		    options_Clear(opt->opt);
X	    }else{
X		if(opt->set!=NULL){
X		    int *clear;
X		    for(clear=opt->set; *clear!=0; clear++)
X		    	options_Clear(*clear);
X		}
X		
X		options_Set(opt->opt);
X	    }
X
X	    break;
X	}
X
X    if(opt->name==NULL)
X	fatal("unknown option: %s",optname);
X}
X
Xvoid options_Init()
X{
X    int i;
X    for(i=0; i<(MAXOPTS/BITSPERLONG); i++)
X	globalOpts[i]=0;
X}
SHAR_EOF
echo "extracting options.h"
sed 's/^X//' << \SHAR_EOF > options.h
X/*
X * compiler options
X * March 1989, Miles Bader
X */
X
X/* increase this for more options */
X#define MAXOPTS	64
X
X#ifndef BITSPERLONG
X#define BITSPERLONG 32
X#endif
X
Xextern long globalOpts[MAXOPTS/BITSPERLONG];
X
X#define options_IsSet(opt) \
X (globalOpts[(opt)/BITSPERLONG]&(1L<<((opt)%BITSPERLONG)))
X#define options_Set(opt) \
X (globalOpts[(opt)/BITSPERLONG]|=(1L<<((opt)%BITSPERLONG)))
X#define options_Clear(opt) \
X (globalOpts[(opt)/BITSPERLONG]&=~(1L<<(long)((opt)%BITSPERLONG)))
X
Xvoid options_SetByName(char *optname);
Xvoid options_Init();
X
X
X#define OPT_NONE	0
X
X#define OPT_ANSI	1	/* enforce ansi fascism */
X#define OPT_CPP		2	/* compat with c++ */
X#define OPT_TRAD	3	/* use traditional style cpp */
X
X#define OPT_ABSCODE	4	/* use long (absolute) addressing for function calls */
X#define OPT_ABSDATA	5	/* use long (absolute) addressing for data */
X
X#define OPT_RELOADA4	6	/* reload reg a4 in each function */
X#define OPT_SHORTINTS	7	/* use short integers */
X#define OPT_REGARGS	8	/* use register argument passing */
X#define OPT_LONGALIGN	9	/* align everything to long boundaries */
X#define OPT_STACKCHECK	10	/* put stack-checking into the func prolog */
X#define OPT_PURESTRINGS	11	/* put strings in the text segment */
X
X#define OPT_FFP		12	/* use mot fast floating point */
X#define OPT_881		13	/* compile for a 68881 */
X#define OPT_IEEE	14	/* ieee floating point */
X
X#define OPT_68K		15	/* compile for a 68000 and up */
X#define OPT_020		16	/* compile for a 68020 and up */
X#define OPT_030		17	/* compile for a 68030 */
X
X#define OPT_DETACH	18	/* make a program that runs in the background */
X#define OPT_TINYMAIN	19	/* use tinymain (this doesn't work) */
X#define OPT_RESIDENT	20	/* try and make resident-able */
X#define OPT_CATCH	21	/* compile in code to try and catch exceptions */
X
X#define OPT_OPTIMIZE	22	/* optimize the obj module */
X#define OPT_LINK	23	/* link the object modules */
X#define OPT_COMPILE	24	/* (otherwise, just pre-process) */
X#define OPT_ASSEMBLE	25	/* emit object-modules (else assembly) */
X#define OPT_DEBUG	26	/* produce debugging info */
X
X#define OPT_ECHO	27	/* echo what we execute */
X#define OPT_FILTER	28	/* filter out yucky message from passes */
X#define OPT_EXEC	29	/* actually run each pass */
X
X#define OPT_BIGLC1	30	/* run lc1b instead of lc1 */
SHAR_EOF
echo "End of archive 1 (of 1)"
# if you want to concatenate archives, remove anything after this line
exit