diff options
-rwxr-xr-x | lib/pure/os.nim | 92 | ||||
-rwxr-xr-x | lib/system.nim | 8 | ||||
-rwxr-xr-x | rod/commands.nim | 7 | ||||
-rwxr-xr-x | rod/crc.nim | 13 | ||||
-rwxr-xr-x | rod/extccomp.nim | 65 | ||||
-rwxr-xr-x | rod/pragmas.nim | 2 | ||||
-rwxr-xr-x | web/news.txt | 12 |
7 files changed, 145 insertions, 54 deletions
diff --git a/lib/pure/os.nim b/lib/pure/os.nim index f807c39f5..129774f6e 100755 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -926,28 +926,90 @@ proc createDir*(dir: string) = rawCreateDir(dir) proc parseCmdLine*(c: string): seq[string] = - ## Splits a command line into several components; components are separated by - ## whitespace unless the whitespace occurs within ``"`` or ``'`` quotes. + ## Splits a command line into several components; ## This proc is only occassionally useful, better use the `parseopt` module. + ## + ## On Windows, it uses the following parsing rules + ## (see http://msdn.microsoft.com/en-us/library/17w5ykft.aspx): + ## + ## * Arguments are delimited by white space, which is either a space or a tab. + ## * The caret character (^) is not recognized as an escape character or + ## delimiter. The character is handled completely by the command-line parser + ## in the operating system before being passed to the argv array in the + ## program. + ## * A string surrounded by double quotation marks ("string") is interpreted + ## as a single argument, regardless of white space contained within. A + ## quoted string can be embedded in an argument. + ## * A double quotation mark preceded by a backslash (\") is interpreted as a + ## literal double quotation mark character ("). + ## * Backslashes are interpreted literally, unless they immediately precede + ## a double quotation mark. + ## * If an even number of backslashes is followed by a double quotation mark, + ## one backslash is placed in the argv array for every pair of backslashes, + ## and the double quotation mark is interpreted as a string delimiter. + ## * If an odd number of backslashes is followed by a double quotation mark, + ## one backslash is placed in the argv array for every pair of backslashes, + ## and the double quotation mark is "escaped" by the remaining backslash, + ## causing a literal double quotation mark (") to be placed in argv. + ## + ## On Posix systems, it uses the following parsing rules: + ## components are separated by + ## whitespace unless the whitespace occurs within ``"`` or ``'`` quotes. result = @[] var i = 0 var a = "" while true: setLen(a, 0) - while c[i] >= '\1' and c[i] <= ' ': inc(i) # skip whitespace - case c[i] - of '\'', '\"': - var delim = c[i] - inc(i) # skip ' or " - while c[i] != '\0' and c[i] != delim: - add a, c[i] - inc(i) - if c[i] != '\0': inc(i) - of '\0': break + while c[i] == ' ' or c[i] == '\t': inc(i) + when defined(windows): + # parse a single argument according to the above rules: + var inQuote = false + while true: + case c[i] + of '\0': break + of '\\': + var j = i + while c[j] == '\\': inc(j) + if c[j] == '"': + for k in 0..(j-i) div 2: a.add('\\') + if (j-i) mod 2 == 0: + i = j + else: + a.add('"') + i = j+1 + else: + a.add(c[i]) + inc(i) + of '"': + inc(i) + if not inQuote: inQuote = true + elif c[i] == '"': + a.add(c[i]) + inc(i) + else: + inQuote = false + break + of ' ', '\t': + if not inQuote: break + a.add(c[i]) + inc(i) + else: + a.add(c[i]) + inc(i) else: - while c[i] > ' ': - add(a, c[i]) - inc(i) + case c[i] + of '\'', '\"': + var delim = c[i] + inc(i) # skip ' or " + while c[i] != '\0' and c[i] != delim: + add a, c[i] + inc(i) + if c[i] != '\0': inc(i) + of '\0': break + else: + while c[i] > ' ': + add(a, c[i]) + inc(i) add(result, a) type diff --git a/lib/system.nim b/lib/system.nim index 66c5b4dfd..a83812ed0 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -233,9 +233,9 @@ type ## that is too small to be represented as ## a normal number EFloatInexact* {.compilerproc.} = - object of EFloatingPoint ## Inexact. Operation produces a result that cannot - ## be represented with infinite precision -- - ## for example, 2.0 / 3.0, log(1.1) + object of EFloatingPoint ## Inexact. Operation produces a result + ## that cannot be represented with infinite + ## precision -- for example, 2.0 / 3.0, log(1.1) ## NOTE: Nimrod currently does not detect these! TResult* = enum Failure, Success @@ -962,7 +962,7 @@ proc `$` *(x: Cstring): string {.magic: "CStrToStr", noSideEffect.} proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.} ## The stingify operator for a string argument. Returns `x` ## as it is. This operator is useful for generic code, so - ## that ``$expr`` also works if ``expr`` is already a string. + ## that ``$expr`` also works if ``expr`` already is a string. proc `$` *[T](x: ordinal[T]): string {.magic: "EnumToStr", noSideEffect.} ## The stingify operator for an enumeration argument. This works for diff --git a/rod/commands.nim b/rod/commands.nim index 01b015b53..289f9c68e 100755 --- a/rod/commands.nim +++ b/rod/commands.nim @@ -216,11 +216,10 @@ proc processPath(path: string): string = result = UnixToNativePath(path % ["nimrod", getPrefixDir(), "lib", libpath]) proc processCompile(filename: string) = - var found, trunc: string - found = findFile(filename) + var found = findFile(filename) if found == "": found = filename - trunc = changeFileExt(found, "") - extccomp.addExternalFileToCompile(trunc) + var trunc = changeFileExt(found, "") + extccomp.addExternalFileToCompile(found) extccomp.addFileToLink(completeCFilePath(trunc, false)) proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) = diff --git a/rod/crc.nim b/rod/crc.nim index e66ce30fb..b397d5382 100755 --- a/rod/crc.nim +++ b/rod/crc.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2008 Andreas Rumpf +# (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -90,8 +90,7 @@ type PByteArray = ref TByteArray proc crcFromBuf(buf: Pointer, length: int): TCrc32 = - var p: PByteArray - p = cast[PByteArray](buf) + var p = cast[PByteArray](buf) result = InitCrc32 for i in countup(0, length - 1): result = updateCrc32(p[i], result) @@ -117,10 +116,12 @@ proc crcFromFile(filename: string): TCrc32 = const base = int32(65521) # largest prime smaller than 65536 - #NMAX = 5552; original code with unsigned 32 bit integer - # NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 + # NMAX = 5552; original code with unsigned 32 bit integer + # NMAX is the largest n + # such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 nmax = 3854 # code with signed 32 bit integer - # NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^31-1 + # NMAX is the largest n such that + # 255n(n+1)/2 + (n+1)(BASE-1) <= 2^31-1 # The penalty is the time loss in the extra MOD-calls. proc updateAdler32(adler: int32, buf: pointer, length: int): int32 = diff --git a/rod/extccomp.nim b/rod/extccomp.nim index 8d70bf16d..6ca816eb1 100755 --- a/rod/extccomp.nim +++ b/rod/extccomp.nim @@ -11,7 +11,7 @@ # some things are read in from the configuration file import - lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs + lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc type TSystemCC* = enum @@ -299,12 +299,30 @@ proc toObjFile(filenameWithoutExt: string): string = proc addFileToCompile(filename: string) = appendStr(toCompile, filename) +proc externalFileChanged(filename: string): bool = + var crcFile = toGeneratedFile(filename, "crc") + var currentCrc = int(crcFromFile(filename)) + var f: TFile + if open(f, crcFile, fmRead): + var line = f.readLine() + if isNil(line) or line.len == 0: line = "0" + close(f) + var oldCrc = parseInt(line) + result = oldCrc != currentCrc + else: + result = true + if result: + if open(f, crcFile, fmWrite): + f.writeln($currentCrc) + close(f) + proc addExternalFileToCompile(filename: string) = - appendStr(externalToCompile, filename) + if optForceFullMake in gGlobalOptions or externalFileChanged(filename): + appendStr(externalToCompile, changeFileExt(filename, "")) proc addFileToLink(filename: string) = - prependStr(toLink, filename) # BUGFIX - #appendStr(toLink, filename); + prependStr(toLink, filename) + # BUGFIX: was ``appendStr`` proc execExternalProgram(cmd: string) = if (optListCmd in gGlobalOptions) or (gVerbosity > 0): MessageOut(cmd) @@ -361,8 +379,8 @@ proc getCompileCFileCmd(cfilename: string, isExternal: bool = false): string = key = cc[c].name & ".exe" if existsConfigVar(key): exe = getConfigVar(key) if targetOS == osWindows: exe = addFileExt(exe, "exe") - if (optGenDynLib in gGlobalOptions) and - (ospNeedsPIC in platform.OS[targetOS].props): + if optGenDynLib in gGlobalOptions and + ospNeedsPIC in platform.OS[targetOS].props: add(options, ' ' & cc[c].pic) if targetOS == platform.hostOS: # compute include paths: @@ -383,11 +401,11 @@ proc getCompileCFileCmd(cfilename: string, isExternal: bool = false): string = objfile, "options", options, "include", includeCmd, "nimrod", getPrefixDir(), "lib", libpath])) add(result, ' ') - add(result, `%`(cc[c].compileTmpl, ["file", cfile, "objfile", objfile, - "options", options, "include", includeCmd, - "nimrod", - quoteIfContainsWhite(getPrefixDir()), - "lib", quoteIfContainsWhite(libpath)])) + addf(result, cc[c].compileTmpl, [ + "file", cfile, "objfile", objfile, + "options", options, "include", includeCmd, + "nimrod", quoteIfContainsWhite(getPrefixDir()), + "lib", quoteIfContainsWhite(libpath)]) proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq, isExternal: bool) = @@ -396,7 +414,7 @@ proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq, inc(fileCounter) # call the C compiler for the .c file: var compileCmd = getCompileCFileCmd(it.data, isExternal) if not (optCompileOnly in gGlobalOptions): - add(cmds, compileCmd) #execExternalProgram(compileCmd); + add(cmds, compileCmd) if (optGenScript in gGlobalOptions): app(script, compileCmd) app(script, tnl) @@ -405,7 +423,7 @@ proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq, proc CallCCompiler(projectfile: string) = var linkCmd, buildgui, builddll: string - if (gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}): + if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}: return # speed up that call if only compiling and no script shall be # generated fileCounter = 0 @@ -414,7 +432,7 @@ proc CallCCompiler(projectfile: string) = var cmds: TStringSeq = @[] CompileCFile(toCompile, script, cmds, false) CompileCFile(externalToCompile, script, cmds, true) - if not (optCompileOnly in gGlobalOptions): + if optCompileOnly notin gGlobalOptions: if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors() var res = 0 if gNumberOfProcessors <= 1: @@ -426,7 +444,7 @@ proc CallCCompiler(projectfile: string) = res = execProcesses(cmds, {poUseShell, poParentStreams}, gNumberOfProcessors) if res != 0: rawMessage(errExecutionOfProgramFailed, []) - if not (optNoLinking in gGlobalOptions): + if optNoLinking notin gGlobalOptions: # call the linker: var linkerExe = getConfigVar(cc[c].name & ".linkerexe") if len(linkerExe) == 0: linkerExe = cc[c].linkerExe @@ -448,22 +466,21 @@ proc CallCCompiler(projectfile: string) = var it = PStrEntry(toLink.head) var objfiles = "" while it != nil: - add(objfiles, " ") + add(objfiles, ' ') if targetOS == platform.hostOS: add(objfiles, quoteIfContainsWhite(toObjfile(it.data))) else: add(objfiles, quoteIfContainsWhite(toObjfile(extractFileName(it.data)))) it = PStrEntry(it.next) - linkCmd = quoteIfContainsWhite(`%`(linkCmd, ["builddll", builddll, + linkCmd = quoteIfContainsWhite(linkCmd % ["builddll", builddll, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, - "exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath])) + "exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath]) add(linkCmd, ' ') - add(linkCmd, `%`(cc[c].linkTmpl, ["builddll", builddll, "buildgui", - buildgui, "options", linkOptions, - "objfiles", objfiles, "exefile", exefile, - "nimrod", - quoteIfContainsWhite(getPrefixDir()), - "lib", quoteIfContainsWhite(libpath)])) + addf(linkCmd, cc[c].linkTmpl, ["builddll", builddll, + "buildgui", buildgui, "options", linkOptions, + "objfiles", objfiles, "exefile", exefile, + "nimrod", quoteIfContainsWhite(getPrefixDir()), + "lib", quoteIfContainsWhite(libpath)]) if not (optCompileOnly in gGlobalOptions): execExternalProgram(linkCmd) else: linkCmd = "" diff --git a/rod/pragmas.nim b/rod/pragmas.nim index 02411ee52..28e4b2a7b 100755 --- a/rod/pragmas.nim +++ b/rod/pragmas.nim @@ -299,7 +299,7 @@ proc processCompile(c: PContext, n: PNode) = var found = findFile(s) if found == "": found = s var trunc = ChangeFileExt(found, "") - extccomp.addExternalFileToCompile(trunc) + extccomp.addExternalFileToCompile(found) extccomp.addFileToLink(completeCFilePath(trunc, false)) proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) = diff --git a/web/news.txt b/web/news.txt index 5096f9af4..94ba076b7 100755 --- a/web/news.txt +++ b/web/news.txt @@ -5,6 +5,12 @@ News 2010-XX-XX Version 0.8.10 released ================================== +Bugfixes +-------- + +- Bugfix: Command line parsing on Windows and ``os.parseCmdLine`` now adheres + to the same parsing rules as Microsoft's C/C++ startup code. + Changes affecting backwards compatibility ----------------------------------------- @@ -13,6 +19,12 @@ Changes affecting backwards compatibility unless they are used in the same module. +Additions +--------- + +- The ``{.compile: "file.c".}`` pragma uses a CRC check to see if the file + needs to be recompiled. + 2010-03-14 Version 0.8.8 released ================================= |