Mercurial > projects > ldc
view dmd/mars.c @ 986:a8cb25d478c4
Use LLVM-style command line (instead of DMD-style)
Note: For a backward compatible interface, use the new bin/ldmd script. It
supports all old options while passing on anything it doesn't recognize.
Some changes caused by this:
* -debug and -version are now -d-debug and -d-version due to a conflict with
standard LLVM options.
* All "flag" options now allow an optional =true/=1/=false/=0 suffix.
* Some "hidden debug switches" starting with "--" were renamed because LLVM
doesn't care about the number of dashes, so they were conflicting with other
options (such as -c).
The new versions start with "-hidden-debug-" instead of "--"
* --help works, but has a non-zero exit code. This breaks some Tango scripts
which use it to test for compiler existence. See tango.patch.
Some changes not (directly) caused by this;
* (-enable/-disable)-FOO options are now available for pre- and postconditions.
* -march is used instead of -m (like other LLVM programs), but -m is an alias
for it.
* -defaultlib, -debuglib, -d-debug and -d-version allow comma-separated values.
The effect should be identical to specifying the same option multiple times.
I decided against allowing these for some other options because paths might
contain commas on some systems.
* -fPIC is removed in favor of the standard LLVM option -relocation-model=pic
Bug:
* If -run is specified as the last argument in DFLAGS, no error is generated.
(Not very serious IMHO)
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Wed, 25 Feb 2009 17:34:51 +0100 |
parents | 0b38b64f62c7 |
children | 2667e3a145be |
line wrap: on
line source
// Compiler implementation of the D programming language // Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com // License for redistribution is by either the Artistic License // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <assert.h> #include <limits.h> #include <string> #include <cstdarg> #if __DMC__ #include <dos.h> #endif #if POSIX #include <errno.h> #elif _WIN32 #include <windows.h> #endif #include "mem.h" #include "root.h" #include "mars.h" #include "module.h" #include "mtype.h" #include "id.h" #include "cond.h" #include "expression.h" #include "lexer.h" #include "gen/logger.h" #include "gen/linker.h" #include "revisions.h" #include "gen/cl_options.h" #include "gen/cl_helpers.h" using namespace opts; static cl::opt<bool> forceBE("forcebe", cl::desc("Force big-endian"), cl::Hidden, cl::ZeroOrMore); static cl::opt<bool> noDefaultLib("nodefaultlib", cl::desc("Don't add a default library for linking implicitly"), cl::ZeroOrMore); static ArrayAdapter impPathsStore("I", global.params.imppath); static cl::list<std::string, ArrayAdapter> importPaths("I", cl::desc("Where to look for imports"), cl::value_desc("path"), cl::location(impPathsStore), cl::Prefix); static ArrayAdapter defaultLibStore("defaultlib", global.params.defaultlibnames); static cl::list<std::string, ArrayAdapter> defaultlibs("defaultlib", cl::desc("Set default libraries for non-debug build"), cl::value_desc("lib,..."), cl::location(defaultLibStore), cl::CommaSeparated); static ArrayAdapter debugLibStore("debuglib", global.params.debuglibnames); static cl::list<std::string, ArrayAdapter> debuglibs("debuglib", cl::desc("Set default libraries for debug build"), cl::value_desc("lib,..."), cl::location(debugLibStore), cl::CommaSeparated); void getenv_setargv(const char *envvar, int *pargc, char** *pargv); Global global; Global::Global() { mars_ext = "d"; sym_ext = "d"; hdr_ext = "di"; doc_ext = "html"; ddoc_ext = "ddoc"; // LDC ll_ext = "ll"; bc_ext = "bc"; s_ext = "s"; obj_ext = "o"; #if _WIN32 obj_ext_alt = "obj"; #endif copyright = "Copyright (c) 1999-2009 by Digital Mars and Tomas Lindquist Olsen"; written = "written by Walter Bright and Tomas Lindquist Olsen"; version = "v1.039"; ldc_version = LDC_REV; llvm_version = LLVM_REV; global.structalign = 8; // This should only be used as a global, so the other fields are // automatically initialized to zero when the program is loaded. // In particular, DO NOT zero-initialize .params here (like DMD // does) because command-line options initialize some of those // fields to non-zero defaults, and do so from constructors that // may run before this one. } char *Loc::toChars() const { OutBuffer buf; if (filename) { buf.printf("%s", filename); } if (linnum) buf.printf("(%d)", linnum); buf.writeByte(0); return (char *)buf.extractData(); } Loc::Loc(Module *mod, unsigned linnum) { this->linnum = linnum; this->filename = mod ? mod->srcfile->toChars() : NULL; } /************************************** * Print error message and exit. */ void error(Loc loc, const char *format, ...) { va_list ap; va_start(ap, format); verror(loc, format, ap); va_end( ap ); } void verror(Loc loc, const char *format, va_list ap) { if (!global.gag) { char *p = loc.toChars(); if (*p) fprintf(stdmsg, "%s: ", p); mem.free(p); fprintf(stdmsg, "Error: "); vfprintf(stdmsg, format, ap); fprintf(stdmsg, "\n"); fflush(stdmsg); } global.errors++; } /*************************************** * Call this after printing out fatal error messages to clean up and exit * the compiler. */ void fatal() { #if 0 halt(); #endif exit(EXIT_FAILURE); } /************************************** * Try to stop forgetting to remove the breakpoints from * release builds. */ void halt() { #ifdef DEBUG *(char*)0=0; #endif } extern void backend_init(); extern void backend_term(); void printVersion() { printf("LLVM D Compiler %s\nbased on DMD %s and %s\n%s\n%s\n", global.ldc_version, global.version, global.llvm_version, global.copyright, global.written); printf("D Language Documentation: http://www.digitalmars.com/d/1.0/index.html\n" "LDC Homepage: http://www.dsource.org/projects/ldc\n"); } // Helper function to handle -d-debug=* and -d-version=* static void processVersions(std::vector<std::string>& list, char* type, void (*setLevel)(unsigned), void (*addIdent)(char*)) { typedef std::vector<std::string>::iterator It; for(It I = list.begin(), E = list.end(); I != E; ++I) { const char* value = I->c_str(); if (isdigit(value[0])) { errno = 0; char* end; long level = strtol(value, &end, 10); if (*end || errno || level > INT_MAX) { error("Invalid %s level: %s", type, I->c_str()); } else { setLevel((unsigned)level); } } else { char* cstr = mem.strdup(value); if (Lexer::isValidIdentifier(cstr)) { addIdent(cstr); continue; } else { error("Invalid %s identifier or level: '%s'", type, I->c_str()); } } } } // Helper function to handle -of, -od, etc. static void initFromString(char*& dest, const cl::opt<std::string>& src) { dest = 0; if (src.getNumOccurrences() != 0) { if (src.empty()) error("Expected argument to '-%s'", src.ArgStr); dest = mem.strdup(src.c_str()); } } int main(int argc, char *argv[]) { int i; Array files; char *p, *ext; Module *m; int status = EXIT_SUCCESS; // Set default values #if _WIN32 char buf[MAX_PATH]; GetModuleFileName(NULL, buf, MAX_PATH); global.params.argv0 = buf; #else global.params.argv0 = argv[0]; #endif global.params.useSwitchError = 1; global.params.linkswitches = new Array(); global.params.libfiles = new Array(); global.params.objfiles = new Array(); global.params.ddocfiles = new Array(); global.params.is64bit = sizeof(void*) == 8 ? 1 : 0; uint16_t endiantest = 0xFF00; uint8_t endianres = ((uint8_t*)&endiantest)[0]; if (endianres == 0x00) global.params.isLE = true; else if (endianres == 0xFF) global.params.isLE = false; else { error("Endian test is broken"); fatal(); } // Predefine version identifiers #if IN_LLVM VersionCondition::addPredefinedGlobalIdent("LLVM"); VersionCondition::addPredefinedGlobalIdent("LDC"); #endif // setup default target os to be build os #if _WIN32 global.params.os = OSWindows; #elif linux global.params.os = OSLinux; #elif __APPLE__ global.params.os = OSMacOSX; #elif __FreeBSD__ global.params.os = OSFreeBSD; #elif defined (__SVR4) && defined (__sun) global.params.os = OSSolaris; #else #error Unsupported OS #endif /* linux */ assert(global.params.os != OSinvalid); //VersionCondition::addPredefinedGlobalIdent("D_Bits"); VersionCondition::addPredefinedGlobalIdent("all"); //#if _WIN32 // inifile(global.params.argv0, "ldc.ini"); //#elif POSIX inifile(global.params.argv0, "ldc.conf"); //#else //#error //#endif getenv_setargv("DFLAGS", &argc, &argv); #if 0 for (i = 0; i < argc; i++) { printf("argv[%d] = '%s'\n", i, argv[i]); } #endif cl::SetVersionPrinter(&printVersion); cl::ParseCommandLineOptions(argc, argv, "LLVM-based D Compiler\n"); global.params.optimize = (global.params.optimizeLevel >= 0); // Negated options global.params.link = !compileOnly; global.params.obj = !dontWriteObj; global.params.useInlineAsm = !noAsm; // String options: std::string --> char* initFromString(global.params.objname, objectFile); initFromString(global.params.objdir, objectDir); initFromString(global.params.docdir, ddocDir); initFromString(global.params.docname, ddocFile); global.params.doDocComments |= global.params.docdir || global.params.docname; #ifdef _DH initFromString(global.params.hdrdir, hdrDir); initFromString(global.params.hdrname, hdrFile); global.params.doHdrGeneration |= global.params.hdrdir || global.params.hdrname; #endif processVersions(debugArgs, "debug", DebugCondition::setGlobalLevel, DebugCondition::addGlobalIdent); processVersions(versions, "version", VersionCondition::setGlobalLevel, VersionCondition::addGlobalIdent); global.params.output_o = opts::output_o == cl::BOU_UNSET ? OUTPUTFLAGdefault : opts::output_o == cl::BOU_TRUE ? OUTPUTFLAGset : OUTPUTFLAGno; global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno; global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno; global.params.output_s = opts::output_s ? OUTPUTFLAGset : OUTPUTFLAGno; if (global.params.run || !runargs.empty()) { // FIXME: how to properly detect the presence of a PositionalEatsArgs // option without parameters? We want to emit an error in that case... // You'd think getNumOccurrences would do it, but it just returns the // number of parameters) // NOTE: Hacked around it by detecting -run in getenv_setargv(), where // we're looking for it anyway, and pre-setting the flag... global.params.run = true; if (!runargs.empty()) { files.push(mem.strdup(runargs[0].c_str())); } else { global.params.run = false; error("Expected at least one argument to '-run'\n"); } } if (mArch) global.params.llvmArch = mArch->Name; files.reserve(fileList.size()); typedef std::vector<std::string>::iterator It; for(It I = fileList.begin(), E = fileList.end(); I != E; ++I) if (!I->empty()) files.push(mem.strdup(I->c_str())); if (global.errors) { fatal(); } if (files.dim == 0) { cl::PrintHelpMessage(); return EXIT_FAILURE; } Array* libs; if (global.params.symdebug) libs = global.params.debuglibnames; else libs = global.params.defaultlibnames; if (libs) { for (int i = 0; i < libs->dim; i++) { char *arg = (char *)mem.malloc(64); strcpy(arg, "-l"); strncat(arg, (char *)libs->data[i], 64); global.params.linkswitches->push(arg); } } else if (!noDefaultLib) { char *arg; arg = (char *)mem.malloc(64); strcpy(arg, "-lldc-runtime"); global.params.linkswitches->push(arg); arg = (char *)mem.malloc(64); strcpy(arg, "-ltango-cc-tango"); global.params.linkswitches->push(arg); arg = (char *)mem.malloc(64); strcpy(arg, "-ltango-gc-basic"); global.params.linkswitches->push(arg); // pass the runtime again to resolve issues // with linking order arg = (char *)mem.malloc(64); strcpy(arg, "-lldc-runtime"); global.params.linkswitches->push(arg); } if (global.params.run) quiet = 1; if (global.params.useUnitTests) global.params.useAssert = 1; // LDC output determination // if we don't link, autodetect target from extension if(!global.params.link && global.params.objname) { ext = FileName::ext(global.params.objname); bool autofound = false; if (!ext) { // keep things as they are } else if (strcmp(ext, global.ll_ext) == 0) { global.params.output_ll = OUTPUTFLAGset; autofound = true; } else if (strcmp(ext, global.bc_ext) == 0) { global.params.output_bc = OUTPUTFLAGset; autofound = true; } else if (strcmp(ext, global.s_ext) == 0) { global.params.output_s = OUTPUTFLAGset; autofound = true; } else if (strcmp(ext, global.obj_ext) == 0) { global.params.output_o = OUTPUTFLAGset; autofound = true; } else { // append dot, so forceExt won't change existing name even if it contains dots size_t len = strlen(global.params.objname); size_t extlen = strlen("."); char* s = (char *)mem.malloc(len + 1 + extlen + 1); memcpy(s, global.params.objname, len); s[len] = '.'; s[len+1+extlen] = 0; global.params.objname = s; } if(autofound && global.params.output_o == OUTPUTFLAGdefault) global.params.output_o = OUTPUTFLAGno; } // only link if possible if (!global.params.obj || !global.params.output_o) global.params.link = 0; if (global.params.link) { global.params.exefile = global.params.objname; if (files.dim > 1) global.params.objname = NULL; } else if (global.params.run) { error("flags conflict with -run"); fatal(); } else { if (global.params.objname && files.dim > 1) { error("multiple source files, but only one .obj name"); fatal(); } } bool allowForceEndianness = false; if (global.params.llvmArch == 0) { #if defined(__x86_64__) || defined(_M_X64) global.params.llvmArch = "x86-64"; #elif defined(__i386__) || defined(_M_IX86) global.params.llvmArch = "x86"; #elif defined(__ppc__) || defined(_M_PPC) if (global.params.is64bit) global.params.llvmArch = "ppc64"; else global.params.llvmArch = "ppc32"; #elif defined(__arm__) global.params.llvmArch = "arm"; #elif defined(__thumb__) global.params.llvmArch = "thumb"; #else #error #endif } if (strcmp(global.params.llvmArch,"x86")==0) { VersionCondition::addPredefinedGlobalIdent("X86"); global.params.isLE = true; global.params.is64bit = false; global.params.cpu = ARCHx86; if (global.params.useInlineAsm) { VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86"); } } else if (strcmp(global.params.llvmArch,"x86-64")==0) { VersionCondition::addPredefinedGlobalIdent("X86_64"); global.params.isLE = true; global.params.is64bit = true; global.params.cpu = ARCHx86_64; if (global.params.useInlineAsm) { VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86_64"); } } else if (strcmp(global.params.llvmArch,"ppc32")==0) { VersionCondition::addPredefinedGlobalIdent("PPC"); global.params.isLE = false; global.params.is64bit = false; global.params.cpu = ARCHppc; } else if (strcmp(global.params.llvmArch,"ppc64")==0) { VersionCondition::addPredefinedGlobalIdent("PPC64"); global.params.isLE = false; global.params.is64bit = true; global.params.cpu = ARCHppc_64; } else if (strcmp(global.params.llvmArch,"arm")==0) { VersionCondition::addPredefinedGlobalIdent("ARM"); global.params.isLE = true; global.params.is64bit = false; global.params.cpu = ARCHarm; } else if (strcmp(global.params.llvmArch,"thumb")==0) { VersionCondition::addPredefinedGlobalIdent("Thumb"); global.params.isLE = true; global.params.is64bit = false; global.params.cpu = ARCHthumb; } else { error("invalid cpu architecture specified: %s", global.params.llvmArch); } assert(global.params.cpu != ARCHinvalid); if (allowForceEndianness && forceBE) { VersionCondition::addPredefinedGlobalIdent("BigEndian"); global.params.isLE = false; } else if (global.params.isLE) { VersionCondition::addPredefinedGlobalIdent("LittleEndian"); } else { VersionCondition::addPredefinedGlobalIdent("BigEndian"); } if (global.params.is64bit) { VersionCondition::addPredefinedGlobalIdent("LLVM64"); } // setup version idents and tt_os for chosen target os switch(global.params.os) { case OSWindows: // TODO Win64 stuff! VersionCondition::addPredefinedGlobalIdent("Windows"); VersionCondition::addPredefinedGlobalIdent("Win32"); VersionCondition::addPredefinedGlobalIdent("mingw32"); break; case OSLinux: VersionCondition::addPredefinedGlobalIdent("linux"); VersionCondition::addPredefinedGlobalIdent("Posix"); break; case OSMacOSX: VersionCondition::addPredefinedGlobalIdent("OSX"); VersionCondition::addPredefinedGlobalIdent("darwin"); VersionCondition::addPredefinedGlobalIdent("Posix"); break; case OSFreeBSD: VersionCondition::addPredefinedGlobalIdent("freebsd"); VersionCondition::addPredefinedGlobalIdent("Posix"); break; case OSSolaris: VersionCondition::addPredefinedGlobalIdent("solaris"); VersionCondition::addPredefinedGlobalIdent("Posix"); break; default: assert(false && "Target OS not supported"); } if (!global.params.targetTriple) global.params.targetTriple = DEFAULT_TARGET_TRIPLE; Logger::println("Target triple: %s", global.params.targetTriple); // build a minimal data layout so llvm can find the target global.params.dataLayout = global.params.isLE ? (char*)(global.params.is64bit ? "e-p:64:64" : "e-p:32:32") : (char*)(global.params.is64bit ? "E-p:64:64" : "E-p:32:32"); Logger::println("Layout: %s", global.params.dataLayout); // added in 1.039 if (global.params.doDocComments) VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); // Initialization Type::init(); Id::initialize(); Module::init(); initPrecedence(); backend_init(); //printf("%d source files\n",files.dim); // Build import search path if (global.params.imppath) { for (i = 0; i < global.params.imppath->dim; i++) { char *path = (char *)global.params.imppath->data[i]; Array *a = FileName::splitPath(path); if (a) { if (!global.path) global.path = new Array(); global.path->append(a); } } } // Build string import search path if (global.params.fileImppath) { for (i = 0; i < global.params.fileImppath->dim; i++) { char *path = (char *)global.params.fileImppath->data[i]; Array *a = FileName::splitPath(path); if (a) { if (!global.filePath) global.filePath = new Array(); global.filePath->append(a); } } } // Create Modules Array modules; modules.reserve(files.dim); for (i = 0; i < files.dim; i++) { Identifier *id; char *ext; char *name; p = (char *) files.data[i]; p = FileName::name(p); // strip path ext = FileName::ext(p); if (ext) { #if POSIX if (strcmp(ext, global.obj_ext) == 0 || strcmp(ext, global.bc_ext) == 0) #else if (stricmp(ext, global.obj_ext) == 0 || stricmp(ext, global.bc_ext) == 0) #endif { global.params.objfiles->push(files.data[i]); continue; } #if POSIX if (strcmp(ext, "a") == 0) #elif __MINGW32__ if (stricmp(ext, "a") == 0) #else if (stricmp(ext, "lib") == 0) #endif { global.params.libfiles->push(files.data[i]); continue; } if (strcmp(ext, global.ddoc_ext) == 0) { global.params.ddocfiles->push(files.data[i]); continue; } #if !POSIX if (stricmp(ext, "res") == 0) { global.params.resfile = (char *)files.data[i]; continue; } if (stricmp(ext, "def") == 0) { global.params.deffile = (char *)files.data[i]; continue; } if (stricmp(ext, "exe") == 0) { global.params.exefile = (char *)files.data[i]; continue; } #endif if (stricmp(ext, global.mars_ext) == 0 || stricmp(ext, global.hdr_ext) == 0 || stricmp(ext, "htm") == 0 || stricmp(ext, "html") == 0 || stricmp(ext, "xhtml") == 0) { ext--; // skip onto '.' assert(*ext == '.'); name = (char *)mem.malloc((ext - p) + 1); memcpy(name, p, ext - p); name[ext - p] = 0; // strip extension if (name[0] == 0 || strcmp(name, "..") == 0 || strcmp(name, ".") == 0) { Linvalid: error("invalid file name '%s'", (char *)files.data[i]); fatal(); } } else { error("unrecognized file extension %s\n", ext); fatal(); } } else { name = p; if (!*name) goto Linvalid; } id = new Identifier(name, 0); m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration); modules.push(m); } // Read files, parse them for (i = 0; i < modules.dim; i++) { m = (Module *)modules.data[i]; if (global.params.verbose) printf("parse %s\n", m->toChars()); if (!Module::rootModule) Module::rootModule = m; m->importedFrom = m; m->read(0); m->parse(); m->buildTargetFiles(); m->deleteObjFile(); if (m->isDocFile) { m->gendocfile(); // Remove m from list of modules modules.remove(i); i--; } } if (global.errors) fatal(); #ifdef _DH if (global.params.doHdrGeneration) { /* Generate 'header' import files. * Since 'header' import files must be independent of command * line switches and what else is imported, they are generated * before any semantic analysis. */ for (i = 0; i < modules.dim; i++) { m = (Module *)modules.data[i]; if (global.params.verbose) printf("import %s\n", m->toChars()); m->genhdrfile(); } } if (global.errors) fatal(); #endif // Do semantic analysis for (i = 0; i < modules.dim; i++) { m = (Module *)modules.data[i]; if (global.params.verbose) printf("semantic %s\n", m->toChars()); m->semantic(); } if (global.errors) fatal(); // Do pass 2 semantic analysis for (i = 0; i < modules.dim; i++) { m = (Module *)modules.data[i]; if (global.params.verbose) printf("semantic2 %s\n", m->toChars()); m->semantic2(); } if (global.errors) fatal(); // Do pass 3 semantic analysis for (i = 0; i < modules.dim; i++) { m = (Module *)modules.data[i]; if (global.params.verbose) printf("semantic3 %s\n", m->toChars()); m->semantic3(); } if (global.errors) fatal(); #if !IN_LLVM // Scan for functions to inline if (global.params.useInline) { /* The problem with useArrayBounds and useAssert is that the * module being linked to may not have generated them, so if * we inline functions from those modules, the symbols for them will * not be found at link time. */ if (!global.params.useArrayBounds && !global.params.useAssert) { #endif // Do pass 3 semantic analysis on all imported modules, // since otherwise functions in them cannot be inlined for (i = 0; i < Module::amodules.dim; i++) { m = (Module *)Module::amodules.data[i]; if (global.params.verbose) printf("semantic3 %s\n", m->toChars()); m->semantic3(); } if (global.errors) fatal(); #if !IN_LLVM } for (i = 0; i < modules.dim; i++) { m = (Module *)modules.data[i]; if (global.params.verbose) printf("inline scan %s\n", m->toChars()); m->inlineScan(); } } #endif if (global.errors) fatal(); // Generate output files for (i = 0; i < modules.dim; i++) { m = (Module *)modules.data[i]; if (global.params.verbose) printf("code %s\n", m->toChars()); if (global.params.obj) { m->genobjfile(0); global.params.objfiles->push(m->objfile->name->str); } if (global.errors) m->deleteObjFile(); else { if (global.params.doDocComments) m->gendocfile(); } } backend_term(); if (global.errors) fatal(); if (!global.params.objfiles->dim) { if (global.params.link) error("no object files to link"); } else { if (global.params.link) //status = runLINK(); linkObjToExecutable(global.params.argv0); if (global.params.run) { if (!status) { status = runExectuable(); /* Delete .obj files and .exe file */ for (i = 0; i < modules.dim; i++) { m = (Module *)modules.data[i]; m->deleteObjFile(); } deleteExecutable(); } } } return status; } /*********************************** * Parse and append contents of environment variable envvar * to argc and argv[]. * The string is separated into arguments, processing \ and ". */ void getenv_setargv(const char *envvar, int *pargc, char** *pargv) { char *env; char *p; Array *argv; int argc; int wildcard; // do wildcard expansion int instring; int slash; char c; int j; env = getenv(envvar); if (!env) return; env = mem.strdup(env); // create our own writable copy argc = *pargc; argv = new Array(); argv->setDim(argc); int argc_left = 0; for (int i = 0; i < argc; i++) { if (!strcmp((*pargv)[i], "-run") || !strcmp((*pargv)[i], "--run")) { // HACK: set flag to indicate we saw '-run' here global.params.run = true; // Don't eat -run yet so the program arguments don't get changed argc_left = argc - i; argc = i; *pargv = &(*pargv)[i]; argv->setDim(i); break; } else { argv->data[i] = (void *)(*pargv)[i]; } } // HACK to stop required values from command line being drawn from DFLAGS argv->push((char*)""); argc++; j = 1; // leave argv[0] alone while (1) { wildcard = 1; switch (*env) { case ' ': case '\t': env++; break; case 0: goto Ldone; case '"': wildcard = 0; default: argv->push(env); // append //argv->insert(j, env); // insert at position j j++; argc++; p = env; slash = 0; instring = 0; c = 0; while (1) { c = *env++; switch (c) { case '"': p -= (slash >> 1); if (slash & 1) { p--; goto Laddc; } instring ^= 1; slash = 0; continue; case ' ': case '\t': if (instring) goto Laddc; *p = 0; //if (wildcard) //wildcardexpand(); // not implemented break; case '\\': slash++; *p++ = c; continue; case 0: *p = 0; //if (wildcard) //wildcardexpand(); // not implemented goto Ldone; default: Laddc: slash = 0; *p++ = c; continue; } break; } } } Ldone: assert(argc == argv->dim); argv->reserve(argc_left); for (int i = 0; i < argc_left; i++) argv->data[argc++] = (void *)(*pargv)[i]; *pargc = argc; *pargv = (char **)argv->data; }