summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-12-23 01:23:16 +0100
committerAraq <rumpf_a@web.de>2013-12-23 01:23:16 +0100
commitb76729df1cd326a3230536d0f78276cfabe4dd2a (patch)
tree9a7cf9a40ef38a79513a0b4c850e68d53f215e91 /lib/pure
parent9145bcfbb680d653f167a1a12f7830025aa951a5 (diff)
parent52a8226edda05f2d3baad791639a1c2fe7f103cc (diff)
downloadNim-b76729df1cd326a3230536d0f78276cfabe4dd2a.tar.gz
Merge branch 'master' of https://github.com/Araq/Nimrod into vm2
Conflicts:
	web/news.txt
Diffstat (limited to 'lib/pure')
-rw-r--r--lib/pure/actors.nimrod.cfg (renamed from lib/pure/actors.cfg)0
-rw-r--r--lib/pure/browsers.nim4
-rw-r--r--lib/pure/cgi.nim36
-rw-r--r--lib/pure/os.nim28
-rw-r--r--lib/pure/osproc.nim73
-rw-r--r--lib/pure/strutils.nim4
6 files changed, 123 insertions, 22 deletions
diff --git a/lib/pure/actors.cfg b/lib/pure/actors.nimrod.cfg
index c6bb9c545..c6bb9c545 100644
--- a/lib/pure/actors.cfg
+++ b/lib/pure/actors.nimrod.cfg
diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim
index 6f5bf7ddb..b44f406c5 100644
--- a/lib/pure/browsers.nim
+++ b/lib/pure/browsers.nim
@@ -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):
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim
index c499abdc0..29c686fd7 100644
--- a/lib/pure/cgi.nim
+++ b/lib/pure/cgi.nim
@@ -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
-
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index d5c4acaec..91893d169 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -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].} =
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 754e34b85..61b940ce8 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -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("") == "''"
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 79525aa18..e290226d2 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -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: