# # # The Nimrod Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # This module handles the parsing of command line arguments. # We do this here before the 'import' statement so 'defined' does not get # confused with 'TGCMode.gcGenerational' etc. template bootSwitch(name, expr, userString: expr): expr = # Helper to build boot constants, for debugging you can 'echo' the else part. const name = if expr: " " & userString else: "" bootSwitch(usedRelease, defined(release), "-d:release") bootSwitch(usedGnuReadline, defined(useGnuReadline), "-d:useGnuReadline") bootSwitch(usedNoCaas, defined(noCaas), "-d:noCaas") bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm") bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep") bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational") bootSwitch(usedNoGC, defined(nogc), "--gc:none") import os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists, wordrecg, parseutils, babelcmd, idents # but some have deps to imported modules. Yay. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") bootSwitch(usedAvoidTimeMachine, noTimeMachine, "-d:avoidTimeMachine") bootSwitch(usedNativeStacktrace, defined(nativeStackTrace) and nativeStackTraceSupported, "-d:nativeStackTrace") bootSwitch(usedFFI, hasFFI, "-d:useFFI") proc writeCommandLineUsage*() type TCmdLinePass* = enum passCmd1, # first pass over the command line passCmd2, # second pass over the command line passPP # preprocessor called ProcessCommand() proc processCommand*(switch: string, pass: TCmdLinePass) proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) # implementation const HelpMessage = "Nimrod Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" & "Copyright (c) 2006-2014 by Andreas Rumpf\n" const Usage = slurp"doc/basicopt.txt".replace("//", "") AdvancedUsage = slurp"doc/advopt.txt".replace("//", "") proc getCommandLineDesc(): string = result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name, CPU[platform.hostCPU].name]) & Usage proc helpOnError(pass: TCmdLinePass) = if pass == passCmd1: msgWriteln(getCommandLineDesc()) quit(0) proc writeAdvancedUsage(pass: TCmdLinePass) = if pass == passCmd1: msgWriteln(`%`(HelpMessage, [VersionAsString, platform.OS[platform.hostOS].name, CPU[platform.hostCPU].name]) & AdvancedUsage) quit(0) proc writeVersionInfo(pass: TCmdLinePass) = if pass == passCmd1: msgWriteln(`%`(HelpMessage, [VersionAsString, platform.OS[platform.hostOS].name, CPU[platform.hostCPU].name])) const gitHash = gorge("git log -n 1 --format=%H") if gitHash.strip.len == 40: msgWriteln("git hash: " & gitHash) msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine & usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas & usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedNoGC) quit(0) var helpWritten: bool proc writeCommandLineUsage() = if not helpWritten: msgWriteln(getCommandLineDesc()) helpWritten = true proc addPrefix(switch: string): string = if len(switch) == 1: result = "-" & switch else: result = "--" & switch proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) = if switch == " ": localError(info, errInvalidCmdLineOption, "-") else: localError(info, errInvalidCmdLineOption, addPrefix(switch)) proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass, info: TLineInfo) = cmd = "" var i = 0 if i < len(switch) and switch[i] == '-': inc(i) if i < len(switch) and switch[i] == '-': inc(i) while i < len(switch): case switch[i] of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i]) else: break inc(i) if i >= len(switch): arg = "" elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1) else: invalidCmdLineOption(pass, switch, info) proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case whichKeyword(arg) of wOn: gOptions = gOptions + op of wOff: gOptions = gOptions - op else: localError(info, errOnOrOffExpectedButXFound, arg) proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case whichKeyword(arg) of wOn: gGlobalOptions = gGlobalOptions + op of wOff: gGlobalOptions = gGlobalOptions - op else: localError(info, errOnOrOffExpectedButXFound, arg) proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch)) proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch)) proc processSpecificNote(arg: string, sta
/* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
 * See LICENSE file for license details.
 */

#define TAGS \
const char *tags[] = { "dev", "work", "net", "fnord", NULL };

#define DEFMODE			dotile		/* dofloat */
#define FLOATSYMBOL		"><>"
#define TILESYMBOL		"[]="

#define FONT			"-*-terminus-medium-r-*-*-14-*-*-*-*-*-*-*"
#define NORMBGCOLOR		"#333333"
#define NORMFGCOLOR		"#cccccc"
#define SELBGCOLOR		"#336699"
#define SELFGCOLOR		"#dddddd"
#define STATUSBGCOLOR		"#222222"
#define STATUSFGCOLOR		"#99ccff"

#define MASTER			600		/* per thousand */
#define MODKEY			Mod1Mask
#define SNAP			40		/* pixel */

#define KEYS \
static Key key[] = { \
	/* modifier			key		function		argument */ \
	{ MODKEY|ShiftMask,		XK_Return,	spawn, \
		{ .cmd = "exec uxterm -bg black -fg '#eeeeee' -cr '#eeeeee' +sb -fn '"FONT"'" } }, \
	{ MODKEY,			XK_p,		spawn, \
		{ .cmd = "exe=\"$(lsx `echo $PATH | sed 's/:/ /g'` | sort -u " \
			" | dmenu -font '"FONT"' -normbg '"NORMBGCOLOR"' -normfg '"NORMFGCOLOR"' " \
			"-selbg '"SELBGCOLOR"' -selfg '"SELFGCOLOR"')\" && exec $exe" } }, \
	{ MODKEY,			XK_j,		focusnext,	{ 0 } }, \
	{ MODKEY,			XK_k,		focusprev,	{ 0 } }, \
	{ MODKEY,			XK_Return,	zoom,		{ 0 } }, \
	{ MODKEY,			XK_g,		resizemaster,	{ .i = 15 } }, \
	{ MODKEY,			XK_s,		resizemaster,	{ .i = -15 } }, \
	{ MODKEY|ShiftMask,		XK_0,		tag,		{ .i = -1 } }, \
	{ MODKEY|ShiftMask,		XK_1,		tag,		{ .i = 0 } }, \
	{ MODKEY|ShiftMask,		XK_2,		tag,		{ .i = 1 } }, \
	{ MODKEY|ShiftMask,		XK_3,		tag,		{ .i = 2 } }, \
	{ MODKEY|ShiftMask,		XK_4,		tag,		{ .i = 3 } }, \
	{ MODKEY|ControlMask|ShiftMask,	XK_1,		toggletag,	{ .i = 0 } }, \
	{ MODKEY|ControlMask|ShiftMask,	XK_2,		toggletag,	{ .i = 1 } }, \
	{ MODKEY|ControlMask|ShiftMask,	XK_3,		toggletag,	{ .i = 2 } }, \
	{ MODKEY|ControlMask|ShiftMask,	XK_4,		toggletag,	{ .i = 3 } }, \
	{ MODKEY|ShiftMask,		XK_c,		killclient,	{ 0 } }, \
	{ MODKEY,			XK_space,	togglemode,	{ 0 } }, \
	{ MODKEY|ShiftMask,		XK_space,	togglefloat,	{ 0 } }, \
	{ MODKEY,			XK_0,		view,		{ .i = -1 } }, \
	{ MODKEY,			XK_1,		view,		{ .i = 0 } }, \
	{ MODKEY,			XK_2,		view,		{ .i = 1 } }, \
	{ MODKEY,			XK_3,		view,		{ .i = 2 } }, \
	{ MODKEY,			XK_4,		view,		{ .i = 3 } }, \
	{ MODKEY|ControlMask,		XK_1,		toggleview,	{ .i = 0 } }, \
	{ MODKEY|ControlMask,		XK_2,		toggleview,	{ .i = 1 } }, \
	{ MODKEY|ControlMask,		XK_3,		toggleview,	{ .i = 2 } }, \
	{ MODKEY|ControlMask,		XK_4,		toggleview,	{ .i = 3 } }, \
	{ MODKEY|ShiftMask,		XK_q,		quit,		{ 0 } }, \
};

#define RULES \
static Rule rule[] = { \
	/* class:instance:title regex	tags regex	isfloat */ \
	{ "Firefox.*",			"net",		False }, \
	{ "Gimp.*",			NULL,		True }, \
	{ "MPlayer.*",			NULL,		True }, \
	{ "Acroread.*",			NULL,		True }, \
};
ass, info) of "implicitstatic": processOnOffSwitch({optImplicitStatic}, arg, pass, info) of "patterns": processOnOffSwitch({optPatterns}, arg, pass, info) of "opt": expectArg(switch, arg, pass, info) case arg.normalize of "speed": incl(gOptions, optOptimizeSpeed) excl(gOptions, optOptimizeSize) of "size": excl(gOptions, optOptimizeSpeed) incl(gOptions, optOptimizeSize) of "none": excl(gOptions, optOptimizeSpeed) excl(gOptions, optOptimizeSize) else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg) of "app": expectArg(switch, arg, pass, info) case arg.normalize of "gui": incl(gGlobalOptions, optGenGuiApp) defineSymbol("executable") defineSymbol("guiapp") of "console": excl(gGlobalOptions, optGenGuiApp) defineSymbol("executable") defineSymbol("consoleapp") of "lib": incl(gGlobalOptions, optGenDynLib) excl(gGlobalOptions, optGenGuiApp) defineSymbol("library") defineSymbol("dll") of "staticlib": incl(gGlobalOptions, optGenStaticLib) excl(gGlobalOptions, optGenGuiApp) defineSymbol("library") defineSymbol("staticlib") else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg) of "passc", "t": expectArg(switch, arg, pass, info) if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg) of "passl", "l": expectArg(switch, arg, pass, info) if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg) of "cincludes": expectArg(switch, arg, pass, info) if pass in {passCmd2, passPP}: cIncludes.add arg.processPath of "clibdir": expectArg(switch, arg, pass, info) if pass in {passCmd2, passPP}: cLibs.add arg.processPath of "clib": expectArg(switch, arg, pass, info) if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath of "header": headerFile = arg incl(gGlobalOptions, optGenIndex) of "index": processOnOffSwitchG({optGenIndex}, arg, pass, info) of "import": expectArg(switch, arg, pass, info) if pass in {passCmd2, passPP}: implicitImports.add arg of "include": expectArg(switch, arg, pass, info) if pass in {passCmd2, passPP}: implicitIncludes.add arg of "listcmd": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optListCmd) of "genmapping": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optGenMapping) of "os": expectArg(switch, arg, pass, info) if pass in {passCmd1, passPP}: theOS = platform.nameToOS(arg) if theOS == osNone: localError(info, errUnknownOS, arg) elif theOS != platform.hostOS: setTarget(theOS, targetCPU) condsyms.initDefines() of "cpu": expectArg(switch, arg, pass, info) if pass in {passCmd1, passPP}: cpu = platform.nameToCPU(arg) if cpu == cpuNone: localError(info, errUnknownCPU, arg) elif cpu != platform.hostCPU: setTarget(targetOS, cpu) condsyms.initDefines() of "run", "r": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optRun) of "verbosity": expectArg(switch, arg, pass, info) gVerbosity = parseInt(arg) of "parallelbuild": expectArg(switch, arg, pass, info) gNumberOfProcessors = parseInt(arg) of "version", "v": expectNoArg(switch, arg, pass, info) writeVersionInfo(pass) of "advanced": expectNoArg(switch, arg, pass, info) writeAdvancedUsage(pass) of "help", "h": expectNoArg(switch, arg, pass, info) helpOnError(pass) of "symbolfiles": processOnOffSwitchG({optSymbolFiles}, arg, pass, info) of "skipcfg": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optSkipConfigFile) of "skipprojcfg": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optSkipProjConfigFile) of "skipusercfg": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optSkipUserConfigFile) of "skipparentcfg": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optSkipParentConfigFiles) of "genscript": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optGenScript) of "lib": expectArg(switch, arg, pass, info) libpath = processPath(arg, notRelativeToProj=true) of "putenv": expectArg(switch, arg, pass, info) splitSwitch(arg, key, val, pass, info) os.putEnv(key, val) of "cc": expectArg(switch, arg, pass, info) setCC(arg) of "track": expectArg(switch, arg, pass, info) track(arg, info) of "trackdirty": expectArg(switch, arg, pass, info) trackDirty(arg, info) of "suggest": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optSuggest) of "def": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optDef) of "eval": expectArg(switch, arg, pass, info) gEvalExpr = arg of "context": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optContext) of "usages": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optUsages) of "stdout": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optStdout) of "listfullpaths": expectNoArg(switch, arg, pass, info) gListFullPaths = true of "dynliboverride": dynlibOverride(switch, arg, pass, info) of "cs": expectArg(switch, arg, pass, info) case arg of "partial": idents.firstCharIsCS = true of "none": idents.firstCharIsCS = false else: localError(info, errGenerated, "'partial' or 'none' expected, but found " & arg) else: if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg) else: invalidCmdLineOption(pass, switch, info) proc processCommand(switch: string, pass: TCmdLinePass) = var cmd, arg: string splitSwitch(switch, cmd, arg, pass, gCmdLineInfo) processSwitch(cmd, arg, pass, gCmdLineInfo)