mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-12 14:23:45 +00:00
Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
@@ -167,7 +167,7 @@ proc AsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
|
||||
result = newAsyncSocket()
|
||||
result.socket = socket(domain, typ, protocol, buffered)
|
||||
result.proto = protocol
|
||||
if result.socket == InvalidSocket: OSError()
|
||||
if result.socket == InvalidSocket: OSError(OSLastError())
|
||||
result.socket.setBlocking(false)
|
||||
|
||||
proc toAsyncSocket*(sock: TSocket, state: TInfo = SockConnected): PAsyncSocket =
|
||||
@@ -349,7 +349,7 @@ proc acceptAddr*(server: PAsyncSocket, client: var PAsyncSocket,
|
||||
client.sslNeedAccept = false
|
||||
client.info = SockConnected
|
||||
|
||||
if c == InvalidSocket: OSError()
|
||||
if c == InvalidSocket: SocketError(server.socket)
|
||||
c.setBlocking(false) # TODO: Needs to be tested.
|
||||
|
||||
# deleg.open is set in ``toDelegate``.
|
||||
@@ -423,6 +423,10 @@ proc isConnecting*(s: PAsyncSocket): bool =
|
||||
proc isClosed*(s: PAsyncSocket): bool =
|
||||
## Determines whether ``s`` has been closed.
|
||||
return s.info == SockClosed
|
||||
proc isSendDataBuffered*(s: PAsyncSocket): bool =
|
||||
## Determines whether ``s`` has data waiting to be sent, i.e. whether this
|
||||
## socket's sendBuffer contains data.
|
||||
return s.sendBuffer.len != 0
|
||||
|
||||
proc setHandleWrite*(s: PAsyncSocket,
|
||||
handleWrite: proc (s: PAsyncSocket) {.closure.}) =
|
||||
@@ -638,8 +642,7 @@ when isMainModule:
|
||||
proc testRead(s: PAsyncSocket, no: int) =
|
||||
echo("Reading! " & $no)
|
||||
var data = ""
|
||||
if not s.readLine(data):
|
||||
OSError()
|
||||
if not s.readLine(data): return
|
||||
if data == "":
|
||||
echo("Closing connection. " & $no)
|
||||
s.close()
|
||||
|
||||
179
lib/pure/os.nim
179
lib/pure/os.nim
@@ -39,6 +39,8 @@ type
|
||||
FWriteDir* = object of FWriteIO ## effect that denotes a write operation to
|
||||
## the directory structure
|
||||
|
||||
TOSErrorCode* = distinct int32 ## Specifies an OS Error Code.
|
||||
|
||||
const
|
||||
doslike = defined(windows) or defined(OS2) or defined(DOS)
|
||||
# DOS-like filesystem
|
||||
@@ -171,10 +173,13 @@ const
|
||||
## The character which separates the base filename from the extension;
|
||||
## for example, the '.' in ``os.nim``.
|
||||
|
||||
proc OSErrorMsg*(): string {.rtl, extern: "nos$1".} =
|
||||
proc OSErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} =
|
||||
## Retrieves the operating system's error flag, ``errno``.
|
||||
## On Windows ``GetLastError`` is checked before ``errno``.
|
||||
## Returns "" if no error occured.
|
||||
##
|
||||
## **Deprecated since version 0.9.4**: use the other ``OSErrorMsg`` proc.
|
||||
|
||||
result = ""
|
||||
when defined(Windows):
|
||||
var err = GetLastError()
|
||||
@@ -194,17 +199,89 @@ proc OSErrorMsg*(): string {.rtl, extern: "nos$1".} =
|
||||
if errno != 0'i32:
|
||||
result = $os.strerror(errno)
|
||||
|
||||
proc OSError*(msg: string = "") {.noinline, rtl, extern: "nos$1".} =
|
||||
{.push warning[deprecated]: off.}
|
||||
proc OSError*(msg: string = "") {.noinline, rtl, extern: "nos$1", deprecated.} =
|
||||
## raises an EOS exception with the given message ``msg``.
|
||||
## If ``msg == ""``, the operating system's error flag
|
||||
## (``errno``) is converted to a readable error message. On Windows
|
||||
## ``GetLastError`` is checked before ``errno``.
|
||||
## If no error flag is set, the message ``unknown OS error`` is used.
|
||||
##
|
||||
## **Deprecated since version 0.9.4**: use the other ``OSError`` proc.
|
||||
if len(msg) == 0:
|
||||
var m = OSErrorMsg()
|
||||
raise newException(EOS, if m.len > 0: m else: "unknown OS error")
|
||||
else:
|
||||
raise newException(EOS, msg)
|
||||
{.pop.}
|
||||
|
||||
proc `==`*(err1, err2: TOSErrorCode): bool {.borrow.}
|
||||
proc `$`*(err: TOSErrorCode): string {.borrow.}
|
||||
|
||||
proc OSErrorMsg*(errorCode: TOSErrorCode): string =
|
||||
## Converts an OS error code into a human readable string.
|
||||
##
|
||||
## The error code can be retrieved using the ``OSLastError`` proc.
|
||||
##
|
||||
## If conversion fails, or ``errorCode`` is ``0`` then ``""`` will be
|
||||
## returned.
|
||||
##
|
||||
## On Windows, the ``-d:useWinAnsi`` compilation flag can be used to
|
||||
## make this procedure use the non-unicode Win API calls to retrieve the
|
||||
## message.
|
||||
result = ""
|
||||
when defined(Windows):
|
||||
if errorCode != TOSErrorCode(0'i32):
|
||||
when useWinUnicode:
|
||||
var msgbuf: widecstring
|
||||
if FormatMessageW(0x00000100 or 0x00001000 or 0x00000200,
|
||||
nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32:
|
||||
result = $msgbuf
|
||||
if msgbuf != nil: LocalFree(cast[pointer](msgbuf))
|
||||
else:
|
||||
var msgbuf: cstring
|
||||
if FormatMessageA(0x00000100 or 0x00001000 or 0x00000200,
|
||||
nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32:
|
||||
result = $msgbuf
|
||||
if msgbuf != nil: LocalFree(msgbuf)
|
||||
else:
|
||||
if errorCode != TOSErrorCode(0'i32):
|
||||
result = $os.strerror(errorCode.int32)
|
||||
|
||||
proc OSError*(errorCode: TOSErrorCode) =
|
||||
## Raises an ``EOS`` exception. The ``errorCode`` will determine the
|
||||
## message, ``OSErrorMsg`` will be used to get this message.
|
||||
##
|
||||
## The error code can be retrieved using the ``OSLastError`` proc.
|
||||
##
|
||||
## If the error code is ``0`` or an error message could not be retrieved,
|
||||
## the message ``unknown OS error`` will be used.
|
||||
let msg = OSErrorMsg(errorCode)
|
||||
if msg == "":
|
||||
raise newException(EOS, "unknown OS error")
|
||||
else:
|
||||
raise newException(EOS, msg)
|
||||
|
||||
{.push stackTrace:off.}
|
||||
proc OSLastError*(): TOSErrorCode =
|
||||
## Retrieves the last operating system error code.
|
||||
##
|
||||
## This procedure is useful in the event when an OS call fails. In that case
|
||||
## this procedure will return the error code describing the reason why the
|
||||
## OS call failed. The ``OSErrorMsg`` procedure can then be used to convert
|
||||
## this code into a string.
|
||||
##
|
||||
## **Warning**:
|
||||
## The behaviour of this procedure varies between Windows and POSIX systems.
|
||||
## On Windows some OS calls can reset the error code to ``0`` causing this
|
||||
## procedure to return ``0``. It is therefore advised to call this procedure
|
||||
## immediately after an OS call fails. On POSIX systems this is not a problem.
|
||||
|
||||
when defined(windows):
|
||||
result = TOSErrorCode(GetLastError())
|
||||
else:
|
||||
result = TOSErrorCode(errno)
|
||||
{.pop.}
|
||||
|
||||
proc UnixToNativePath*(path: string): string {.
|
||||
noSideEffect, rtl, extern: "nos$1".} =
|
||||
@@ -311,12 +388,12 @@ proc getLastModificationTime*(file: string): TTime {.rtl, extern: "nos$1".} =
|
||||
## Returns the `file`'s last modification time.
|
||||
when defined(posix):
|
||||
var res: TStat
|
||||
if stat(file, res) < 0'i32: OSError()
|
||||
if stat(file, res) < 0'i32: OSError(OSLastError())
|
||||
return res.st_mtime
|
||||
else:
|
||||
var f: TWIN32_Find_Data
|
||||
var h = findfirstFile(file, f)
|
||||
if h == -1'i32: OSError()
|
||||
if h == -1'i32: OSError(OSLastError())
|
||||
result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime))
|
||||
findclose(h)
|
||||
|
||||
@@ -324,12 +401,12 @@ proc getLastAccessTime*(file: string): TTime {.rtl, extern: "nos$1".} =
|
||||
## Returns the `file`'s last read or write access time.
|
||||
when defined(posix):
|
||||
var res: TStat
|
||||
if stat(file, res) < 0'i32: OSError()
|
||||
if stat(file, res) < 0'i32: OSError(OSLastError())
|
||||
return res.st_atime
|
||||
else:
|
||||
var f: TWIN32_Find_Data
|
||||
var h = findfirstFile(file, f)
|
||||
if h == -1'i32: OSError()
|
||||
if h == -1'i32: OSError(OSLastError())
|
||||
result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime))
|
||||
findclose(h)
|
||||
|
||||
@@ -337,12 +414,12 @@ proc getCreationTime*(file: string): TTime {.rtl, extern: "nos$1".} =
|
||||
## Returns the `file`'s creation time.
|
||||
when defined(posix):
|
||||
var res: TStat
|
||||
if stat(file, res) < 0'i32: OSError()
|
||||
if stat(file, res) < 0'i32: OSError(OSLastError())
|
||||
return res.st_ctime
|
||||
else:
|
||||
var f: TWIN32_Find_Data
|
||||
var h = findfirstFile(file, f)
|
||||
if h == -1'i32: OSError()
|
||||
if h == -1'i32: OSError(OSLastError())
|
||||
result = winTimeToUnixTime(rdFileTime(f.ftCreationTime))
|
||||
findclose(h)
|
||||
|
||||
@@ -358,30 +435,30 @@ proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} =
|
||||
when useWinUnicode:
|
||||
var res = newWideCString("", bufsize)
|
||||
var L = GetCurrentDirectoryW(bufsize, res)
|
||||
if L == 0'i32: OSError()
|
||||
if L == 0'i32: OSError(OSLastError())
|
||||
result = res$L
|
||||
else:
|
||||
result = newString(bufsize)
|
||||
var L = GetCurrentDirectoryA(bufsize, result)
|
||||
if L == 0'i32: OSError()
|
||||
if L == 0'i32: OSError(OSLastError())
|
||||
setLen(result, L)
|
||||
else:
|
||||
result = newString(bufsize)
|
||||
if getcwd(result, bufsize) != nil:
|
||||
setlen(result, c_strlen(result))
|
||||
else:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
|
||||
proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
|
||||
## Sets the `current working directory`:idx:; `EOS` is raised if
|
||||
## `newDir` cannot been set.
|
||||
when defined(Windows):
|
||||
when useWinUnicode:
|
||||
if SetCurrentDirectoryW(newWideCString(newDir)) == 0'i32: OSError()
|
||||
if SetCurrentDirectoryW(newWideCString(newDir)) == 0'i32: OSError(OSLastError())
|
||||
else:
|
||||
if SetCurrentDirectoryA(newDir) == 0'i32: OSError()
|
||||
if SetCurrentDirectoryA(newDir) == 0'i32: OSError(OSLastError())
|
||||
else:
|
||||
if chdir(newDir) != 0'i32: OSError()
|
||||
if chdir(newDir) != 0'i32: OSError(OSLastError())
|
||||
|
||||
proc JoinPath*(head, tail: string): string {.
|
||||
noSideEffect, rtl, extern: "nos$1".} =
|
||||
@@ -571,23 +648,23 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
|
||||
var res = newWideCString("", bufsize div 2)
|
||||
var L = GetFullPathNameW(newWideCString(filename), bufsize, res, unused)
|
||||
if L <= 0'i32 or L >= bufsize:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
result = res$L
|
||||
else:
|
||||
var unused: cstring
|
||||
result = newString(bufsize)
|
||||
var L = GetFullPathNameA(filename, bufsize, result, unused)
|
||||
if L <= 0'i32 or L >= bufsize: OSError()
|
||||
if L <= 0'i32 or L >= bufsize: OSError(OSLastError())
|
||||
setLen(result, L)
|
||||
elif defined(macosx) or defined(bsd):
|
||||
# On Mac OS X 10.5, realpath does not allocate the buffer on its own
|
||||
var pathBuffer: cstring = newString(pathMax)
|
||||
var resultBuffer = realpath(filename, pathBuffer)
|
||||
if resultBuffer == nil: OSError()
|
||||
if resultBuffer == nil: OSError(OSLastError())
|
||||
result = $resultBuffer
|
||||
else:
|
||||
var res = realpath(filename, nil)
|
||||
if res == nil: OSError()
|
||||
if res == nil: OSError(OSLastError())
|
||||
result = $res
|
||||
c_free(res)
|
||||
|
||||
@@ -677,6 +754,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
|
||||
var f1 = OpenHandle(path1)
|
||||
var f2 = OpenHandle(path2)
|
||||
|
||||
var lastErr: TOSErrorCode
|
||||
if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
|
||||
var fi1, fi2: TBY_HANDLE_FILE_INFORMATION
|
||||
|
||||
@@ -685,17 +763,21 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
|
||||
result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and
|
||||
fi1.nFileIndexHigh == fi2.nFileIndexHigh and
|
||||
fi1.nFileIndexLow == fi2.nFileIndexLow
|
||||
else: success = false
|
||||
else: success = false
|
||||
else:
|
||||
lastErr = OSLastError()
|
||||
success = false
|
||||
else:
|
||||
lastErr = OSLastError()
|
||||
success = false
|
||||
|
||||
discard CloseHandle(f1)
|
||||
discard CloseHandle(f2)
|
||||
|
||||
if not success: OSError()
|
||||
if not success: OSError(lastErr)
|
||||
else:
|
||||
var a, b: TStat
|
||||
if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
else:
|
||||
result = a.st_dev == b.st_dev and a.st_ino == b.st_ino
|
||||
|
||||
@@ -738,17 +820,17 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
when useWinUnicode:
|
||||
let s = newWideCString(source)
|
||||
let d = newWideCString(dest)
|
||||
if CopyFileW(s, d, 0'i32) == 0'i32: OSError()
|
||||
if CopyFileW(s, d, 0'i32) == 0'i32: OSError(OSLastError())
|
||||
else:
|
||||
if CopyFileA(source, dest, 0'i32) == 0'i32: OSError()
|
||||
if CopyFileA(source, dest, 0'i32) == 0'i32: OSError(OSLastError())
|
||||
else:
|
||||
# generic version of copyFile which works for any platform:
|
||||
const bufSize = 8000 # better for memory manager
|
||||
var d, s: TFile
|
||||
if not open(s, source): OSError()
|
||||
if not open(s, source): OSError(OSLastError())
|
||||
if not open(d, dest, fmWrite):
|
||||
close(s)
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
var buf = alloc(bufsize)
|
||||
while True:
|
||||
var bytesread = readBuffer(s, buf, bufsize)
|
||||
@@ -758,7 +840,7 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
dealloc(buf)
|
||||
close(s)
|
||||
close(d)
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
if bytesread != bufSize: break
|
||||
dealloc(buf)
|
||||
close(s)
|
||||
@@ -767,7 +849,8 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
tags: [FReadIO, FWriteIO].} =
|
||||
## Moves a file from `source` to `dest`. If this fails, `EOS` is raised.
|
||||
if crename(source, dest) != 0'i32: OSError()
|
||||
if crename(source, dest) != 0'i32:
|
||||
raise newException(EOS, $strerror(errno))
|
||||
|
||||
when not defined(ENOENT):
|
||||
var ENOENT {.importc, header: "<errno.h>".}: cint
|
||||
@@ -775,7 +858,8 @@ when not defined(ENOENT):
|
||||
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.
|
||||
if cremove(file) != 0'i32 and errno != ENOENT: OSError()
|
||||
if cremove(file) != 0'i32 and errno != ENOENT:
|
||||
raise newException(EOS, $strerror(errno))
|
||||
|
||||
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
|
||||
tags: [FExecIO].} =
|
||||
@@ -907,14 +991,14 @@ proc putEnv*(key, val: string) {.tags: [FWriteEnv].} =
|
||||
indx = high(environment)
|
||||
when defined(unix):
|
||||
if cputenv(environment[indx]) != 0'i32:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
else:
|
||||
when useWinUnicode:
|
||||
var k = newWideCString(key)
|
||||
var v = newWideCString(val)
|
||||
if SetEnvironmentVariableW(k, v) == 0'i32: OSError()
|
||||
if SetEnvironmentVariableW(k, v) == 0'i32: OSError(OSLastError())
|
||||
else:
|
||||
if SetEnvironmentVariableA(key, val) == 0'i32: OSError()
|
||||
if SetEnvironmentVariableA(key, val) == 0'i32: OSError(OSLastError())
|
||||
|
||||
iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [FReadEnv].} =
|
||||
## Iterate over all `environments variables`:idx:. In the first component
|
||||
@@ -1044,10 +1128,12 @@ proc rawRemoveDir(dir: string) =
|
||||
wrapUnary(res, RemoveDirectoryW, dir)
|
||||
else:
|
||||
var res = RemoveDirectoryA(dir)
|
||||
if res == 0'i32 and GetLastError() != 3'i32 and
|
||||
GetLastError() != 18'i32: OSError()
|
||||
let lastError = OSLastError()
|
||||
if res == 0'i32 and lastError.int32 != 3'i32 and
|
||||
lastError.int32 != 18'i32 and lastError.int32 != 2'i32:
|
||||
OSError(lastError)
|
||||
else:
|
||||
if rmdir(dir) != 0'i32 and errno != ENOENT: OSError()
|
||||
if rmdir(dir) != 0'i32 and errno != ENOENT: OSError(OSLastError())
|
||||
|
||||
proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
|
||||
FWriteDir, FReadDir].} =
|
||||
@@ -1065,14 +1151,14 @@ proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
|
||||
proc rawCreateDir(dir: string) =
|
||||
when defined(unix):
|
||||
if mkdir(dir, 0o711) != 0'i32 and errno != EEXIST:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
else:
|
||||
when useWinUnicode:
|
||||
wrapUnary(res, CreateDirectoryW, dir)
|
||||
else:
|
||||
var res = CreateDirectoryA(dir)
|
||||
if res == 0'i32 and GetLastError() != 183'i32:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
|
||||
proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
|
||||
## Creates the `directory`:idx: `dir`.
|
||||
@@ -1213,7 +1299,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {.
|
||||
## permission is available in any case.
|
||||
when defined(posix):
|
||||
var a: TStat
|
||||
if stat(filename, a) < 0'i32: OSError()
|
||||
if stat(filename, a) < 0'i32: OSError(OSLastError())
|
||||
result = {}
|
||||
if (a.st_mode and S_IRUSR) != 0'i32: result.incl(fpUserRead)
|
||||
if (a.st_mode and S_IWUSR) != 0'i32: result.incl(fpUserWrite)
|
||||
@@ -1231,7 +1317,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {.
|
||||
wrapUnary(res, GetFileAttributesW, filename)
|
||||
else:
|
||||
var res = GetFileAttributesA(filename)
|
||||
if res == -1'i32: OSError()
|
||||
if res == -1'i32: OSError(OSLastError())
|
||||
if (res and FILE_ATTRIBUTE_READONLY) != 0'i32:
|
||||
result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead,
|
||||
fpOthersExec, fpOthersRead}
|
||||
@@ -1257,13 +1343,13 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
|
||||
if fpOthersWrite in permissions: p = p or S_IWOTH
|
||||
if fpOthersExec in permissions: p = p or S_IXOTH
|
||||
|
||||
if chmod(filename, p) != 0: OSError()
|
||||
if chmod(filename, p) != 0: OSError(OSLastError())
|
||||
else:
|
||||
when useWinUnicode:
|
||||
wrapUnary(res, GetFileAttributesW, filename)
|
||||
else:
|
||||
var res = GetFileAttributesA(filename)
|
||||
if res == -1'i32: OSError()
|
||||
if res == -1'i32: OSError(OSLastError())
|
||||
if fpUserWrite in permissions:
|
||||
res = res and not FILE_ATTRIBUTE_READONLY
|
||||
else:
|
||||
@@ -1272,7 +1358,7 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
|
||||
wrapBinary(res2, SetFileAttributesW, filename, res)
|
||||
else:
|
||||
var res2 = SetFileAttributesA(filename, res)
|
||||
if res2 == - 1'i32: OSError()
|
||||
if res2 == - 1'i32: OSError(OSLastError())
|
||||
|
||||
proc inclFilePermissions*(filename: string,
|
||||
permissions: set[TFilePermission]) {.
|
||||
@@ -1368,6 +1454,9 @@ when defined(macosx):
|
||||
|
||||
proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} =
|
||||
## Returns the filename of the application's executable.
|
||||
##
|
||||
## This procedure will resolve symlinks.
|
||||
##
|
||||
## **Note**: This does not work reliably on BSD.
|
||||
|
||||
# Linux: /proc/<pid>/exe
|
||||
@@ -1397,6 +1486,8 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} =
|
||||
result = newString(int(size))
|
||||
if getExecPath2(result, size):
|
||||
result = "" # error!
|
||||
if result.len > 0:
|
||||
result = result.expandFilename
|
||||
else:
|
||||
# little heuristic that may work on other POSIX-like systems:
|
||||
result = string(getEnv("_"))
|
||||
@@ -1443,7 +1534,7 @@ proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1",
|
||||
when defined(windows):
|
||||
var a: TWin32FindData
|
||||
var resA = findfirstFile(file, a)
|
||||
if resA == -1: OSError()
|
||||
if resA == -1: OSError(OSLastError())
|
||||
result = rdFileSize(a)
|
||||
findclose(resA)
|
||||
else:
|
||||
@@ -1451,7 +1542,7 @@ proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1",
|
||||
if open(f, file):
|
||||
result = getFileSize(f)
|
||||
close(f)
|
||||
else: OSError()
|
||||
else: OSError(OSLastError())
|
||||
|
||||
proc findExe*(exe: string): string {.tags: [FReadDir, FReadEnv].} =
|
||||
## Searches for `exe` in the current working directory and then
|
||||
|
||||
@@ -264,7 +264,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
# TRUE and zero bytes returned (EOF).
|
||||
# TRUE and n (>0) bytes returned (good data).
|
||||
# FALSE and bytes returned undefined (system error).
|
||||
if a == 0 and br != 0: OSError()
|
||||
if a == 0 and br != 0: OSError(OSLastError())
|
||||
s.atTheEnd = br < bufLen
|
||||
result = br
|
||||
|
||||
@@ -272,7 +272,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
var s = PFileHandleStream(s)
|
||||
var bytesWritten: int32
|
||||
var a = winlean.writeFile(s.handle, buffer, bufLen.cint, bytesWritten, nil)
|
||||
if a == 0: OSError()
|
||||
if a == 0: OSError(OSLastError())
|
||||
|
||||
proc newFileHandleStream(handle: THandle): PFileHandleStream =
|
||||
new(result)
|
||||
@@ -313,7 +313,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
piInheritablePipe.lpSecurityDescriptor = nil
|
||||
piInheritablePipe.Binherithandle = 1
|
||||
if CreatePipe(Rdhandle, Wrhandle, piInheritablePipe, 1024) == 0'i32:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
|
||||
proc fileClose(h: THandle) {.inline.} =
|
||||
if h > 4: discard CloseHandle(h)
|
||||
@@ -370,6 +370,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
else:
|
||||
success = winlean.CreateProcessA(nil,
|
||||
cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo)
|
||||
let lastError = OSLastError()
|
||||
|
||||
if poParentStreams notin options:
|
||||
FileClose(si.hStdInput)
|
||||
@@ -379,7 +380,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
|
||||
if e != nil: dealloc(e)
|
||||
dealloc(cmdl)
|
||||
if success == 0: OSError()
|
||||
if success == 0: OSError(lastError)
|
||||
# Close the handle now so anyone waiting is woken:
|
||||
discard closeHandle(procInfo.hThread)
|
||||
result.FProcessHandle = procInfo.hProcess
|
||||
@@ -450,7 +451,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
var res = winlean.CreateProcessA(nil, command, nil, nil, 0,
|
||||
NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo)
|
||||
if res == 0:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
else:
|
||||
Process = ProcInfo.hProcess
|
||||
discard CloseHandle(ProcInfo.hThread)
|
||||
@@ -473,7 +474,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
of WAIT_TIMEOUT:
|
||||
return 0
|
||||
of WAIT_FAILED:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
else:
|
||||
var i = ret - WAIT_OBJECT_0
|
||||
readfds.del(i)
|
||||
@@ -531,7 +532,7 @@ elif not defined(useNimRtl):
|
||||
if poParentStreams notin options:
|
||||
if pipe(p_stdin) != 0'i32 or pipe(p_stdout) != 0'i32 or
|
||||
pipe(p_stderr) != 0'i32:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
|
||||
var pid: TPid
|
||||
when defined(posix_spawn) and not defined(useFork):
|
||||
@@ -539,7 +540,7 @@ elif not defined(useNimRtl):
|
||||
var fops: Tposix_spawn_file_actions
|
||||
|
||||
template chck(e: expr) =
|
||||
if e != 0'i32: OSError()
|
||||
if e != 0'i32: OSError(OSLastError())
|
||||
|
||||
chck posix_spawn_file_actions_init(fops)
|
||||
chck posix_spawnattr_init(attr)
|
||||
@@ -584,20 +585,20 @@ elif not defined(useNimRtl):
|
||||
else:
|
||||
|
||||
Pid = fork()
|
||||
if Pid < 0: OSError()
|
||||
if Pid < 0: OSError(OSLastError())
|
||||
if pid == 0:
|
||||
## child process:
|
||||
|
||||
if poParentStreams notin options:
|
||||
discard close(p_stdin[writeIdx])
|
||||
if dup2(p_stdin[readIdx], readIdx) < 0: OSError()
|
||||
if dup2(p_stdin[readIdx], readIdx) < 0: OSError(OSLastError())
|
||||
discard close(p_stdout[readIdx])
|
||||
if dup2(p_stdout[writeIdx], writeIdx) < 0: OSError()
|
||||
if dup2(p_stdout[writeIdx], writeIdx) < 0: OSError(OSLastError())
|
||||
discard close(p_stderr[readIdx])
|
||||
if poStdErrToStdOut in options:
|
||||
if dup2(p_stdout[writeIdx], 2) < 0: OSError()
|
||||
if dup2(p_stdout[writeIdx], 2) < 0: OSError(OSLastError())
|
||||
else:
|
||||
if dup2(p_stderr[writeIdx], 2) < 0: OSError()
|
||||
if dup2(p_stderr[writeIdx], 2) < 0: OSError(OSLastError())
|
||||
|
||||
# Create a new process group
|
||||
if setpgid(0, 0) == -1: quit("setpgid call failed: " & $strerror(errno))
|
||||
@@ -652,10 +653,10 @@ elif not defined(useNimRtl):
|
||||
discard close(p.errorHandle)
|
||||
|
||||
proc suspend(p: PProcess) =
|
||||
if kill(-p.id, SIGSTOP) != 0'i32: OSError()
|
||||
if kill(-p.id, SIGSTOP) != 0'i32: OSError(OSLastError())
|
||||
|
||||
proc resume(p: PProcess) =
|
||||
if kill(-p.id, SIGCONT) != 0'i32: OSError()
|
||||
if kill(-p.id, SIGCONT) != 0'i32: OSError(OSLastError())
|
||||
|
||||
proc running(p: PProcess): bool =
|
||||
var ret = waitPid(p.id, p.exitCode, WNOHANG)
|
||||
@@ -665,8 +666,8 @@ elif not defined(useNimRtl):
|
||||
proc terminate(p: PProcess) =
|
||||
if kill(-p.id, SIGTERM) == 0'i32:
|
||||
if p.running():
|
||||
if kill(-p.id, SIGKILL) != 0'i32: OSError()
|
||||
else: OSError()
|
||||
if kill(-p.id, SIGKILL) != 0'i32: OSError(OSLastError())
|
||||
else: OSError(OSLastError())
|
||||
|
||||
proc waitForExit(p: PProcess, timeout: int = -1): int =
|
||||
#if waitPid(p.id, p.exitCode, 0) == int(p.id):
|
||||
@@ -676,7 +677,7 @@ elif not defined(useNimRtl):
|
||||
if p.exitCode != -3: return p.exitCode
|
||||
if waitPid(p.id, p.exitCode, 0) < 0:
|
||||
p.exitCode = -3
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
result = int(p.exitCode) shr 8
|
||||
|
||||
proc peekExitCode(p: PProcess): int =
|
||||
@@ -690,7 +691,7 @@ elif not defined(useNimRtl):
|
||||
proc createStream(stream: var PStream, handle: var TFileHandle,
|
||||
fileMode: TFileMode) =
|
||||
var f: TFile
|
||||
if not open(f, handle, fileMode): OSError()
|
||||
if not open(f, handle, fileMode): OSError(OSLastError())
|
||||
stream = newFileStream(f)
|
||||
|
||||
proc inputStream(p: PProcess): PStream =
|
||||
|
||||
@@ -175,6 +175,15 @@ proc recvBufferAsync(client: PAsyncClient, L: int): TReadLineResult =
|
||||
if ret == L:
|
||||
return ReadFullLine
|
||||
|
||||
proc checkCloseSocket(client: PAsyncClient) =
|
||||
if not client.c.isClosed:
|
||||
if client.c.isSendDataBuffered:
|
||||
client.c.setHandleWrite do (s: PAsyncSocket):
|
||||
if not s.isClosed and not s.isSendDataBuffered:
|
||||
s.close()
|
||||
s.delHandleWrite()
|
||||
else: client.c.close()
|
||||
|
||||
proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) =
|
||||
case client.mode
|
||||
of ClientReadChar:
|
||||
@@ -206,7 +215,7 @@ proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) =
|
||||
client.mode = ClientReadContent
|
||||
else:
|
||||
s.handleRequest(client.c, client.input, client.headers)
|
||||
if not client.c.isClosed: client.c.close()
|
||||
checkCloseSocket(client)
|
||||
of ReadPartialLine, ReadDisconnected, ReadNone: return
|
||||
of ClientReadContent:
|
||||
let L = parseInt(client.headers["CONTENT_LENGTH"])-client.input.len
|
||||
@@ -215,11 +224,11 @@ proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) =
|
||||
case ret
|
||||
of ReadFullLine:
|
||||
s.handleRequest(client.c, client.input, client.headers)
|
||||
if not client.c.isClosed: client.c.close()
|
||||
checkCloseSocket(client)
|
||||
of ReadPartialLine, ReadDisconnected, ReadNone: return
|
||||
else:
|
||||
s.handleRequest(client.c, client.input, client.headers)
|
||||
if not client.c.isClosed: client.c.close()
|
||||
checkCloseSocket(client)
|
||||
|
||||
proc handleAccept(sock: PAsyncSocket, s: PAsyncScgiState) =
|
||||
var client: PAsyncSocket
|
||||
|
||||
@@ -231,7 +231,7 @@ when defined(ssl):
|
||||
if err == 0:
|
||||
raise newException(ESSL, "No error reported.")
|
||||
if err == -1:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
var errStr = ErrErrorString(err, nil)
|
||||
raise newException(ESSL, $errStr)
|
||||
|
||||
@@ -347,24 +347,23 @@ proc SocketError*(socket: TSocket, err: int = -1, async = false) =
|
||||
else: SSLError("Unknown Error")
|
||||
|
||||
if err == -1 and not (when defined(ssl): socket.isSSL else: false):
|
||||
let lastError = OSLastError()
|
||||
if async:
|
||||
when defined(windows):
|
||||
# TODO: Test on Windows
|
||||
var err = WSAGetLastError()
|
||||
if err == WSAEWOULDBLOCK:
|
||||
if lastError.int32 == WSAEWOULDBLOCK:
|
||||
return
|
||||
else: OSError()
|
||||
else: OSError(lastError)
|
||||
else:
|
||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
||||
if lastError.int32 == EAGAIN or lastError.int32 == EWOULDBLOCK:
|
||||
return
|
||||
else: OSError()
|
||||
else: OSError()
|
||||
else: OSError(lastError)
|
||||
else: OSError(lastError)
|
||||
|
||||
proc listen*(socket: TSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} =
|
||||
## Marks ``socket`` as accepting connections.
|
||||
## ``Backlog`` specifies the maximum length of the
|
||||
## queue of pending connections.
|
||||
if listen(socket.fd, cint(backlog)) < 0'i32: OSError()
|
||||
if listen(socket.fd, cint(backlog)) < 0'i32: OSError(OSLastError())
|
||||
|
||||
proc invalidIp4(s: string) {.noreturn, noinline.} =
|
||||
raise newException(EInvalidValue, "invalid ip4 address: " & s)
|
||||
@@ -403,7 +402,7 @@ template gaiNim(a, p, h, list: expr): stmt =
|
||||
var gaiResult = getAddrInfo(a, $p, addr(h), list)
|
||||
if gaiResult != 0'i32:
|
||||
when defined(windows):
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
else:
|
||||
OSError($gai_strerror(gaiResult))
|
||||
|
||||
@@ -423,7 +422,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
|
||||
name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
|
||||
if bindSocket(socket.fd, cast[ptr TSockAddr](addr(name)),
|
||||
sizeof(name).TSockLen) < 0'i32:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
else:
|
||||
var hints: TAddrInfo
|
||||
var aiList: ptr TAddrInfo = nil
|
||||
@@ -432,21 +431,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
|
||||
hints.ai_protocol = toInt(IPPROTO_TCP)
|
||||
gaiNim(address, port, hints, aiList)
|
||||
if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrLen.TSockLen) < 0'i32:
|
||||
OSError()
|
||||
|
||||
when false:
|
||||
proc bindAddr*(socket: TSocket, port = TPort(0)) =
|
||||
## binds a port number to a socket.
|
||||
var name: Tsockaddr_in
|
||||
when defined(Windows):
|
||||
name.sin_family = int16(ord(AF_INET))
|
||||
else:
|
||||
name.sin_family = posix.AF_INET
|
||||
name.sin_port = sockets.htons(int16(port))
|
||||
name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
|
||||
if bindSocket(cint(socket), cast[ptr TSockAddr](addr(name)),
|
||||
sizeof(name).TSockLen) < 0'i32:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
|
||||
proc getSockName*(socket: TSocket): TPort =
|
||||
## returns the socket's associated port number.
|
||||
@@ -460,7 +445,7 @@ proc getSockName*(socket: TSocket): TPort =
|
||||
var namelen = sizeof(name).TSockLen
|
||||
if getsockname(socket.fd, cast[ptr TSockAddr](addr(name)),
|
||||
addr(namelen)) == -1'i32:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
result = TPort(sockets.ntohs(name.sin_port))
|
||||
|
||||
template acceptAddrPlain(noClientRet, successRet: expr,
|
||||
@@ -472,26 +457,25 @@ template acceptAddrPlain(noClientRet, successRet: expr,
|
||||
addr(addrLen))
|
||||
|
||||
if sock < 0:
|
||||
# TODO: Test on Windows.
|
||||
let err = OSLastError()
|
||||
when defined(windows):
|
||||
var err = WSAGetLastError()
|
||||
if err == WSAEINPROGRESS:
|
||||
if err.int32 == WSAEINPROGRESS:
|
||||
client = InvalidSocket
|
||||
address = ""
|
||||
when noClientRet.int == -1:
|
||||
return
|
||||
else:
|
||||
return noClientRet
|
||||
else: OSError()
|
||||
else: OSError(err)
|
||||
else:
|
||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
||||
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
|
||||
client = InvalidSocket
|
||||
address = ""
|
||||
when noClientRet.int == -1:
|
||||
return
|
||||
else:
|
||||
return noClientRet
|
||||
else: OSError()
|
||||
else: OSError(err)
|
||||
else:
|
||||
client.fd = sock
|
||||
client.isBuffered = server.isBuffered
|
||||
@@ -644,7 +628,7 @@ proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
|
||||
var s = winlean.getservbyname(name, proto)
|
||||
else:
|
||||
var s = posix.getservbyname(name, proto)
|
||||
if s == nil: OSError()
|
||||
if s == nil: OSError(OSLastError())
|
||||
result.name = $s.s_name
|
||||
result.aliases = cstringArrayToSeq(s.s_aliases)
|
||||
result.port = TPort(s.s_port)
|
||||
@@ -656,7 +640,7 @@ proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} =
|
||||
var s = winlean.getservbyport(ze(int16(port)).cint, proto)
|
||||
else:
|
||||
var s = posix.getservbyport(ze(int16(port)).cint, proto)
|
||||
if s == nil: OSError()
|
||||
if s == nil: OSError(OSLastError())
|
||||
result.name = $s.s_name
|
||||
result.aliases = cstringArrayToSeq(s.s_aliases)
|
||||
result.port = TPort(s.s_port)
|
||||
@@ -670,7 +654,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
|
||||
when defined(windows):
|
||||
var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
|
||||
cint(sockets.AF_INET))
|
||||
if s == nil: OSError()
|
||||
if s == nil: OSError(OSLastError())
|
||||
else:
|
||||
var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSockLen,
|
||||
cint(posix.AF_INET))
|
||||
@@ -687,7 +671,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
|
||||
elif s.h_addrtype == posix.AF_INET6:
|
||||
result.addrType = AF_INET6
|
||||
else:
|
||||
OSError("unknown h_addrtype")
|
||||
raise newException(EOS, "unknown h_addrtype")
|
||||
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
||||
result.length = int(s.h_length)
|
||||
|
||||
@@ -697,7 +681,7 @@ proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
|
||||
var s = winlean.gethostbyname(name)
|
||||
else:
|
||||
var s = posix.gethostbyname(name)
|
||||
if s == nil: OSError()
|
||||
if s == nil: OSError(OSLastError())
|
||||
result.name = $s.h_name
|
||||
result.aliases = cstringArrayToSeq(s.h_aliases)
|
||||
when defined(windows):
|
||||
@@ -708,7 +692,7 @@ proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
|
||||
elif s.h_addrtype == posix.AF_INET6:
|
||||
result.addrType = AF_INET6
|
||||
else:
|
||||
OSError("unknown h_addrtype")
|
||||
raise newException(EOS, "unknown h_addrtype")
|
||||
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
||||
result.length = int(s.h_length)
|
||||
|
||||
@@ -719,7 +703,7 @@ proc getSockOptInt*(socket: TSocket, level, optname: int): int {.
|
||||
var size = sizeof(res).TSockLen
|
||||
if getsockopt(socket.fd, cint(level), cint(optname),
|
||||
addr(res), addr(size)) < 0'i32:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
result = int(res)
|
||||
|
||||
proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
|
||||
@@ -728,7 +712,7 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
|
||||
var value = cint(optval)
|
||||
if setsockopt(socket.fd, cint(level), cint(optname), addr(value),
|
||||
sizeof(value).TSockLen) < 0'i32:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
|
||||
proc connect*(socket: TSocket, address: string, port = TPort(0),
|
||||
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
||||
@@ -746,15 +730,17 @@ proc connect*(socket: TSocket, address: string, port = TPort(0),
|
||||
gaiNim(address, port, hints, aiList)
|
||||
# try all possibilities:
|
||||
var success = false
|
||||
var lastError: TOSErrorCode
|
||||
var it = aiList
|
||||
while it != nil:
|
||||
if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen) == 0'i32:
|
||||
success = true
|
||||
break
|
||||
else: lastError = OSLastError()
|
||||
it = it.ai_next
|
||||
|
||||
freeaddrinfo(aiList)
|
||||
if not success: OSError()
|
||||
if not success: OSError(lastError)
|
||||
|
||||
when defined(ssl):
|
||||
if socket.isSSL:
|
||||
@@ -807,6 +793,7 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
|
||||
gaiNim(name, port, hints, aiList)
|
||||
# try all possibilities:
|
||||
var success = false
|
||||
var lastError: TOSErrorCode
|
||||
var it = aiList
|
||||
while it != nil:
|
||||
var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen)
|
||||
@@ -814,22 +801,21 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
|
||||
success = true
|
||||
break
|
||||
else:
|
||||
# TODO: Test on Windows.
|
||||
lastError = OSLastError()
|
||||
when defined(windows):
|
||||
var err = WSAGetLastError()
|
||||
# Windows EINTR doesn't behave same as POSIX.
|
||||
if err == WSAEWOULDBLOCK:
|
||||
if lastError.int32 == WSAEWOULDBLOCK:
|
||||
success = true
|
||||
break
|
||||
else:
|
||||
if errno == EINTR or errno == EINPROGRESS:
|
||||
if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
|
||||
success = true
|
||||
break
|
||||
|
||||
it = it.ai_next
|
||||
|
||||
freeaddrinfo(aiList)
|
||||
if not success: OSError()
|
||||
if not success: OSError(lastError)
|
||||
when defined(ssl):
|
||||
if socket.isSSL:
|
||||
socket.sslNoHandshake = true
|
||||
@@ -1110,7 +1096,7 @@ proc waitFor(socket: TSocket, waited: var float, timeout, size: int,
|
||||
var s = @[socket]
|
||||
var startTime = epochTime()
|
||||
let selRet = select(s, timeout - int(waited * 1000.0))
|
||||
if selRet < 0: OSError()
|
||||
if selRet < 0: OSError(OSLastError())
|
||||
if selRet != 1:
|
||||
raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
|
||||
waited += (epochTime() - startTime)
|
||||
@@ -1259,14 +1245,14 @@ proc readLine*(socket: TSocket, line: var TaintedString, timeout = -1) {.
|
||||
var c: char
|
||||
discard waitFor(socket, waited, timeout, 1, "readLine")
|
||||
var n = recv(socket, addr(c), 1)
|
||||
if n < 0: OSError()
|
||||
if n < 0: OSError(OSLastError())
|
||||
elif n == 0: return
|
||||
if c == '\r':
|
||||
discard waitFor(socket, waited, timeout, 1, "readLine")
|
||||
n = peekChar(socket, c)
|
||||
if n > 0 and c == '\L':
|
||||
discard recv(socket, addr(c), 1)
|
||||
elif n <= 0: OSError()
|
||||
elif n <= 0: OSError(OSLastError())
|
||||
addNlIfEmpty()
|
||||
return
|
||||
elif c == '\L':
|
||||
@@ -1326,6 +1312,7 @@ proc readLineAsync*(socket: TSocket,
|
||||
while true:
|
||||
var c: char
|
||||
var n = recv(socket, addr(c), 1)
|
||||
#echo(n)
|
||||
if n < 0:
|
||||
if line.len == 0: errorOrNone else: return ReadPartialLine
|
||||
elif n == 0:
|
||||
@@ -1352,7 +1339,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} =
|
||||
var pos = 0
|
||||
while true:
|
||||
var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1)
|
||||
if bytesRead == -1: OSError()
|
||||
if bytesRead == -1: OSError(OSLastError())
|
||||
setLen(result.string, pos + bytesRead)
|
||||
if bytesRead != bufSize-1: break
|
||||
# increase capacity:
|
||||
@@ -1364,7 +1351,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} =
|
||||
while true:
|
||||
var bytesRead = recv(socket, cstring(buf), bufSize-1)
|
||||
# Error
|
||||
if bytesRead == -1: OSError()
|
||||
if bytesRead == -1: OSError(OSLastError())
|
||||
|
||||
buf[bytesRead] = '\0' # might not be necessary
|
||||
setLen(buf, bytesRead)
|
||||
@@ -1421,16 +1408,15 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool {.
|
||||
else: SSLError("Unknown Error")
|
||||
|
||||
if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false):
|
||||
let err = OSLastError()
|
||||
when defined(windows):
|
||||
# TODO: Test on Windows
|
||||
var err = WSAGetLastError()
|
||||
if err == WSAEWOULDBLOCK:
|
||||
if err.int32 == WSAEWOULDBLOCK:
|
||||
return False
|
||||
else: OSError()
|
||||
else: OSError(err)
|
||||
else:
|
||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
||||
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
|
||||
return False
|
||||
else: OSError()
|
||||
else: OSError(err)
|
||||
|
||||
setLen(s.string, pos + bytesRead)
|
||||
if bytesRead != bufSize-1: break
|
||||
@@ -1475,16 +1461,15 @@ proc recvFromAsync*(socket: TSocket, data: var String, length: int,
|
||||
result = true
|
||||
var callRes = recvFrom(socket, data, length, address, port, flags)
|
||||
if callRes < 0:
|
||||
let err = OSLastError()
|
||||
when defined(windows):
|
||||
# TODO: Test on Windows
|
||||
var err = WSAGetLastError()
|
||||
if err == WSAEWOULDBLOCK:
|
||||
if err.int32 == WSAEWOULDBLOCK:
|
||||
return False
|
||||
else: OSError()
|
||||
else: OSError(err)
|
||||
else:
|
||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
||||
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
|
||||
return False
|
||||
else: OSError()
|
||||
else: OSError(err)
|
||||
|
||||
proc skip*(socket: TSocket) {.tags: [FReadIO], deprecated.} =
|
||||
## skips all the data that is pending for the socket
|
||||
@@ -1531,7 +1516,7 @@ proc send*(socket: TSocket, data: string) {.tags: [FWriteIO].} =
|
||||
if socket.isSSL:
|
||||
SSLError()
|
||||
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
|
||||
proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} =
|
||||
## sends data to a non-blocking socket.
|
||||
@@ -1561,16 +1546,15 @@ proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} =
|
||||
else:
|
||||
return
|
||||
if result == -1:
|
||||
let err = OSLastError()
|
||||
when defined(windows):
|
||||
var err = WSAGetLastError()
|
||||
# TODO: Test on windows.
|
||||
if err == WSAEINPROGRESS:
|
||||
if err.int32 == WSAEINPROGRESS:
|
||||
return 0
|
||||
else: OSError()
|
||||
else: OSError(err)
|
||||
else:
|
||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
||||
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
|
||||
return 0
|
||||
else: OSError()
|
||||
else: OSError(err)
|
||||
|
||||
|
||||
proc trySend*(socket: TSocket, data: string): bool {.tags: [FWriteIO].} =
|
||||
@@ -1626,15 +1610,15 @@ proc setBlocking(s: TSocket, blocking: bool) =
|
||||
when defined(Windows):
|
||||
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
|
||||
if ioctlsocket(TWinSocket(s.fd), FIONBIO, addr(mode)) == -1:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
else: # BSD sockets
|
||||
var x: int = fcntl(s.fd, F_GETFL, 0)
|
||||
if x == -1:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
else:
|
||||
var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
|
||||
if fcntl(s.fd, F_SETFL, mode) == -1:
|
||||
OSError()
|
||||
OSError(OSLastError())
|
||||
s.nonblocking = not blocking
|
||||
|
||||
proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int,
|
||||
@@ -1665,6 +1649,6 @@ proc getFD*(socket: TSocket): cint = return socket.fd
|
||||
|
||||
when defined(Windows):
|
||||
var wsa: TWSADATA
|
||||
if WSAStartup(0x0101'i16, wsa) != 0: OSError()
|
||||
if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
|
||||
|
||||
|
||||
|
||||
@@ -1,312 +1,310 @@
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module contains a few procedures to control the *terminal*
|
||||
## (also called *console*). On UNIX, the implementation simply uses ANSI escape
|
||||
## sequences and does not depend on any other module, on Windows it uses the
|
||||
## Windows API.
|
||||
## Changing the style is permanent even after program termination! Use the
|
||||
## code ``system.addQuitProc(resetAttributes)`` to restore the defaults.
|
||||
|
||||
import macros
|
||||
|
||||
when defined(windows):
|
||||
import windows, os
|
||||
|
||||
var
|
||||
conHandle: THandle
|
||||
# = createFile("CONOUT$", GENERIC_WRITE, 0, nil, OPEN_ALWAYS, 0, 0)
|
||||
|
||||
block:
|
||||
var hTemp = GetStdHandle(STD_OUTPUT_HANDLE)
|
||||
if DuplicateHandle(GetCurrentProcess(), hTemp, GetCurrentProcess(),
|
||||
addr(conHandle), 0, 1, DUPLICATE_SAME_ACCESS) == 0:
|
||||
OSError()
|
||||
|
||||
proc getCursorPos(): tuple [x,y: int] =
|
||||
var c: TCONSOLE_SCREEN_BUFFER_INFO
|
||||
if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: OSError()
|
||||
return (int(c.dwCursorPosition.x), int(c.dwCursorPosition.y))
|
||||
|
||||
proc getAttributes(): int16 =
|
||||
var c: TCONSOLE_SCREEN_BUFFER_INFO
|
||||
# workaround Windows bugs: try several times
|
||||
if GetConsoleScreenBufferInfo(conHandle, addr(c)) != 0:
|
||||
return c.wAttributes
|
||||
else:
|
||||
OSError()
|
||||
return 0x70'i16 # ERROR: return white background, black text
|
||||
|
||||
var
|
||||
oldAttr = getAttributes()
|
||||
|
||||
proc setCursorPos*(x, y: int) =
|
||||
## sets the terminal's cursor to the (x,y) position. (0,0) is the
|
||||
## upper left of the screen.
|
||||
when defined(windows):
|
||||
var c: TCoord
|
||||
c.x = int16(x)
|
||||
c.y = int16(y)
|
||||
if SetConsoleCursorPosition(conHandle, c) == 0: OSError()
|
||||
else:
|
||||
stdout.write("\e[" & $y & ';' & $x & 'f')
|
||||
|
||||
proc setCursorXPos*(x: int) =
|
||||
## sets the terminal's cursor to the x position. The y position is
|
||||
## not changed.
|
||||
when defined(windows):
|
||||
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
||||
var hStdout = conHandle
|
||||
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()
|
||||
var origin = scrbuf.dwCursorPosition
|
||||
origin.x = int16(x)
|
||||
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError()
|
||||
else:
|
||||
stdout.write("\e[" & $x & 'G')
|
||||
|
||||
when defined(windows):
|
||||
proc setCursorYPos*(y: int) =
|
||||
## sets the terminal's cursor to the y position. The x position is
|
||||
## not changed. **Warning**: This is not supported on UNIX!
|
||||
when defined(windows):
|
||||
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
||||
var hStdout = conHandle
|
||||
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()
|
||||
var origin = scrbuf.dwCursorPosition
|
||||
origin.y = int16(y)
|
||||
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError()
|
||||
else:
|
||||
nil
|
||||
|
||||
proc CursorUp*(count=1) =
|
||||
## Moves the cursor up by `count` rows.
|
||||
when defined(windows):
|
||||
var p = getCursorPos()
|
||||
dec(p.y, count)
|
||||
setCursorPos(p.x, p.y)
|
||||
else:
|
||||
stdout.write("\e[" & $count & 'A')
|
||||
|
||||
proc CursorDown*(count=1) =
|
||||
## Moves the cursor down by `count` rows.
|
||||
when defined(windows):
|
||||
var p = getCursorPos()
|
||||
inc(p.y, count)
|
||||
setCursorPos(p.x, p.y)
|
||||
else:
|
||||
stdout.write("\e[" & $count & 'B')
|
||||
|
||||
proc CursorForward*(count=1) =
|
||||
## Moves the cursor forward by `count` columns.
|
||||
when defined(windows):
|
||||
var p = getCursorPos()
|
||||
inc(p.x, count)
|
||||
setCursorPos(p.x, p.y)
|
||||
else:
|
||||
stdout.write("\e[" & $count & 'C')
|
||||
|
||||
proc CursorBackward*(count=1) =
|
||||
## Moves the cursor backward by `count` columns.
|
||||
when defined(windows):
|
||||
var p = getCursorPos()
|
||||
dec(p.x, count)
|
||||
setCursorPos(p.x, p.y)
|
||||
else:
|
||||
stdout.write("\e[" & $count & 'D')
|
||||
|
||||
when true:
|
||||
nil
|
||||
else:
|
||||
proc EraseLineEnd* =
|
||||
## Erases from the current cursor position to the end of the current line.
|
||||
when defined(windows):
|
||||
nil
|
||||
else:
|
||||
stdout.write("\e[K")
|
||||
|
||||
proc EraseLineStart* =
|
||||
## Erases from the current cursor position to the start of the current line.
|
||||
when defined(windows):
|
||||
nil
|
||||
else:
|
||||
stdout.write("\e[1K")
|
||||
|
||||
proc EraseDown* =
|
||||
## Erases the screen from the current line down to the bottom of the screen.
|
||||
when defined(windows):
|
||||
nil
|
||||
else:
|
||||
stdout.write("\e[J")
|
||||
|
||||
proc EraseUp* =
|
||||
## Erases the screen from the current line up to the top of the screen.
|
||||
when defined(windows):
|
||||
nil
|
||||
else:
|
||||
stdout.write("\e[1J")
|
||||
|
||||
proc EraseLine* =
|
||||
## Erases the entire current line.
|
||||
when defined(windows):
|
||||
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
||||
var numwrote: DWORD
|
||||
var hStdout = conHandle
|
||||
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()
|
||||
var origin = scrbuf.dwCursorPosition
|
||||
origin.x = 0'i16
|
||||
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError()
|
||||
var ht = scrbuf.dwSize.Y - origin.Y
|
||||
var wt = scrbuf.dwSize.X - origin.X
|
||||
if FillConsoleOutputCharacter(hStdout,' ', ht*wt,
|
||||
origin, addr(numwrote)) == 0:
|
||||
OSError()
|
||||
if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, ht * wt,
|
||||
scrbuf.dwCursorPosition, addr(numwrote)) == 0:
|
||||
OSError()
|
||||
else:
|
||||
stdout.write("\e[2K")
|
||||
setCursorXPos(0)
|
||||
|
||||
proc EraseScreen* =
|
||||
## Erases the screen with the background colour and moves the cursor to home.
|
||||
when defined(windows):
|
||||
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
||||
var numwrote: DWORD
|
||||
var origin: TCoord # is inititalized to 0, 0
|
||||
var hStdout = conHandle
|
||||
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()
|
||||
if FillConsoleOutputCharacter(hStdout, ' ', scrbuf.dwSize.X*scrbuf.dwSize.Y,
|
||||
origin, addr(numwrote)) == 0:
|
||||
OSError()
|
||||
if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes,
|
||||
scrbuf.dwSize.X * scrbuf.dwSize.Y,
|
||||
origin, addr(numwrote)) == 0:
|
||||
OSError()
|
||||
setCursorXPos(0)
|
||||
else:
|
||||
stdout.write("\e[2J")
|
||||
|
||||
proc ResetAttributes* {.noconv.} =
|
||||
## resets all attributes; it is advisable to register this as a quit proc
|
||||
## with ``system.addQuitProc(resetAttributes)``.
|
||||
when defined(windows):
|
||||
discard SetConsoleTextAttribute(conHandle, oldAttr)
|
||||
else:
|
||||
stdout.write("\e[0m")
|
||||
|
||||
type
|
||||
TStyle* = enum ## different styles for text output
|
||||
styleBright = 1, ## bright text
|
||||
styleDim, ## dim text
|
||||
styleUnknown, ## unknown
|
||||
styleUnderscore = 4, ## underscored text
|
||||
styleBlink, ## blinking/bold text
|
||||
styleReverse = 7, ## unknown
|
||||
styleHidden ## hidden text
|
||||
|
||||
when not defined(windows):
|
||||
var
|
||||
# XXX: These better be thread-local
|
||||
gFG = 0
|
||||
gBG = 0
|
||||
|
||||
proc setStyle*(style: set[TStyle]) =
|
||||
## sets the terminal style
|
||||
when defined(windows):
|
||||
var a = 0'i16
|
||||
if styleBright in style: a = a or int16(FOREGROUND_INTENSITY)
|
||||
if styleBlink in style: a = a or int16(BACKGROUND_INTENSITY)
|
||||
if styleReverse in style: a = a or 0x4000'i16 # COMMON_LVB_REVERSE_VIDEO
|
||||
if styleUnderscore in style: a = a or 0x8000'i16 # COMMON_LVB_UNDERSCORE
|
||||
discard SetConsoleTextAttribute(conHandle, a)
|
||||
else:
|
||||
for s in items(style):
|
||||
stdout.write("\e[" & $ord(s) & 'm')
|
||||
|
||||
proc WriteStyled*(txt: string, style: set[TStyle] = {styleBright}) =
|
||||
## writes the text `txt` in a given `style`.
|
||||
when defined(windows):
|
||||
var old = getAttributes()
|
||||
setStyle(style)
|
||||
stdout.write(txt)
|
||||
discard SetConsoleTextAttribute(conHandle, old)
|
||||
else:
|
||||
setStyle(style)
|
||||
stdout.write(txt)
|
||||
resetAttributes()
|
||||
if gFG != 0:
|
||||
stdout.write("\e[" & $ord(gFG) & 'm')
|
||||
if gBG != 0:
|
||||
stdout.write("\e[" & $ord(gBG) & 'm')
|
||||
|
||||
type
|
||||
TForegroundColor* = enum ## terminal's foreground colors
|
||||
fgBlack = 30, ## black
|
||||
fgRed, ## red
|
||||
fgGreen, ## green
|
||||
fgYellow, ## yellow
|
||||
fgBlue, ## blue
|
||||
fgMagenta, ## magenta
|
||||
fgCyan, ## cyan
|
||||
fgWhite ## white
|
||||
|
||||
TBackgroundColor* = enum ## terminal's background colors
|
||||
bgBlack = 40, ## black
|
||||
bgRed, ## red
|
||||
bgGreen, ## green
|
||||
bgYellow, ## yellow
|
||||
bgBlue, ## blue
|
||||
bgMagenta, ## magenta
|
||||
bgCyan, ## cyan
|
||||
bgWhite ## white
|
||||
|
||||
proc setForegroundColor*(fg: TForegroundColor, bright=false) =
|
||||
## sets the terminal's foreground color
|
||||
when defined(windows):
|
||||
var old = getAttributes() and not 0x0007
|
||||
if bright:
|
||||
old = old or FOREGROUND_INTENSITY
|
||||
const lookup: array [TForegroundColor, int] = [
|
||||
0,
|
||||
(FOREGROUND_RED),
|
||||
(FOREGROUND_GREEN),
|
||||
(FOREGROUND_RED or FOREGROUND_GREEN),
|
||||
(FOREGROUND_BLUE),
|
||||
(FOREGROUND_RED or FOREGROUND_BLUE),
|
||||
(FOREGROUND_BLUE or FOREGROUND_GREEN),
|
||||
(FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED)]
|
||||
discard SetConsoleTextAttribute(conHandle, toU16(old or lookup[fg]))
|
||||
else:
|
||||
gFG = ord(fg)
|
||||
if bright: inc(gFG, 60)
|
||||
stdout.write("\e[" & $gFG & 'm')
|
||||
|
||||
proc setBackgroundColor*(bg: TBackgroundColor, bright=false) =
|
||||
## sets the terminal's background color
|
||||
when defined(windows):
|
||||
var old = getAttributes() and not 0x0070
|
||||
if bright:
|
||||
old = old or BACKGROUND_INTENSITY
|
||||
const lookup: array [TBackgroundColor, int] = [
|
||||
0,
|
||||
(BACKGROUND_RED),
|
||||
(BACKGROUND_GREEN),
|
||||
(BACKGROUND_RED or BACKGROUND_GREEN),
|
||||
(BACKGROUND_BLUE),
|
||||
(BACKGROUND_RED or BACKGROUND_BLUE),
|
||||
(BACKGROUND_BLUE or BACKGROUND_GREEN),
|
||||
(BACKGROUND_BLUE or BACKGROUND_GREEN or BACKGROUND_RED)]
|
||||
discard SetConsoleTextAttribute(conHandle, toU16(old or lookup[bg]))
|
||||
else:
|
||||
gBG = ord(bg)
|
||||
if bright: inc(gBG, 60)
|
||||
stdout.write("\e[" & $gBG & 'm')
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module contains a few procedures to control the *terminal*
|
||||
## (also called *console*). On UNIX, the implementation simply uses ANSI escape
|
||||
## sequences and does not depend on any other module, on Windows it uses the
|
||||
## Windows API.
|
||||
## Changing the style is permanent even after program termination! Use the
|
||||
## code ``system.addQuitProc(resetAttributes)`` to restore the defaults.
|
||||
|
||||
import macros
|
||||
|
||||
when defined(windows):
|
||||
import windows, os
|
||||
|
||||
var
|
||||
conHandle: THandle
|
||||
# = createFile("CONOUT$", GENERIC_WRITE, 0, nil, OPEN_ALWAYS, 0, 0)
|
||||
|
||||
block:
|
||||
var hTemp = GetStdHandle(STD_OUTPUT_HANDLE)
|
||||
if DuplicateHandle(GetCurrentProcess(), hTemp, GetCurrentProcess(),
|
||||
addr(conHandle), 0, 1, DUPLICATE_SAME_ACCESS) == 0:
|
||||
OSError(OSLastError())
|
||||
|
||||
proc getCursorPos(): tuple [x,y: int] =
|
||||
var c: TCONSOLE_SCREEN_BUFFER_INFO
|
||||
if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: OSError(OSLastError())
|
||||
return (int(c.dwCursorPosition.x), int(c.dwCursorPosition.y))
|
||||
|
||||
proc getAttributes(): int16 =
|
||||
var c: TCONSOLE_SCREEN_BUFFER_INFO
|
||||
# workaround Windows bugs: try several times
|
||||
if GetConsoleScreenBufferInfo(conHandle, addr(c)) != 0:
|
||||
return c.wAttributes
|
||||
return 0x70'i16 # ERROR: return white background, black text
|
||||
|
||||
var
|
||||
oldAttr = getAttributes()
|
||||
|
||||
proc setCursorPos*(x, y: int) =
|
||||
## sets the terminal's cursor to the (x,y) position. (0,0) is the
|
||||
## upper left of the screen.
|
||||
when defined(windows):
|
||||
var c: TCoord
|
||||
c.x = int16(x)
|
||||
c.y = int16(y)
|
||||
if SetConsoleCursorPosition(conHandle, c) == 0: OSError(OSLastError())
|
||||
else:
|
||||
stdout.write("\e[" & $y & ';' & $x & 'f')
|
||||
|
||||
proc setCursorXPos*(x: int) =
|
||||
## sets the terminal's cursor to the x position. The y position is
|
||||
## not changed.
|
||||
when defined(windows):
|
||||
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
||||
var hStdout = conHandle
|
||||
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError(OSLastError())
|
||||
var origin = scrbuf.dwCursorPosition
|
||||
origin.x = int16(x)
|
||||
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError(OSLastError())
|
||||
else:
|
||||
stdout.write("\e[" & $x & 'G')
|
||||
|
||||
when defined(windows):
|
||||
proc setCursorYPos*(y: int) =
|
||||
## sets the terminal's cursor to the y position. The x position is
|
||||
## not changed. **Warning**: This is not supported on UNIX!
|
||||
when defined(windows):
|
||||
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
||||
var hStdout = conHandle
|
||||
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError(OSLastError())
|
||||
var origin = scrbuf.dwCursorPosition
|
||||
origin.y = int16(y)
|
||||
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError(OSLastError())
|
||||
else:
|
||||
nil
|
||||
|
||||
proc CursorUp*(count=1) =
|
||||
## Moves the cursor up by `count` rows.
|
||||
when defined(windows):
|
||||
var p = getCursorPos()
|
||||
dec(p.y, count)
|
||||
setCursorPos(p.x, p.y)
|
||||
else:
|
||||
stdout.write("\e[" & $count & 'A')
|
||||
|
||||
proc CursorDown*(count=1) =
|
||||
## Moves the cursor down by `count` rows.
|
||||
when defined(windows):
|
||||
var p = getCursorPos()
|
||||
inc(p.y, count)
|
||||
setCursorPos(p.x, p.y)
|
||||
else:
|
||||
stdout.write("\e[" & $count & 'B')
|
||||
|
||||
proc CursorForward*(count=1) =
|
||||
## Moves the cursor forward by `count` columns.
|
||||
when defined(windows):
|
||||
var p = getCursorPos()
|
||||
inc(p.x, count)
|
||||
setCursorPos(p.x, p.y)
|
||||
else:
|
||||
stdout.write("\e[" & $count & 'C')
|
||||
|
||||
proc CursorBackward*(count=1) =
|
||||
## Moves the cursor backward by `count` columns.
|
||||
when defined(windows):
|
||||
var p = getCursorPos()
|
||||
dec(p.x, count)
|
||||
setCursorPos(p.x, p.y)
|
||||
else:
|
||||
stdout.write("\e[" & $count & 'D')
|
||||
|
||||
when true:
|
||||
nil
|
||||
else:
|
||||
proc EraseLineEnd* =
|
||||
## Erases from the current cursor position to the end of the current line.
|
||||
when defined(windows):
|
||||
nil
|
||||
else:
|
||||
stdout.write("\e[K")
|
||||
|
||||
proc EraseLineStart* =
|
||||
## Erases from the current cursor position to the start of the current line.
|
||||
when defined(windows):
|
||||
nil
|
||||
else:
|
||||
stdout.write("\e[1K")
|
||||
|
||||
proc EraseDown* =
|
||||
## Erases the screen from the current line down to the bottom of the screen.
|
||||
when defined(windows):
|
||||
nil
|
||||
else:
|
||||
stdout.write("\e[J")
|
||||
|
||||
proc EraseUp* =
|
||||
## Erases the screen from the current line up to the top of the screen.
|
||||
when defined(windows):
|
||||
nil
|
||||
else:
|
||||
stdout.write("\e[1J")
|
||||
|
||||
proc EraseLine* =
|
||||
## Erases the entire current line.
|
||||
when defined(windows):
|
||||
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
||||
var numwrote: DWORD
|
||||
var hStdout = conHandle
|
||||
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError(OSLastError())
|
||||
var origin = scrbuf.dwCursorPosition
|
||||
origin.x = 0'i16
|
||||
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError(OSLastError())
|
||||
var ht = scrbuf.dwSize.Y - origin.Y
|
||||
var wt = scrbuf.dwSize.X - origin.X
|
||||
if FillConsoleOutputCharacter(hStdout,' ', ht*wt,
|
||||
origin, addr(numwrote)) == 0:
|
||||
OSError(OSLastError())
|
||||
if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, ht * wt,
|
||||
scrbuf.dwCursorPosition, addr(numwrote)) == 0:
|
||||
OSError(OSLastError())
|
||||
else:
|
||||
stdout.write("\e[2K")
|
||||
setCursorXPos(0)
|
||||
|
||||
proc EraseScreen* =
|
||||
## Erases the screen with the background colour and moves the cursor to home.
|
||||
when defined(windows):
|
||||
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
||||
var numwrote: DWORD
|
||||
var origin: TCoord # is inititalized to 0, 0
|
||||
var hStdout = conHandle
|
||||
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError(OSLastError())
|
||||
if FillConsoleOutputCharacter(hStdout, ' ', scrbuf.dwSize.X*scrbuf.dwSize.Y,
|
||||
origin, addr(numwrote)) == 0:
|
||||
OSError(OSLastError())
|
||||
if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes,
|
||||
scrbuf.dwSize.X * scrbuf.dwSize.Y,
|
||||
origin, addr(numwrote)) == 0:
|
||||
OSError(OSLastError())
|
||||
setCursorXPos(0)
|
||||
else:
|
||||
stdout.write("\e[2J")
|
||||
|
||||
proc ResetAttributes* {.noconv.} =
|
||||
## resets all attributes; it is advisable to register this as a quit proc
|
||||
## with ``system.addQuitProc(resetAttributes)``.
|
||||
when defined(windows):
|
||||
discard SetConsoleTextAttribute(conHandle, oldAttr)
|
||||
else:
|
||||
stdout.write("\e[0m")
|
||||
|
||||
type
|
||||
TStyle* = enum ## different styles for text output
|
||||
styleBright = 1, ## bright text
|
||||
styleDim, ## dim text
|
||||
styleUnknown, ## unknown
|
||||
styleUnderscore = 4, ## underscored text
|
||||
styleBlink, ## blinking/bold text
|
||||
styleReverse = 7, ## unknown
|
||||
styleHidden ## hidden text
|
||||
|
||||
when not defined(windows):
|
||||
var
|
||||
# XXX: These better be thread-local
|
||||
gFG = 0
|
||||
gBG = 0
|
||||
|
||||
proc setStyle*(style: set[TStyle]) =
|
||||
## sets the terminal style
|
||||
when defined(windows):
|
||||
var a = 0'i16
|
||||
if styleBright in style: a = a or int16(FOREGROUND_INTENSITY)
|
||||
if styleBlink in style: a = a or int16(BACKGROUND_INTENSITY)
|
||||
if styleReverse in style: a = a or 0x4000'i16 # COMMON_LVB_REVERSE_VIDEO
|
||||
if styleUnderscore in style: a = a or 0x8000'i16 # COMMON_LVB_UNDERSCORE
|
||||
discard SetConsoleTextAttribute(conHandle, a)
|
||||
else:
|
||||
for s in items(style):
|
||||
stdout.write("\e[" & $ord(s) & 'm')
|
||||
|
||||
proc WriteStyled*(txt: string, style: set[TStyle] = {styleBright}) =
|
||||
## writes the text `txt` in a given `style`.
|
||||
when defined(windows):
|
||||
var old = getAttributes()
|
||||
setStyle(style)
|
||||
stdout.write(txt)
|
||||
discard SetConsoleTextAttribute(conHandle, old)
|
||||
else:
|
||||
setStyle(style)
|
||||
stdout.write(txt)
|
||||
resetAttributes()
|
||||
if gFG != 0:
|
||||
stdout.write("\e[" & $ord(gFG) & 'm')
|
||||
if gBG != 0:
|
||||
stdout.write("\e[" & $ord(gBG) & 'm')
|
||||
|
||||
type
|
||||
TForegroundColor* = enum ## terminal's foreground colors
|
||||
fgBlack = 30, ## black
|
||||
fgRed, ## red
|
||||
fgGreen, ## green
|
||||
fgYellow, ## yellow
|
||||
fgBlue, ## blue
|
||||
fgMagenta, ## magenta
|
||||
fgCyan, ## cyan
|
||||
fgWhite ## white
|
||||
|
||||
TBackgroundColor* = enum ## terminal's background colors
|
||||
bgBlack = 40, ## black
|
||||
bgRed, ## red
|
||||
bgGreen, ## green
|
||||
bgYellow, ## yellow
|
||||
bgBlue, ## blue
|
||||
bgMagenta, ## magenta
|
||||
bgCyan, ## cyan
|
||||
bgWhite ## white
|
||||
|
||||
proc setForegroundColor*(fg: TForegroundColor, bright=false) =
|
||||
## sets the terminal's foreground color
|
||||
when defined(windows):
|
||||
var old = getAttributes() and not 0x0007
|
||||
if bright:
|
||||
old = old or FOREGROUND_INTENSITY
|
||||
const lookup: array [TForegroundColor, int] = [
|
||||
0,
|
||||
(FOREGROUND_RED),
|
||||
(FOREGROUND_GREEN),
|
||||
(FOREGROUND_RED or FOREGROUND_GREEN),
|
||||
(FOREGROUND_BLUE),
|
||||
(FOREGROUND_RED or FOREGROUND_BLUE),
|
||||
(FOREGROUND_BLUE or FOREGROUND_GREEN),
|
||||
(FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED)]
|
||||
discard SetConsoleTextAttribute(conHandle, toU16(old or lookup[fg]))
|
||||
else:
|
||||
gFG = ord(fg)
|
||||
if bright: inc(gFG, 60)
|
||||
stdout.write("\e[" & $gFG & 'm')
|
||||
|
||||
proc setBackgroundColor*(bg: TBackgroundColor, bright=false) =
|
||||
## sets the terminal's background color
|
||||
when defined(windows):
|
||||
var old = getAttributes() and not 0x0070
|
||||
if bright:
|
||||
old = old or BACKGROUND_INTENSITY
|
||||
const lookup: array [TBackgroundColor, int] = [
|
||||
0,
|
||||
(BACKGROUND_RED),
|
||||
(BACKGROUND_GREEN),
|
||||
(BACKGROUND_RED or BACKGROUND_GREEN),
|
||||
(BACKGROUND_BLUE),
|
||||
(BACKGROUND_RED or BACKGROUND_BLUE),
|
||||
(BACKGROUND_BLUE or BACKGROUND_GREEN),
|
||||
(BACKGROUND_BLUE or BACKGROUND_GREEN or BACKGROUND_RED)]
|
||||
discard SetConsoleTextAttribute(conHandle, toU16(old or lookup[bg]))
|
||||
else:
|
||||
gBG = ord(bg)
|
||||
if bright: inc(gBG, 60)
|
||||
stdout.write("\e[" & $gBG & 'm')
|
||||
|
||||
proc isatty*(f: TFile): bool =
|
||||
## returns true if `f` is associated with a terminal device.
|
||||
@@ -318,33 +316,33 @@ proc isatty*(f: TFile): bool =
|
||||
importc: "_isatty", header: "<io.h>".}
|
||||
|
||||
result = isatty(fileHandle(f)) != 0'i32
|
||||
|
||||
proc styledEchoProcessArg(s: string) = write stdout, s
|
||||
proc styledEchoProcessArg(style: TStyle) = setStyle({style})
|
||||
proc styledEchoProcessArg(style: set[TStyle]) = setStyle style
|
||||
proc styledEchoProcessArg(color: TForegroundColor) = setForeGroundColor color
|
||||
proc styledEchoProcessArg(color: TBackgroundColor) = setBackGroundColor color
|
||||
|
||||
|
||||
proc styledEchoProcessArg(s: string) = write stdout, s
|
||||
proc styledEchoProcessArg(style: TStyle) = setStyle({style})
|
||||
proc styledEchoProcessArg(style: set[TStyle]) = setStyle style
|
||||
proc styledEchoProcessArg(color: TForegroundColor) = setForeGroundColor color
|
||||
proc styledEchoProcessArg(color: TBackgroundColor) = setBackGroundColor color
|
||||
|
||||
macro styledEcho*(m: varargs[expr]): stmt =
|
||||
## to be documented.
|
||||
let m = callsite()
|
||||
result = newNimNode(nnkStmtList)
|
||||
|
||||
for i in countup(1, m.len - 1):
|
||||
result.add(newCall(bindSym"styledEchoProcessArg", m[i]))
|
||||
|
||||
result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
|
||||
result.add(newCall(bindSym"resetAttributes"))
|
||||
|
||||
when isMainModule:
|
||||
system.addQuitProc(resetAttributes)
|
||||
write(stdout, "never mind")
|
||||
eraseLine()
|
||||
#setCursorPos(2, 2)
|
||||
writeStyled("styled text ", {styleBright, styleBlink, styleUnderscore})
|
||||
setBackGroundColor(bgCyan, true)
|
||||
setForeGroundColor(fgBlue)
|
||||
writeln(stdout, "ordinary text")
|
||||
|
||||
result = newNimNode(nnkStmtList)
|
||||
|
||||
for i in countup(1, m.len - 1):
|
||||
result.add(newCall(bindSym"styledEchoProcessArg", m[i]))
|
||||
|
||||
result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
|
||||
result.add(newCall(bindSym"resetAttributes"))
|
||||
|
||||
when isMainModule:
|
||||
system.addQuitProc(resetAttributes)
|
||||
write(stdout, "never mind")
|
||||
eraseLine()
|
||||
#setCursorPos(2, 2)
|
||||
writeStyled("styled text ", {styleBright, styleBlink, styleUnderscore})
|
||||
setBackGroundColor(bgCyan, true)
|
||||
setForeGroundColor(fgBlue)
|
||||
writeln(stdout, "ordinary text")
|
||||
|
||||
styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore})
|
||||
|
||||
@@ -489,7 +489,7 @@ proc FD_SET*(Socket: TWinSocket, FDSet: var TFDSet) =
|
||||
proc FD_ZERO*(FDSet: var TFDSet) =
|
||||
FDSet.fd_count = 0
|
||||
|
||||
proc WSAStartup*(wVersionRequired: int16, WSData: var TWSAData): cint {.
|
||||
proc WSAStartup*(wVersionRequired: int16, WSData: ptr TWSAData): cint {.
|
||||
stdcall, importc: "WSAStartup", dynlib: ws2dll.}
|
||||
|
||||
proc getaddrinfo*(nodename, servname: cstring, hints: ptr TAddrInfo,
|
||||
|
||||
@@ -27,7 +27,7 @@ type
|
||||
gshort* = cshort
|
||||
glong* = clong
|
||||
gint* = cint
|
||||
gboolean* = bool
|
||||
gboolean* = distinct gint
|
||||
guchar* = char
|
||||
gushort* = int16
|
||||
gulong* = int
|
||||
@@ -173,6 +173,12 @@ type
|
||||
TGBoxedFreeFunc* = proc (boxed: gpointer){.cdecl.}
|
||||
PGsource = pointer # I don't know and don't care
|
||||
|
||||
converter gbool*(nimbool: bool): gboolean =
|
||||
return ord(nimbool).gboolean
|
||||
|
||||
converter toBool*(gbool: gboolean): bool =
|
||||
return int(gbool) == 1
|
||||
|
||||
const
|
||||
G_TYPE_FUNDAMENTAL_SHIFT* = 2
|
||||
G_TYPE_FUNDAMENTAL_MAX* = 255 shl G_TYPE_FUNDAMENTAL_SHIFT
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
import
|
||||
glib2, atk, pango, gdk2pixbuf, gdk2
|
||||
|
||||
export gbool, toBool
|
||||
|
||||
when defined(win32):
|
||||
const
|
||||
lib = "libgtk-win32-2.0-0.dll"
|
||||
|
||||
@@ -196,7 +196,7 @@ const
|
||||
|
||||
proc SSL_library_init*(): cInt{.cdecl, dynlib: DLLSSLName, importc, discardable.}
|
||||
proc SSL_load_error_strings*(){.cdecl, dynlib: DLLSSLName, importc.}
|
||||
proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLSSLName, importc.}
|
||||
proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLUtilName, importc.}
|
||||
|
||||
proc SSLv23_client_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
|
||||
proc SSLv23_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
|
||||
@@ -262,14 +262,15 @@ proc ERR_error_string*(e: cInt, buf: cstring): cstring{.cdecl,
|
||||
proc ERR_get_error*(): cInt{.cdecl, dynlib: DLLUtilName, importc.}
|
||||
proc ERR_peek_last_error*(): cInt{.cdecl, dynlib: DLLUtilName, importc.}
|
||||
|
||||
proc OpenSSL_add_all_algorithms*(){.cdecl, dynlib: DLLSSLName, importc: "OPENSSL_add_all_algorithms_conf".}
|
||||
proc OpenSSL_add_all_algorithms*(){.cdecl, dynlib: DLLUtilName, importc: "OPENSSL_add_all_algorithms_conf".}
|
||||
|
||||
proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
proc CRYPTO_malloc_init*() =
|
||||
CRYPTO_set_mem_functions(alloc, realloc, dealloc)
|
||||
when not defined(windows):
|
||||
CRYPTO_set_mem_functions(alloc, realloc, dealloc)
|
||||
|
||||
when True:
|
||||
nil
|
||||
|
||||
@@ -32,6 +32,7 @@ Options:
|
||||
--ignoreCase, -i be case insensitive
|
||||
--ignoreStyle, -y be style insensitive
|
||||
--ext:EX1|EX2|... only search the files with the given extension(s)
|
||||
--nocolor output will be given without any colours.
|
||||
--verbose be verbose: list every processed file
|
||||
--help, -h shows this help
|
||||
--version, -v shows the version
|
||||
@@ -291,6 +292,7 @@ for kind, key, val in getopt():
|
||||
of "ignorecase", "i": incl(options, optIgnoreCase)
|
||||
of "ignorestyle", "y": incl(options, optIgnoreStyle)
|
||||
of "ext": extensions = val.split('|')
|
||||
of "nocolor": useWriteStyled = false
|
||||
of "verbose": incl(options, optVerbose)
|
||||
of "help", "h": writeHelp()
|
||||
of "version", "v": writeVersion()
|
||||
|
||||
@@ -20,7 +20,10 @@ Changes affecting backwards compatibility
|
||||
|
||||
- The scoping rules for the ``if`` statement changed for better interaction
|
||||
with the new syntactic construct ``(;)``.
|
||||
|
||||
- ``OSError`` family of procedures has been deprecated. Procedures with the same
|
||||
name but which take different parameters have been introduced. These procs now
|
||||
require an error code to be passed to them. This error code can be retrieved
|
||||
using the new ``OSLastError`` proc.
|
||||
|
||||
|
||||
Compiler Additions
|
||||
|
||||
Reference in New Issue
Block a user