}
#endif
-/*@-redef@*/
-int main(int argc, char *argv[])
-/*@=redef@*/
+extern int optind; /* set by getopt */
+
+/**
+ * This parses command line options.
+ * @param argc What do you think?
+ * @param argv Likewise.
+ * @note May (directly) call ick_lose() with IE111 and IE256.
+ */
+static void parse_options(int argc, char *argv[])
{
- /*@-nestedextern@*/
- extern int optind; /* set by getopt */
- /*@=nestedextern@*/
- char buf[BUFSIZ], buf2[BUFSIZ], *chp, yukcmdstr[BUFSIZ], path[BUFSIZ],
- libbuf[BUFSIZ];
- tuple *tp;
- atom *op;
- int c, i;
- /*@-shadow@*/ /* no it doesn't, cesspool isn't linked to perpet */
- const char *includedir, *libdir, *ick_datadir;
- /*@=shadow@*/
- /* AIS: removed getenv(), added ick_datadir */
- const char *cooptsh; /* AIS */
- FILE *ifp, *ofp;
- int maxabstain, /* nextcount, AIS */ bugline;
- ick_bool needsyslib, firstfile;
- int oldoptind;
-#ifdef HAVE_UNISTD_H
- int oldstdin; /* AIS: for keeping track of where stdin was */
-#endif
-
- if (!(includedir = getenv("ICKINCLUDEDIR")))
- includedir = ICKINCLUDEDIR;
- if (!(libdir = getenv("ICKLIBDIR")))
- libdir = ICKLIBDIR;
- if (!(ick_datadir = getenv("ICKDATADIR"))) /* AIS */
- ick_datadir = ICKDATADIR;
-/*
- AIS: nothing actually uses this at the moment,
- commenting it out for future use
-
- if (!(bindir = getenv("ICKBINDIR")))
- bindir = ICKBINDIR;
-*/
- if (!(compiler = getenv("CC")))
- compiler = CC;
+ int c;
/* getopt is POSIX, and I provide my own version if the POSIX version
isn't found, so the unrecog warning is a false positive. */
/*@-unreachable@*/ break; /*@=unreachable@*/
}
}
+}
- (void) signal(SIGSEGV, abend);
-#ifdef SIGBUS
- (void) signal(SIGBUS, abend);
-#endif /* SIGBUS */
-
- if (!nocompilerbug) {
-#ifdef USG
- srand48(time(NULL) + getpid());
-#else
- srand((unsigned)time(NULL));
-#endif /* UNIX */
- }
-
- /* AIS: New function for enhanced file-finding */
- ifp = ick_findandfopen(pickcompile?PSKELETON:SKELETON,
- ick_datadir, "r", argv[0]);
- if(!ifp) ick_lose(IE999, 1, (const char *)NULL);
-
- /* now substitute in tokens in the skeleton */
-
- /* AIS: This doesn't actually seem to do anything, and buf is
- uninitialised at this point, so it's actually dangerous
- because it's undefined behaviour.
- buf[strlen(buf) - 2] = '\0'; */
-
- /* AIS: Save the old stdin, if we can */
-#ifdef HAVE_UNISTD_H
- oldstdin=dup(0);
-#endif
-
- oldoptind=optind; /* AIS */
- *libbuf = 0; /* AIS */
- for (firstfile = ick_TRUE; optind < argc; optind++, firstfile = ick_FALSE)
- {
- /* AIS: Read as binary to pick up Latin-1 and UTF-8 better */
- if (/* AIS */ strrchr(argv[optind],'.') != NULL &&
- freopen(argv[optind], "rb", stdin) == (FILE *)NULL &&
- /* AIS */ strcmp(strchr(argv[optind],'.')+1,"a"))
- ick_lose(IE777, 1, (const char *)NULL);
- else
- {
- /* strip off the file extension */
- if(!(chp = strrchr(argv[optind],'.')))
- {
- if(useickec && firstfile == ick_FALSE) /* By AIS */
- {
- /* the filename indicates a request for an expansion library,
- along the same lines as CLC-INTERCAL's preloads. Search for
- it in the usual places, then make a copy in a temp directory
- and substitute that on the command line. */
- const char* tempfn;
- FILE* fromcopy;
- FILE* tocopy;
- int c2;
- fixexpansionlibrary:
- tempfn="%s.c";
- (void) ick_snprintf_or_die(buf2, sizeof buf2, "%s.c", argv[optind]);
- fromcopy = ick_findandfopen(buf2,ick_datadir,"rb",argv[0]);
- if(!fromcopy) /* same error as for syslib */
- ick_lose(IE127, 1, (const char*) NULL);
-#if __DJGPP__
- /* Look for a temp directory to store a copy of the C file,
- the resulting .cio, .o files, etc. */
- if(isenv("TMP")) tempfn="/dev/env/TMP/%s.c";
- if(isenv("TEMP")) tempfn="/dev/env/TEMP/%s.c";
- if(isenv("TMPDIR")) tempfn="/dev/env/TMPDIR/%s.c";
- if(isenv("ICKTEMP")) tempfn="/dev/env/ICKTEMP/%s.c";
-#else
- tempfn="/tmp/%s.c"; /* always valid on POSIX */
-#endif
- /*@-formatconst@*/ /* all possibilities are fine */
- (void) ick_snprintf_or_die(buf2, sizeof buf2, tempfn, argv[optind]);
- /*@=formatconst@*/
- if((tocopy = fopen(buf2,"wb")) == NULL)
- ick_lose(IE888, 1, (const char*) NULL);
-
- for(;;)
- {
- c2=fgetc(fromcopy);
- if(c2==EOF) break;
- (void) fputc(c2,tocopy);
- }
- (void) fclose(fromcopy); (void) fclose(tocopy);
- /*@+onlytrans@*/
- /* this is a memory leak that will need sorting out later,
- thus the explicit turn-warning-on */
- argv[optind]=malloc(sizeof(buf2)+1);
- /*@=onlytrans@*/
- if(!(argv[optind]))
- ick_lose(IE888, 1, (const char*) NULL);
- strcpy(argv[optind],buf2);
- *(strrchr(argv[optind],'.')) = '\0';
- continue;
- }
-
- ick_lose(IE998, 1, (const char *)NULL);
- }
- *chp++ = '\0';
-
- if(useickec && (!strcmp(chp,"c") || !strcmp(chp,"cio") ||
- !strcmp(chp,"c99"))) /* AIS */
- {
- if(firstfile != ick_FALSE) /* need exactly 1 INTERCAL file */
- ick_lose(IE998, 1, (const char *)NULL);
- continue; /* don't process C or cio files further yet */
- }
- if(useickec && !strcmp(chp,"a"))
- {
+/**
+ * This code handles archives (for -e).
+ * @param libbuf Pointer to a buffer to which extra files to link in prelink()
+ * will be added. Need to be initialized up to the first zero byte.
+ * @param libbuf_size Size of the buffer libbuf.
+ * @param library The cmd line argument used for the library (but without the
+ * extension).
+ */
+static void handle_archive(char *libbuf, size_t libbuf_size,
+ /*@observer@*/ const char* library)
+{
/* AIS: request for a library. Given a filename of the form
libwhatever.a, it adds -lwhatever to libbuf (that's with
a preceding space). If the filename doesn't start with lib,
it instead adds a space and the filename to libbuf. */
- if(argv[optind][0]=='l'&&argv[optind][1]=='i'&&
- argv[optind][2]=='b')
- ick_snprintf_or_die(libbuf+strlen(libbuf),sizeof libbuf - strlen(libbuf),
- " -l%s",argv[optind]+3);
+ if(library[0]=='l'&&library[1]=='i'&&
+ library[2]=='b')
+ ick_snprintf_or_die(libbuf+strlen(libbuf),libbuf_size - strlen(libbuf),
+ " -l%s",library+3);
else
- ick_snprintf_or_die(libbuf+strlen(libbuf),sizeof libbuf - strlen(libbuf),
- " %s.a",argv[optind]);
- *argv[optind]=0;
- continue;
- }
+ ick_snprintf_or_die(libbuf+strlen(libbuf),libbuf_size - strlen(libbuf),
+ " %s.a",library);
+}
- if(useickec && !strcmp(chp,"b98"))
- {
+
+/**
+ * This handles Befunge 98 (for -e).
+ * @param libbuf Pointer to a buffer to which extra files to link in prelink()
+ * will be added. Need to be initialized up to the first zero byte.
+ * @param libbuf_size Size of the buffer libbuf.
+ * @param libdir The ick library directory.
+ * @param argv0 Should be argv[0], which wasn't modified.
+ * @param filename The file name of the Befunge file (but without the extension).
+ * @note May (directly) call ick_lose() with IE888 and IE899.
+ */
+static void handle_befunge98(char *libbuf, size_t libbuf_size,
+ /*@observer@*/ const char* libdir,
+ /*@observer@*/ const char* argv0,
+ /*@observer@*/ const char* filename)
+{
/* AIS: Compile the .b98 file into a .cio so that it can be used
later, and include the necessary libraries to use it, or error
if the libraries aren't installed yet. I use a somewhat dubious
FILE* of;
int x,y,jlb;
+ char outputfilename[BUFSIZ];
int markerposns[MARKERMAX][2];
int markercount=0;
/* Error if libick_ecto_b98.a is missing. It might be, and not
just due to installation problems. */
- if(!ick_findandtestopen("libick_ecto_b98.a",libdir,"rb",argv[0]))
+ if(!ick_findandtestopen("libick_ecto_b98.a",libdir,"rb",argv0))
ick_lose(IE899,-1,(const char *)NULL);
/* Compile the .b98 file into a .cio. It's open on stdin right now,
so we just need to handle the output side of things. */
- ick_snprintf_or_die(buf2, sizeof buf2, "%s.cio", argv[optind]);
+ ick_snprintf_or_die(outputfilename, sizeof outputfilename, "%s.cio", filename);
- if(!((of = ick_debfopen(buf2,"w"))))
+ if(!((of = ick_debfopen(outputfilename,"w"))))
ick_lose(IE888,-1,(const char *)NULL);
fprintf(of,"const char* ick_iffi_befungeString=\n\"");
fclose(of);
/* Put the libraries and .cio file in the command line. */
- ick_snprintf_or_die(libbuf+strlen(libbuf),sizeof libbuf - strlen(libbuf),
- " %s.cio -lick_ecto_b98 -lm -lncurses", argv[optind]);
- /* Sort out the ecto_b98 expansion library. */
- argv[optind] = "ecto_b98";
- goto fixexpansionlibrary;
- }
+ ick_snprintf_or_die(libbuf+strlen(libbuf),libbuf_size - strlen(libbuf),
+ " %s.cio -lick_ecto_b98 -lm -lncurses", filename);
+}
- if(useickec && firstfile == ick_FALSE) /* AIS */
- ick_lose(IE998, 1, (const char *)NULL);
+/**
+ * This computes what type the INTERCAL source file is.
+ * It will change various globals.
+ * @param chp A pointer to the first letter of the extension of the file. Note
+ * that it won't be changed, but can't be const char* due to being
+ * passed as the second parameter to strtol() as well.
+ * @note May (directly) call ick_lose() with IE111, IE256 and IE998.
+ */
+static void find_intercal_base(char* chp)
+{
/* wwp: reset the base variables to defaults, because if the */
/* sourcefile has extension .i they will not be reset in the */
/* following chunk of code. but i don't want to modify the */
else
ick_Max_large = (ick_Max_small + 1) * (ick_Max_small + 1) - 1;
}
+}
- /* zero out tuple and oblist storage */
- treset();
- politesse = 0;
- /* JH: default to no op-overusage and no computed come from */
- opoverused = 0;
- compucomesused = compucomecount = 0;
- gerucomesused = 0; /* AIS: you forgot this one */
- /* AIS: ensure that at least one variable exists, to prevent
- NULL pointers later on */
- (void) intern(ick_ONESPOT, 1); /* mention .1 */
-
- /* reset the lex/yacc environment */
- if (!firstfile)
- {
-#ifdef NEED_YYRESTART
- yyrestart(stdin);
-#endif /* NEED_YYRESTART */
- iyylineno = 1;
- }
-
- /* compile tuples from current input source */
- (void) yyparse();
-
- if(variableconstants)
- {
- /* AIS: Up to 4 extra meshes may be needed by feh.c. */
- (void) intern(MESH, 0xFFFFFFFFLU);
- (void) intern(MESH, 0xFFFFLU);
- (void) intern(MESH, 0xAAAAAAAALU);
- (void) intern(MESH, 0x55555555LU);
- }
-
-
- /*
- * Miss Manners lives.
- */
- if (ick_lineno > 2)
- {
- if (politesse == 0 || (ick_lineno - 1) / politesse >= 5)
- ick_lose(IE079, iyylineno, (const char *)NULL);
- else if (ick_lineno / politesse < 3)
- ick_lose(IE099, iyylineno, (const char *)NULL);
- }
+/**
+ * This checks if we automagically need to include syslib
+ * @param buffer Output buffer that may be modified to contain the path of
+ * syslib.i or syslib.Ni (where N is 3-7).
+ * @param size Size of buffer.
+ * @param needsyslib Pointer to the ick_bool needsyslib declared in main().
+ * @param argv0 Should be argv[0], which wasn't modified.
+ * @param ick_datadir The ick data directory.
+ * @note May (directly) call ick_lose() with IE127.
+ */
+static void check_syslib(/*@partial@*/ char *buffer,
+ size_t size,
+ /*@out@*/ ick_bool *needsyslib,
+ /*@observer@*/ const char *argv0,
+ /*@observer@*/ const char *ick_datadir)
+{
+ tuple *tp;
/*
* check if we need to magically include the system library
*/
- needsyslib = ick_FALSE;
+ *needsyslib = ick_FALSE;
if(!pickcompile) /* AIS: We never need syslib when compiling
for PIC, because it's preoptimized. */
{
* can stop searching and won't need the syslib.
*/
if (tp->label >= 1000 && tp->label <= 1999) {
- needsyslib = ick_FALSE;
+ *needsyslib = ick_FALSE;
break;
}
/*
*/
if (tp->type == NEXT && tp->u.target >= 1000 &&
tp->u.target <= 1999)
- needsyslib = ick_TRUE;
+ *needsyslib = ick_TRUE;
}
}
- if(nosyslib) needsyslib = ick_FALSE; /* AIS */
- if (needsyslib)
+ if(nosyslib) *needsyslib = ick_FALSE; /* AIS */
+ if (*needsyslib)
{ /* AIS: modified to use ick_findandfreopen */
if (ick_Base == 2) /* see code for opening the skeleton */
- (void) ick_snprintf_or_die(buf2, sizeof buf2, "%s.i", SYSLIB);
+ (void) ick_snprintf_or_die(buffer, size, "%s.i", SYSLIB);
else
- (void) ick_snprintf_or_die(buf2, sizeof buf2, "%s.%di", SYSLIB, ick_Base);
- if (ick_findandfreopen(buf2, ick_datadir, "r", argv[0], stdin) == NULL)
+ (void) ick_snprintf_or_die(buffer, size, "%s.%di", SYSLIB, ick_Base);
+ if (ick_findandfreopen(buffer, ick_datadir, "r", argv0, stdin) == NULL)
ick_lose(IE127, 1, (const char*) NULL);
#ifdef USE_YYRESTART
yyrestart(stdin);
(void) yyparse();
textlinecount=iyylineno;
}
+}
+
+/**
+ * This code propagates type information up the expression tree.
+ * It also does some unrelated stuff such as checking for WRITE IN and disabling
+ * coopt if that is found.
+ */
+static void propagate_typeinfo(void)
+{
+ tuple *tp;
/*
* Now propagate type information up the expression tree.
* We need to do this because the unary-logical operations
if (tp->type == WRITE_IN) coopt = 0; /* AIS: may as well do
this here */
}
+}
- codecheck(); /* check for compile-time errors */
- /* AIS: And importantly, sort out line number references */
+/**
+ * This runs the optimiser.
+ */
+static void run_optimiser(void)
+{
+ tuple *tp;
/* perform optimizations */
if (dooptimize)
for (tp = tuples; tp->type; tp++)
/* AIS: perform flow optimizations */
if (flowoptimize) optimizef();
+}
+
+/**
+ * Generate random line number for E774.
+ * @returns A random line number, or -1 for no random bug generated.
+ */
+static int randomise_bugline(void)
+{
/* decide if and where to place the compiler bug */
#ifdef USG
if (!nocompilerbug && lrand48() % 10 == 0)
- bugline = (int)(lrand48() % ick_lineno);
+ return (int)(lrand48() % ick_lineno);
#else
if (!nocompilerbug && rand() % 10 == 0)
- bugline = rand() % ick_lineno;
+ return rand() % ick_lineno;
#endif
else
- bugline = -1;
+ return -1;
+}
- /* set up the generated C output file name */
- (void) strcpy(buf, argv[optind]);
- (void) strcat(buf, ".c");
+
+/**
+ * This opens the outfile.
+ * @param filename The filename to open.
+ * @returns A pointer to a FILE for the filename. If the global outtostdout is
+ * set then it will return stdout.
+ * @note May (directly) call ick_lose() with IE888.
+ */
+static /*@dependent@*/ FILE* open_outfile(/*@observer@*/ const char * filename)
+{
+ FILE *ofp;
/* AIS: ofp holds fopened storage if !outtostdout, and local-copy
storage if outtostdout, and this is not a bug, although it
confuses Splint. */
/*@-branchstate@*/
if(outtostdout) ofp=stdout; /* AIS */
- else if((ofp = ick_debfopen(buf, "w")) == (FILE *)NULL)
+ else if((ofp = ick_debfopen(filename, "w")) == (FILE *)NULL)
ick_lose(IE888, 1, (const char *)NULL);
/*@=branchstate@*/
+ return ofp;
+}
- (void) fseek(ifp,0L,0); /* rewind skeleton file */
-
- /* AIS: Before changing argv[0], locate coopt.sh. */
- cooptsh = ick_findandtestopen("coopt.sh", ick_datadir, "rb", argv[0]);
- /* AIS: and calculate yukcmdstr. */
- (void) ick_snprintf_or_die(yukcmdstr, sizeof yukcmdstr, "%s%s" EXEEXT " %s %s",
- strchr(argv[optind],'/')||strchr(argv[optind],'\\')?
- "":"./",argv[optind],ick_datadir,argv[0]);
-
- /* AIS: Remove the filename from argv[0], leaving only a directory.
- If this would leave it blank, change argv[0] to '.'.
- This is so gcc can find the includes/libraries the same way that
- ick_findandfreopen does. */
- /* JH: use a copy of argv[0] for the path, to ensure argv[0] is
- * available for the next round
- */
- strcpy(path,argv[0]);
- if(strchr(path,'/')) *(strrchr(path,'/')) = '\0';
- else strcpy(path,".");
- (void) ick_snprintf_or_die(buf2, sizeof buf2,
- "%s %s%s-I%s -I%s -I%s/../include -L%s -L%s -L%s/../lib -O%c -o %s"
+/**
+ * This generates the CC command line.
+ * @param buffer Output buffer.
+ * @param size Size of the output buffer.
+ * @param sourcefile The name of the C file.
+ * @param includedir The ick include directory.
+ * @param path The path of the ick binary (execuding filename).
+ * @param libdir The ick library directory.
+ * @param outputfile The name of the output file.
+ */
+static void gen_cc_command(char* buffer, size_t size,
+ /*@observer@*/ const char* sourcefile,
+ /*@observer@*/ const char* includedir,
+ /*@observer@*/ const char* path,
+ /*@observer@*/ const char* libdir,
+ /*@observer@*/ const char* outputfile)
+{
+ (void) ick_snprintf_or_die(buffer, size,
+ "%s %s%s-I%s -I%s -I%s/../include -L%s -L%s -L%s/../lib -O%c -o %s" EXEEXT " -lick%s%s",
#ifdef __DJGPP__
- EXEEXT " -lick%s%s","",
+ "",
#else
- EXEEXT " -lick%s%s",compiler,
+ compiler,
#endif
#ifdef HAVE_CLOCK_GETTIME /* implies -lrt is available */
- buf, yukdebug||yukprofile?" -lyuk -lrt ":" ",
+ sourcefile, yukdebug||yukprofile?" -lyuk -lrt ":" ",
#else
- buf, yukdebug||yukprofile?" -lyuk ":" ",
+ sourcefile, yukdebug||yukprofile?" -lyuk ":" ",
#endif
includedir, path, path, libdir, path, path,
cdebug?'0':coopt?'3':'2', /* AIS: If coopting, optimize as much as possible
JH: [d]on't optimise when compiling with debugger support */
- argv[optind], multithread?"mt":"", cdebug?" -g":"");
+ outputfile, multithread?"mt":"", cdebug?" -g":"");
/* AIS: Possibly link in the debugger yuk and/or libickmt.a here. */
/* AIS: Added -g support. */
/* AIS: Added argv[0] (now path) to the -I, -L settings. */
+}
- textlinecount=0; /* AIS: If there are no files, there's
- no need to free any textlines */
+
+/**
+ * This generates the actual C code.
+ * @param ifp This should be opened to either ick-wrap.c or pickwrap.c.
+ * @param ofp The out file.
+ * @param source_name_stem Source name stem
+ * @param needsyslib Pointer to the needsyslib bool in main().
+ * @param bugline What line number to add a random bug to.
+ * @param compilercommand The compiler command line.
+ * @note May (directly) call ick_lose() with IE256.
+ */
+static void generate_code(FILE *ifp, FILE *ofp,
+ /*@observer@*/ const char* source_name_stem,
+ ick_bool *needsyslib,
+ int bugline,
+ /*@observer@*/ const char* compilercommand)
+{
+ int maxabstain;
+ int c, i;
+ tuple *tp;
+ atom *op;
while ((c = myfgetc(ifp)) != EOF)
if (c != (int)'$')
(void) fputc(c, ofp);
else switch(myfgetc(ifp))
{
case 'A': /* source name stem */
- (void) fputs(argv[optind], ofp);
+ (void) fputs(source_name_stem, ofp);
break;
case 'B': /* # of statements */
isn't referenced; if it isn't, we can allow
one double-oh-seven if syslib was
automagically inclulded. */
- if(needsyslib) needsyslib = 0; else coopt = 0;
+ if(*needsyslib) *needsyslib = 0; else coopt = 0;
}
if(!pickcompile)
{
#else
"","",
#endif
- buf2);
+ compilercommand);
break;
case 'M': /* AIS: place new features defines in program */
emitslat(ofp);
break;
}
+}
- if(!outtostdout) (void) fclose(ofp);
+/**
+ * This runs the C compiler, and may invoke yuk.
+ * @param cc_command The compiler command line to use. Constructed by gen_cc_command().
+ * @param oldstdin The previous stdin, used for yuk.
+ * @param yukcmdstr The command line to use for running yuk.
+ * @param sourcefile The output filename.
+ * @param binaryname The name of the binary.
+ */
+static void run_cc_and_maybe_debugger(/*@observer@*/ const char *cc_command,
+ int oldstdin,
+ /*@observer@*/ const char *yukcmdstr,
+ /*@observer@*/ const char *sourcefile,
+ /*@observer@*/ const char *binaryname)
+{
#ifndef __DJGPP__
/* OK, now sic the C compiler on the results */
if (!compile_only&&!yukdebug&&!yukprofile&&!useickec)
{
/* AIS: buf2 now assigned elsewhere so $L works */
- ICK_SYSTEM(buf2);
- /* AIS: no unlink if cdebug */ if(!cdebug) (void) unlink(buf);
+ ICK_SYSTEM(cc_command);
+ /* AIS: no unlink if cdebug */ if(!cdebug) (void) unlink(sourcefile);
}
else if(!compile_only&&!useickec)
{ /* AIS: run, then delete all output but yuk.out */
/* Note that the output must be deleted for copyright
reasons (so as not to GPL a non-GPL file automatically) */
- ICK_SYSTEM(buf2);
+ ICK_SYSTEM(cc_command);
#ifdef HAVE_UNISTD_H
(void) dup2(oldstdin,0); /* restore stdin */
#endif
ICK_SYSTEM(yukcmdstr);
- (void) unlink(buf);
- (void) unlink(argv[optind]);
+ (void) unlink(sourcefile);
+ (void) unlink(binaryname);
}
#else /* we are using DJGPP */
/* OK, now sic the C compiler on the results */
with the arguments needed to give gcc. */
FILE* rsp;
/* Use current dir as temp if needed */
- char* tempfn="gcc @ickgcc.rsp";
+ const char* tempfn="gcc @ickgcc.rsp";
/* Four tries are used to find a temp directory.
ICKTEMP is the preferred environment variable to check;
if, as expected, this isn't set, try TMPDIR (which DJGPP
if(isenv("TMPDIR")) tempfn="gcc @/dev/env/TMPDIR/ickgcc.rsp";
if(isenv("ICKTEMP")) tempfn="gcc @/dev/env/ICKTEMP/ickgcc.rsp";
rsp=ick_debfopen(tempfn+5,"w");
- fprintf(rsp,"%s\n",buf2);
+ fprintf(rsp,"%s\n",cc_command);
fclose(rsp);
ICK_SYSTEM(tempfn);
remove(tempfn+5);
if(yukdebug || yukprofile)
{
+ char buffer[BUFSIZ];
#ifdef HAVE_UNISTD_H
dup2(oldstdin,0); /* restore stdin */
#endif
- ick_snprintf_or_die(buf2, sizeof buf2, "%s" EXEEXT,argv[optind]);
+/* FIXME: This looks broken (the buf2 usage and such). */
+ ick_snprintf_or_die(buffer, sizeof(buffer), "%s" EXEEXT,binaryname);
ICK_SYSTEM(yukcmdstr);
- remove(buf);
- remove(buf2);
+ remove(sourcefile);
+ remove(buffer);
}
else if(!cdebug)
{
- remove(buf);
+ remove(sourcefile);
}
}
#endif
+
+}
+
+
+/**
+ * This runs coopt.sh if -F is given and the program can be "coopted".
+ * @param cooptsh Path to coopt.sh
+ * @param binaryname The output binary filename.
+ */
+static void run_coopt(/*@observer@*/ /*@null@*/ const char* cooptsh,
+ /*@observer@*/ const char* binaryname)
+{
+ char commandlinebuf[BUFSIZ];
#ifdef HAVE_PROG_SH
# ifdef HAVE_SYS_INTERPRETER
- if(coopt) /* AIS */
- {
- /* The constant-output optimizer is a form of post-processor.
- IMPORTANT NOTE: This MUST NOT be run if the input program
- takes any input or is affected in any way by the state of
- the system, as the degenerated program may be wrong. At the
- moment, the only INTERCAL command that takes input is
- WRITE IN. Double-oh-sevens screw this up, too. */
- if(cooptsh)
- {
- (void) ick_snprintf_or_die(buf2, sizeof buf2,
- "sh %s %s", cooptsh, argv[optind]);
- ICK_SYSTEM(buf2); /* replaces the output executable if
- neccesary */
- }
- }
-# endif
-#endif
+ if(coopt) /* AIS */
+ {
+ /* The constant-output optimizer is a form of post-processor.
+ IMPORTANT NOTE: This MUST NOT be run if the input program
+ takes any input or is affected in any way by the state of
+ the system, as the degenerated program may be wrong. At the
+ moment, the only INTERCAL command that takes input is
+ WRITE IN. Double-oh-sevens screw this up, too. */
+ if(cooptsh)
+ {
+ (void) ick_snprintf_or_die(commandlinebuf, sizeof commandlinebuf,
+ "sh %s %s", cooptsh, binaryname);
+ ICK_SYSTEM(commandlinebuf); /* replaces the output executable if
+ neccesary */
}
}
- (void) fclose(ifp);
+# endif
+#endif
+}
- if(!compile_only && useickec) /* AIS */
- {
+
+/**
+ * This is for -e, runs prelinking.
+ * @param argc Exactly what you think.
+ * @param argv Also what you think.
+ * @param oldoptind The original optind.
+ * @param libdir The ick library directory.
+ * @param includedir The ick include directory.
+ * @param path The path of the ick binary (execuding filename).
+ * @param libbuf A string with -lfoo to add to compiler command line.
+ * @note May (directly) call ick_lose() with IE666. IE778 and IE888.
+ */
+static void prelink(int argc, char *argv[], int oldoptind,
+ /*@observer@*/ const char* libdir,
+ /*@observer@*/ const char *includedir,
+ /*@observer@*/ const char* path,
+ /*@observer@*/ const char* libbuf)
+{
+ char buffer[BUFSIZ];
FILE* cioin;
FILE* cioallec;
char* buf2ptr;
executable. */
for(optind=oldoptind; optind < argc; optind++)
{
- (void) ick_snprintf_or_die(buf2, sizeof buf2,
+ (void) ick_snprintf_or_die(buffer, sizeof buffer,
"%s --std=c%d -E -DICK_HAVE_STDINT_H=%d "
"-I%s -I%s -I%s/../include "
"-x c %s.c%c%c > %s.cio",
if(*(argv[optind]) && /* there is some file to compile */
(argv[optind][strlen(argv[optind])+2]=='\0' /* a .c or .i file */
||argv[optind][strlen(argv[optind])+3]!='o')) /* not a .cio file */
- ICK_SYSTEM(buf2); /* run the C preprocessor */
- buf2ptr = strrchr(buf2,'>'); /* get the .cio's filename */
+ ICK_SYSTEM(buffer); /* run the C preprocessor */
+ buf2ptr = strrchr(buffer,'>'); /* get the .cio's filename */
cioin=NULL;
/* Do our preprocessing, by editing the file in place using rb+. */
if(buf2ptr != NULL && buf2ptr[1] != '\0' && buf2ptr[2] != '\0')
fprintf(cioallec,"};\n");
(void) fclose(cioallec);
+ /* NOTE: buffer changes use around here. */
+
/* This command line needs some explanation, and is specific to gcc and
GNU ld. The -x causes gcc to interpret the .cio files as C; the
-Wl,-z,muldefs is an instruction to GNU ld, telling it to link in the
first main found and ignore the others. (That way, there can be a
main function in each .cio, but the .cios can be linked in any order,
with the right main function foremost each time.)
- */
- (void) ick_snprintf_or_die(buf2, sizeof buf2,
-"%s -L%s -L%s -L%s/../lib -O2 -o %s" EXEEXT "%s "
+ */
+ (void) ick_snprintf_or_die(buffer, sizeof buffer,
+ "%s -L%s -L%s -L%s/../lib -O2 -o %s" EXEEXT "%s "
#ifndef __DJGPP__
-"-Wl,-z,muldefs "
+ "-Wl,-z,muldefs "
#endif
-"-DICK_HAVE_STDINT_H=%d -x c --std=c%d %s", compiler, libdir,
-path, path, argv[oldoptind], cdebug?" -g":"", ICK_HAVE_STDINT_H+1==2?1:0,
-needc99?99:89,tempfn);
- remspace = (long)(sizeof buf2 - strlen(buf2) - 1);
+ "-DICK_HAVE_STDINT_H=%d -x c --std=c%d %s", compiler, libdir,
+ path, path, argv[oldoptind], cdebug?" -g":"", ICK_HAVE_STDINT_H+1==2?1:0,
+ needc99?99:89,tempfn);
+ remspace = (long)(sizeof buffer - strlen(buffer) - 1);
for(optind=oldoptind; optind < argc; optind++)
{
if(!*(argv[optind])) continue;
remspace -= strlen(argv[optind]) - 5; /* 5 for <space>.cio */
if(remspace <= 0)
ick_lose(IE666, -1, (const char*)NULL);
- strcat(buf2," ");
- strcat(buf2,argv[optind]);
- strcat(buf2,".cio");
+ strcat(buffer," ");
+ strcat(buffer,argv[optind]);
+ strcat(buffer,".cio");
}
remspace -= strlen(libbuf);
if(remspace <= 0)
ick_lose(IE666, -1, (const char*)NULL);
- strcat(buf2,libbuf);
+ strcat(buffer,libbuf);
remspace -= strlen(" -lickec");
if(remspace <= 0)
ick_lose(IE666, -1, (const char*)NULL);
- strcat(buf2," -lickec");
- ICK_SYSTEM(buf2);
+ strcat(buffer," -lickec");
+ ICK_SYSTEM(buffer);
(void) remove(tempfn);
+}
+
+
+/*@-redef@*/
+int main(int argc, char *argv[])
+/*@=redef@*/
+{
+ char buf[BUFSIZ], buf2[BUFSIZ], *chp, yukcmdstr[BUFSIZ], path[BUFSIZ],
+ libbuf[BUFSIZ];
+ /*@-shadow@*/ /* no it doesn't, cesspool isn't linked to perpet */
+ const char *includedir, *libdir, *ick_datadir;
+ /*@=shadow@*/
+ /* AIS: removed getenv(), added ick_datadir */
+ const char *cooptsh; /* AIS */
+ FILE *ifp, *ofp;
+ int /* nextcount, AIS */ bugline;
+ ick_bool needsyslib, firstfile;
+ int oldoptind;
+#ifdef HAVE_UNISTD_H
+ int oldstdin; /* AIS: for keeping track of where stdin was */
+#endif
+ if (!(includedir = getenv("ICKINCLUDEDIR")))
+ includedir = ICKINCLUDEDIR;
+ if (!(libdir = getenv("ICKLIBDIR")))
+ libdir = ICKLIBDIR;
+ if (!(ick_datadir = getenv("ICKDATADIR"))) /* AIS */
+ ick_datadir = ICKDATADIR;
+/*
+ AIS: nothing actually uses this at the moment,
+ commenting it out for future use
+
+ if (!(bindir = getenv("ICKBINDIR")))
+ bindir = ICKBINDIR;
+*/
+ if (!(compiler = getenv("CC")))
+ compiler = CC;
+
+ /* Parse the options. */
+ parse_options(argc, argv);
+
+ (void) signal(SIGSEGV, abend);
+#ifdef SIGBUS
+ (void) signal(SIGBUS, abend);
+#endif /* SIGBUS */
+
+ if (!nocompilerbug) {
+#ifdef USG
+ srand48(time(NULL) + getpid());
+#else
+ srand((unsigned)time(NULL));
+#endif /* UNIX */
}
+ /* AIS: New function for enhanced file-finding */
+ ifp = ick_findandfopen(pickcompile?PSKELETON:SKELETON,
+ ick_datadir, "r", argv[0]);
+ if(!ifp) ick_lose(IE999, 1, (const char *)NULL);
+
+ /* now substitute in tokens in the skeleton */
+
+ /* AIS: This doesn't actually seem to do anything, and buf is
+ uninitialised at this point, so it's actually dangerous
+ because it's undefined behaviour.
+ buf[strlen(buf) - 2] = '\0'; */
+
+ /* AIS: Save the old stdin, if we can */
+#ifdef HAVE_UNISTD_H
+ oldstdin=dup(0);
+#endif
+
+ oldoptind=optind; /* AIS */
+ *libbuf = 0; /* AIS */
+ /* Begin file loop */
+ for (firstfile = ick_TRUE; optind < argc; optind++, firstfile = ick_FALSE)
+ {
+ /* AIS: Read as binary to pick up Latin-1 and UTF-8 better */
+ if (/* AIS */ strrchr(argv[optind],'.') != NULL &&
+ freopen(argv[optind], "rb", stdin) == (FILE *)NULL &&
+ /* AIS */ strcmp(strchr(argv[optind],'.')+1,"a"))
+ ick_lose(IE777, 1, (const char *)NULL);
+ else
+ {
+ /* strip off the file extension */
+ if(!(chp = strrchr(argv[optind],'.')))
+ {
+ if(useickec && firstfile == ick_FALSE) /* By AIS */
+ {
+ /* the filename indicates a request for an expansion library,
+ along the same lines as CLC-INTERCAL's preloads. Search for
+ it in the usual places, then make a copy in a temp directory
+ and substitute that on the command line. */
+ const char* tempfn;
+ FILE* fromcopy;
+ FILE* tocopy;
+ int c2;
+ fixexpansionlibrary:
+ tempfn="%s.c";
+ (void) ick_snprintf_or_die(buf2, sizeof buf2, "%s.c", argv[optind]);
+ fromcopy = ick_findandfopen(buf2,ick_datadir,"rb",argv[0]);
+ if(!fromcopy) /* same error as for syslib */
+ ick_lose(IE127, 1, (const char*) NULL);
+#if __DJGPP__
+ /* Look for a temp directory to store a copy of the C file,
+ the resulting .cio, .o files, etc. */
+ if(isenv("TMP")) tempfn="/dev/env/TMP/%s.c";
+ if(isenv("TEMP")) tempfn="/dev/env/TEMP/%s.c";
+ if(isenv("TMPDIR")) tempfn="/dev/env/TMPDIR/%s.c";
+ if(isenv("ICKTEMP")) tempfn="/dev/env/ICKTEMP/%s.c";
+#else
+ tempfn="/tmp/%s.c"; /* always valid on POSIX */
+#endif
+ /*@-formatconst@*/ /* all possibilities are fine */
+ (void) ick_snprintf_or_die(buf2, sizeof buf2, tempfn, argv[optind]);
+ /*@=formatconst@*/
+ if((tocopy = fopen(buf2,"wb")) == NULL)
+ ick_lose(IE888, 1, (const char*) NULL);
+
+ for(;;)
+ {
+ c2=fgetc(fromcopy);
+ if(c2==EOF) break;
+ (void) fputc(c2,tocopy);
+ }
+ (void) fclose(fromcopy); (void) fclose(tocopy);
+ /*@+onlytrans@*/
+ /* this is a memory leak that will need sorting out later,
+ thus the explicit turn-warning-on */
+ argv[optind]=malloc(sizeof(buf2)+1);
+ /*@=onlytrans@*/
+ if(!(argv[optind]))
+ ick_lose(IE888, 1, (const char*) NULL);
+ strcpy(argv[optind],buf2);
+ *(strrchr(argv[optind],'.')) = '\0';
+ continue;
+ }
+
+ ick_lose(IE998, 1, (const char *)NULL);
+ }
+ *chp++ = '\0';
+
+ /* Beginning of block that figures out file type from extension. */
+ if(useickec && (!strcmp(chp,"c") || !strcmp(chp,"cio") ||
+ !strcmp(chp,"c99"))) /* AIS */
+ {
+ if(firstfile != ick_FALSE) /* need exactly 1 INTERCAL file */
+ ick_lose(IE998, 1, (const char *)NULL);
+ continue; /* don't process C or cio files further yet */
+ }
+
+ if(useickec && !strcmp(chp,"a"))
+ {
+ /* AIS: request for a library. Given a filename of the form
+ libwhatever.a, it adds -lwhatever to libbuf (that's with
+ a preceding space). If the filename doesn't start with lib,
+ it instead adds a space and the filename to libbuf. */
+ handle_archive(libbuf, sizeof libbuf,
+ argv[optind] /* Archive name without extension. */);
+ *argv[optind]=0;
+ continue;
+ }
+
+ if(useickec && !strcmp(chp,"b98"))
+ {
+ handle_befunge98(libbuf, sizeof libbuf, libdir, argv[0],
+ argv[optind] /* Filename without extension. */);
+ /* Sort out the ecto_b98 expansion library. */
+ argv[optind] = "ecto_b98";
+ goto fixexpansionlibrary;
+ }
+
+ if(useickec && firstfile == ick_FALSE) /* AIS */
+ ick_lose(IE998, 1, (const char *)NULL);
+
+ /* determine the file type from the extension */
+ /* AN: chp isn't used again after this it seems? */
+ find_intercal_base(chp);
+
+ /* End of block that figures out file type from extension. */
+
+ /* zero out tuple and oblist storage */
+ treset();
+ politesse = 0;
+ /* JH: default to no op-overusage and no computed come from */
+ opoverused = 0;
+ compucomesused = compucomecount = 0;
+ gerucomesused = 0; /* AIS: you forgot this one */
+ /* AIS: ensure that at least one variable exists, to prevent
+ NULL pointers later on */
+ (void) intern(ick_ONESPOT, 1); /* mention .1 */
+
+ /* reset the lex/yacc environment */
+ if (!firstfile)
+ {
+#ifdef NEED_YYRESTART
+ yyrestart(stdin);
+#endif /* NEED_YYRESTART */
+ iyylineno = 1;
+ }
+
+ /* compile tuples from current input source */
+ (void) yyparse();
+
+ if(variableconstants)
+ {
+ /* AIS: Up to 4 extra meshes may be needed by feh.c. */
+ (void) intern(MESH, 0xFFFFFFFFLU);
+ (void) intern(MESH, 0xFFFFLU);
+ (void) intern(MESH, 0xAAAAAAAALU);
+ (void) intern(MESH, 0x55555555LU);
+ }
+
+
+ /*
+ * Miss Manners lives.
+ */
+ if (ick_lineno > 2)
+ {
+ if (politesse == 0 || (ick_lineno - 1) / politesse >= 5)
+ ick_lose(IE079, iyylineno, (const char *)NULL);
+ else if (ick_lineno / politesse < 3)
+ ick_lose(IE099, iyylineno, (const char *)NULL);
+ }
+
+ /* Check if we should auto add the system library. */
+ check_syslib(buf2, sizeof buf2, &needsyslib, argv[0], ick_datadir);
+
+ /*
+ * Now propagate type information up the expression tree.
+ * We need to do this because the unary-logical operations
+ * are sensitive to the type widths of their operands, so
+ * we have to generate different code depending on the
+ * deducible type of the operand.
+ */
+ propagate_typeinfo();
+
+ codecheck(); /* check for compile-time errors */
+ /* AIS: And importantly, sort out line number references */
+ run_optimiser();
+
+ /* decide if and where to place the compiler bug */
+ bugline = randomise_bugline();
+
+ /* set up the generated C output file name */
+ (void) ick_snprintf_or_die(buf, sizeof buf, "%s.c", argv[optind]);
+ /* Open output file. */
+ ofp = open_outfile(buf /* Output filename */);
+
+ (void) fseek(ifp,0L,0); /* rewind skeleton file */
+
+ /* AIS: Before changing argv[0], locate coopt.sh. */
+ /* AN: Even though argv[0] isn't changed any more this breaks if moved out
+ * of the per-file loop since ick_findandtestopen() returns a pointer to a
+ * static buffer. Should be fixed.
+ */
+ cooptsh = ick_findandtestopen("coopt.sh", ick_datadir, "rb", argv[0]);
+ /* AIS: and calculate yukcmdstr. */
+ (void) ick_snprintf_or_die(yukcmdstr, sizeof yukcmdstr, "%s%s" EXEEXT " %s %s",
+ strchr(argv[optind],'/')||strchr(argv[optind],'\\')?
+ "":"./",argv[optind],ick_datadir,argv[0]);
+
+ /* AIS: Remove the filename from argv[0], leaving only a directory.
+ If this would leave it blank, change argv[0] to '.'.
+ This is so gcc can find the includes/libraries the same way that
+ ick_findandfreopen does. */
+ /* JH: use a copy of argv[0] for the path, to ensure argv[0] is
+ * available for the next round
+ */
+ strcpy(path,argv[0]);
+ if(strchr(path,'/')) *(strrchr(path,'/')) = '\0';
+ else strcpy(path,".");
+
+ /* Generate the compiler command. */
+ gen_cc_command(buf2 /* output */, sizeof buf2, buf /* Source filename. */,
+ includedir, path, libdir, argv[optind] /* Output binary filename. */);
+
+ textlinecount=0; /* AIS: If there are no files, there's
+ no need to free any textlines */
+ /* Generate code using ick-wrap.c (or pickwrap.c) */
+ generate_code(ifp, ofp, argv[optind] /* Source file name stem. */,
+ &needsyslib, bugline, buf2 /* CC command. */);
+
+ if(!outtostdout) (void) fclose(ofp);
+
+ /* OK, now sic the C compiler on the results */
+ /* Also: if -y was given, run debugger */
+ run_cc_and_maybe_debugger(buf2, oldstdin, yukcmdstr, buf /* C file name */,
+ argv[optind] /* Binary filename */);
+
+ /* Run the constant-output optimizer (a form of post-processor). */
+ run_coopt(cooptsh, argv[optind]);
+
+ }
+ }
+ /* Here ends the per-file loop. */
+ (void) fclose(ifp);
+
+ if(!compile_only && useickec) /* AIS */
+ prelink(argc, argv, oldoptind, libdir, includedir, path, libbuf);
+
/* AIS: Free malloc'd memory. */
if(textlines)
{