Merge branch 'master' of https://github.com/Araq/Nimrod into vm2
Conflicts: web/news.txt
This commit is contained in:
commit
b76729df1c
35 changed files with 1047 additions and 269 deletions
|
|
@ -33,10 +33,10 @@ proc openDefaultBrowser*(url: string) =
|
|||
else:
|
||||
discard ShellExecuteA(0'i32, "open", url, nil, nil, SW_SHOWNORMAL)
|
||||
elif defined(macosx):
|
||||
discard execShellCmd("open " & quoteIfContainsWhite(url))
|
||||
discard execShellCmd("open " & quoteShell(url))
|
||||
else:
|
||||
const attempts = ["gnome-open ", "kde-open ", "xdg-open "]
|
||||
var u = quoteIfContainsWhite(url)
|
||||
var u = quoteShell(url)
|
||||
for a in items(attempts):
|
||||
if execShellCmd(a & u) == 0: return
|
||||
for b in getEnv("BROWSER").string.split(PathSep):
|
||||
|
|
|
|||
|
|
@ -342,16 +342,35 @@ proc writeContentType*() =
|
|||
##
|
||||
## .. code-block:: Nimrod
|
||||
## write(stdout, "Content-type: text/html\n\n")
|
||||
##
|
||||
## It also modifies the debug stack traces so that they contain
|
||||
## ``<br />`` and are easily readable in a browser.
|
||||
write(stdout, "Content-type: text/html\n\n")
|
||||
system.stackTraceNewLine = "<br />\n"
|
||||
|
||||
proc setStackTraceNewLine*() =
|
||||
## Modifies the debug stack traces so that they contain
|
||||
## ``<br />`` and are easily readable in a browser.
|
||||
system.stackTraceNewLine = "<br />\n"
|
||||
proc resetForStacktrace() =
|
||||
stdout.write """<!--: spam
|
||||
Content-Type: text/html
|
||||
|
||||
<body bgcolor=#f0f0f8><font color=#f0f0f8 size=-5> -->
|
||||
<body bgcolor=#f0f0f8><font color=#f0f0f8 size=-5> --> -->
|
||||
</font> </font> </font> </script> </object> </blockquote> </pre>
|
||||
</table> </table> </table> </table> </table> </font> </font> </font>
|
||||
"""
|
||||
|
||||
proc writeErrorMessage*(data: string) =
|
||||
## Tries to reset browser state and writes `data` to stdout in
|
||||
## <plaintext> tag.
|
||||
resetForStacktrace()
|
||||
# We use <plaintext> here, instead of escaping, so stacktrace can
|
||||
# be understood by human looking at source.
|
||||
stdout.write("<plaintext>\n")
|
||||
stdout.write(data)
|
||||
|
||||
proc setStackTraceStdout*() =
|
||||
## Makes Nimrod output stacktraces to stdout, instead of server log.
|
||||
errorMessageWriter = writeErrorMessage
|
||||
|
||||
proc setStackTraceNewLine*() {.deprecated.} =
|
||||
## Makes Nimrod output stacktraces to stdout, instead of server log.
|
||||
## Depracated alias for setStackTraceStdout.
|
||||
setStackTraceStdout()
|
||||
|
||||
proc setCookie*(name, value: string) =
|
||||
## Sets a cookie.
|
||||
|
|
@ -374,4 +393,3 @@ when isMainModule:
|
|||
const test1 = "abc\L+def xyz"
|
||||
assert UrlEncode(test1) == "abc%0A%2Bdef+xyz"
|
||||
assert UrlDecode(UrlEncode(test1)) == test1
|
||||
|
||||
|
|
|
|||
|
|
@ -956,17 +956,37 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
|||
if crename(source, dest) != 0'i32:
|
||||
raise newException(EOS, $strerror(errno))
|
||||
|
||||
when not defined(ENOENT):
|
||||
when not defined(ENOENT) and not defined(Windows):
|
||||
var ENOENT {.importc, header: "<errno.h>".}: cint
|
||||
|
||||
when defined(Windows):
|
||||
when useWinUnicode:
|
||||
template DeleteFile(file: expr): expr {.immediate.} = DeleteFileW(file)
|
||||
template SetFileAttributes(file, attrs: expr): expr {.immediate.} =
|
||||
SetFileAttributesW(file, attrs)
|
||||
else:
|
||||
template DeleteFile(file: expr): expr {.immediate.} = DeleteFileA(file)
|
||||
template SetFileAttributes(file, attrs: expr): expr {.immediate.} =
|
||||
SetFileAttributesA(file, attrs)
|
||||
|
||||
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
|
||||
## Removes the `file`. If this fails, `EOS` is raised. This does not fail
|
||||
## if the file never existed in the first place.
|
||||
## On Windows, ignores the read-only attribute.
|
||||
when defined(Windows):
|
||||
setFilePermissions(file, {fpUserWrite})
|
||||
if cremove(file) != 0'i32 and errno != ENOENT:
|
||||
raise newException(EOS, $strerror(errno))
|
||||
when useWinUnicode:
|
||||
let f = newWideCString(file)
|
||||
else:
|
||||
let f = file
|
||||
if DeleteFile(f) == 0:
|
||||
if GetLastError() == ERROR_ACCESS_DENIED:
|
||||
if SetFileAttributes(f, FILE_ATTRIBUTE_NORMAL) == 0:
|
||||
OSError(OSLastError())
|
||||
if DeleteFile(f) == 0:
|
||||
OSError(OSLastError())
|
||||
else:
|
||||
if cremove(file) != 0'i32 and errno != ENOENT:
|
||||
raise newException(EOS, $strerror(errno))
|
||||
|
||||
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
|
||||
tags: [FExecIO].} =
|
||||
|
|
|
|||
|
|
@ -41,6 +41,58 @@ type
|
|||
poStdErrToStdOut, ## merge stdout and stderr to the stdout stream
|
||||
poParentStreams ## use the parent's streams
|
||||
|
||||
proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
|
||||
## Quote s, so it can be safely passed to Windows API.
|
||||
## Based on Python's subprocess.list2cmdline
|
||||
## See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
|
||||
let needQuote = {' ', '\t'} in s or s.len == 0
|
||||
|
||||
result = ""
|
||||
var backslashBuff = ""
|
||||
if needQuote:
|
||||
result.add("\"")
|
||||
|
||||
for c in s:
|
||||
if c == '\\':
|
||||
backslashBuff.add(c)
|
||||
elif c == '\"':
|
||||
result.add(backslashBuff)
|
||||
result.add(backslashBuff)
|
||||
backslashBuff.setLen(0)
|
||||
result.add("\\\"")
|
||||
else:
|
||||
if backslashBuff.len != 0:
|
||||
result.add(backslashBuff)
|
||||
backslashBuff.setLen(0)
|
||||
result.add(c)
|
||||
|
||||
if needQuote:
|
||||
result.add("\"")
|
||||
|
||||
proc quoteShellPosix*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
|
||||
## Quote s, so it can be safely passed to POSIX shell.
|
||||
## Based on Python's pipes.quote
|
||||
const safeUnixChars = {'%', '+', '-', '.', '/', '_', ':', '=', '@',
|
||||
'0'..'9', 'A'..'Z', 'a'..'z'}
|
||||
if s.len == 0:
|
||||
return "''"
|
||||
|
||||
let safe = s.allCharsInSet(safeUnixChars)
|
||||
|
||||
if safe:
|
||||
return s
|
||||
else:
|
||||
return "'" & s.replace("'", "'\"'\"'") & "'"
|
||||
|
||||
proc quoteShell*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
|
||||
## Quote s, so it can be safely passed to shell.
|
||||
when defined(Windows):
|
||||
return quoteShellWindows(s)
|
||||
elif defined(posix):
|
||||
return quoteShellPosix(s)
|
||||
else:
|
||||
{.error:"quoteShell is not supported on your system".}
|
||||
|
||||
proc execProcess*(command: string,
|
||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||
poUseShell}): TaintedString {.
|
||||
|
|
@ -307,10 +359,10 @@ when defined(Windows) and not defined(useNimRtl):
|
|||
result.writeDataImpl = hsWriteData
|
||||
|
||||
proc buildCommandLine(a: string, args: openarray[string]): cstring =
|
||||
var res = quoteIfContainsWhite(a)
|
||||
var res = quoteShell(a)
|
||||
for i in 0..high(args):
|
||||
res.add(' ')
|
||||
res.add(quoteIfContainsWhite(args[i]))
|
||||
res.add(quoteShell(args[i]))
|
||||
result = cast[cstring](alloc0(res.len+1))
|
||||
copyMem(result, cstring(res), res.len)
|
||||
|
||||
|
|
@ -510,10 +562,10 @@ elif not defined(useNimRtl):
|
|||
writeIdx = 1
|
||||
|
||||
proc addCmdArgs(command: string, args: openarray[string]): string =
|
||||
result = quoteIfContainsWhite(command)
|
||||
result = quoteShell(command)
|
||||
for i in 0 .. high(args):
|
||||
add(result, " ")
|
||||
add(result, quoteIfContainsWhite(args[i]))
|
||||
add(result, quoteShell(args[i]))
|
||||
|
||||
proc toCStringArray(b, a: openarray[string]): cstringArray =
|
||||
result = cast[cstringArray](alloc0((a.len + b.len + 1) * sizeof(cstring)))
|
||||
|
|
@ -792,5 +844,14 @@ proc execCmdEx*(command: string, options: set[TProcessOption] = {
|
|||
close(p)
|
||||
|
||||
when isMainModule:
|
||||
var x = execProcess("gcc -v")
|
||||
echo "ECHO ", x
|
||||
assert quoteShellWindows("aaa") == "aaa"
|
||||
assert quoteShellWindows("aaa\"") == "aaa\\\""
|
||||
assert quoteShellWindows("") == "\"\""
|
||||
|
||||
assert quoteShellPosix("aaa") == "aaa"
|
||||
assert quoteShellPosix("aaa a") == "'aaa a'"
|
||||
assert quoteShellPosix("") == "''"
|
||||
assert quoteShellPosix("a'a") == "'a'\"'\"'a'"
|
||||
|
||||
when defined(posix):
|
||||
assert quoteShell("") == "''"
|
||||
|
|
|
|||
|
|
@ -709,9 +709,11 @@ proc rfind*(s, sub: string, start: int = -1): int {.noSideEffect.} =
|
|||
if result != -1: return
|
||||
return -1
|
||||
|
||||
proc quoteIfContainsWhite*(s: string): string =
|
||||
proc quoteIfContainsWhite*(s: string): string {.deprecated.} =
|
||||
## returns ``'"' & s & '"'`` if `s` contains a space and does not
|
||||
## start with a quote, else returns `s`
|
||||
## DEPRECATED as it was confused for shell quoting function.
|
||||
## For this application use osproc.quoteShell.
|
||||
if find(s, {' ', '\t'}) >= 0 and s[0] != '"':
|
||||
result = '"' & s & '"'
|
||||
else:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue