Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
commit
3ff572ffcd
12 changed files with 585 additions and 485 deletions
|
|
@ -167,7 +167,7 @@ proc AsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
|
||||||
result = newAsyncSocket()
|
result = newAsyncSocket()
|
||||||
result.socket = socket(domain, typ, protocol, buffered)
|
result.socket = socket(domain, typ, protocol, buffered)
|
||||||
result.proto = protocol
|
result.proto = protocol
|
||||||
if result.socket == InvalidSocket: OSError()
|
if result.socket == InvalidSocket: OSError(OSLastError())
|
||||||
result.socket.setBlocking(false)
|
result.socket.setBlocking(false)
|
||||||
|
|
||||||
proc toAsyncSocket*(sock: TSocket, state: TInfo = SockConnected): PAsyncSocket =
|
proc toAsyncSocket*(sock: TSocket, state: TInfo = SockConnected): PAsyncSocket =
|
||||||
|
|
@ -349,7 +349,7 @@ proc acceptAddr*(server: PAsyncSocket, client: var PAsyncSocket,
|
||||||
client.sslNeedAccept = false
|
client.sslNeedAccept = false
|
||||||
client.info = SockConnected
|
client.info = SockConnected
|
||||||
|
|
||||||
if c == InvalidSocket: OSError()
|
if c == InvalidSocket: SocketError(server.socket)
|
||||||
c.setBlocking(false) # TODO: Needs to be tested.
|
c.setBlocking(false) # TODO: Needs to be tested.
|
||||||
|
|
||||||
# deleg.open is set in ``toDelegate``.
|
# deleg.open is set in ``toDelegate``.
|
||||||
|
|
@ -423,6 +423,10 @@ proc isConnecting*(s: PAsyncSocket): bool =
|
||||||
proc isClosed*(s: PAsyncSocket): bool =
|
proc isClosed*(s: PAsyncSocket): bool =
|
||||||
## Determines whether ``s`` has been closed.
|
## Determines whether ``s`` has been closed.
|
||||||
return s.info == SockClosed
|
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,
|
proc setHandleWrite*(s: PAsyncSocket,
|
||||||
handleWrite: proc (s: PAsyncSocket) {.closure.}) =
|
handleWrite: proc (s: PAsyncSocket) {.closure.}) =
|
||||||
|
|
@ -638,8 +642,7 @@ when isMainModule:
|
||||||
proc testRead(s: PAsyncSocket, no: int) =
|
proc testRead(s: PAsyncSocket, no: int) =
|
||||||
echo("Reading! " & $no)
|
echo("Reading! " & $no)
|
||||||
var data = ""
|
var data = ""
|
||||||
if not s.readLine(data):
|
if not s.readLine(data): return
|
||||||
OSError()
|
|
||||||
if data == "":
|
if data == "":
|
||||||
echo("Closing connection. " & $no)
|
echo("Closing connection. " & $no)
|
||||||
s.close()
|
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
|
FWriteDir* = object of FWriteIO ## effect that denotes a write operation to
|
||||||
## the directory structure
|
## the directory structure
|
||||||
|
|
||||||
|
TOSErrorCode* = distinct int32 ## Specifies an OS Error Code.
|
||||||
|
|
||||||
const
|
const
|
||||||
doslike = defined(windows) or defined(OS2) or defined(DOS)
|
doslike = defined(windows) or defined(OS2) or defined(DOS)
|
||||||
# DOS-like filesystem
|
# DOS-like filesystem
|
||||||
|
|
@ -171,10 +173,13 @@ const
|
||||||
## The character which separates the base filename from the extension;
|
## The character which separates the base filename from the extension;
|
||||||
## for example, the '.' in ``os.nim``.
|
## 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``.
|
## Retrieves the operating system's error flag, ``errno``.
|
||||||
## On Windows ``GetLastError`` is checked before ``errno``.
|
## On Windows ``GetLastError`` is checked before ``errno``.
|
||||||
## Returns "" if no error occured.
|
## Returns "" if no error occured.
|
||||||
|
##
|
||||||
|
## **Deprecated since version 0.9.4**: use the other ``OSErrorMsg`` proc.
|
||||||
|
|
||||||
result = ""
|
result = ""
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var err = GetLastError()
|
var err = GetLastError()
|
||||||
|
|
@ -194,17 +199,89 @@ proc OSErrorMsg*(): string {.rtl, extern: "nos$1".} =
|
||||||
if errno != 0'i32:
|
if errno != 0'i32:
|
||||||
result = $os.strerror(errno)
|
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``.
|
## raises an EOS exception with the given message ``msg``.
|
||||||
## If ``msg == ""``, the operating system's error flag
|
## If ``msg == ""``, the operating system's error flag
|
||||||
## (``errno``) is converted to a readable error message. On Windows
|
## (``errno``) is converted to a readable error message. On Windows
|
||||||
## ``GetLastError`` is checked before ``errno``.
|
## ``GetLastError`` is checked before ``errno``.
|
||||||
## If no error flag is set, the message ``unknown OS error`` is used.
|
## 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:
|
if len(msg) == 0:
|
||||||
var m = OSErrorMsg()
|
var m = OSErrorMsg()
|
||||||
raise newException(EOS, if m.len > 0: m else: "unknown OS error")
|
raise newException(EOS, if m.len > 0: m else: "unknown OS error")
|
||||||
else:
|
else:
|
||||||
raise newException(EOS, msg)
|
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 {.
|
proc UnixToNativePath*(path: string): string {.
|
||||||
noSideEffect, rtl, extern: "nos$1".} =
|
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.
|
## Returns the `file`'s last modification time.
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
var res: TStat
|
var res: TStat
|
||||||
if stat(file, res) < 0'i32: OSError()
|
if stat(file, res) < 0'i32: OSError(OSLastError())
|
||||||
return res.st_mtime
|
return res.st_mtime
|
||||||
else:
|
else:
|
||||||
var f: TWIN32_Find_Data
|
var f: TWIN32_Find_Data
|
||||||
var h = findfirstFile(file, f)
|
var h = findfirstFile(file, f)
|
||||||
if h == -1'i32: OSError()
|
if h == -1'i32: OSError(OSLastError())
|
||||||
result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime))
|
result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime))
|
||||||
findclose(h)
|
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.
|
## Returns the `file`'s last read or write access time.
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
var res: TStat
|
var res: TStat
|
||||||
if stat(file, res) < 0'i32: OSError()
|
if stat(file, res) < 0'i32: OSError(OSLastError())
|
||||||
return res.st_atime
|
return res.st_atime
|
||||||
else:
|
else:
|
||||||
var f: TWIN32_Find_Data
|
var f: TWIN32_Find_Data
|
||||||
var h = findfirstFile(file, f)
|
var h = findfirstFile(file, f)
|
||||||
if h == -1'i32: OSError()
|
if h == -1'i32: OSError(OSLastError())
|
||||||
result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime))
|
result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime))
|
||||||
findclose(h)
|
findclose(h)
|
||||||
|
|
||||||
|
|
@ -337,12 +414,12 @@ proc getCreationTime*(file: string): TTime {.rtl, extern: "nos$1".} =
|
||||||
## Returns the `file`'s creation time.
|
## Returns the `file`'s creation time.
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
var res: TStat
|
var res: TStat
|
||||||
if stat(file, res) < 0'i32: OSError()
|
if stat(file, res) < 0'i32: OSError(OSLastError())
|
||||||
return res.st_ctime
|
return res.st_ctime
|
||||||
else:
|
else:
|
||||||
var f: TWIN32_Find_Data
|
var f: TWIN32_Find_Data
|
||||||
var h = findfirstFile(file, f)
|
var h = findfirstFile(file, f)
|
||||||
if h == -1'i32: OSError()
|
if h == -1'i32: OSError(OSLastError())
|
||||||
result = winTimeToUnixTime(rdFileTime(f.ftCreationTime))
|
result = winTimeToUnixTime(rdFileTime(f.ftCreationTime))
|
||||||
findclose(h)
|
findclose(h)
|
||||||
|
|
||||||
|
|
@ -358,30 +435,30 @@ proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} =
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
var res = newWideCString("", bufsize)
|
var res = newWideCString("", bufsize)
|
||||||
var L = GetCurrentDirectoryW(bufsize, res)
|
var L = GetCurrentDirectoryW(bufsize, res)
|
||||||
if L == 0'i32: OSError()
|
if L == 0'i32: OSError(OSLastError())
|
||||||
result = res$L
|
result = res$L
|
||||||
else:
|
else:
|
||||||
result = newString(bufsize)
|
result = newString(bufsize)
|
||||||
var L = GetCurrentDirectoryA(bufsize, result)
|
var L = GetCurrentDirectoryA(bufsize, result)
|
||||||
if L == 0'i32: OSError()
|
if L == 0'i32: OSError(OSLastError())
|
||||||
setLen(result, L)
|
setLen(result, L)
|
||||||
else:
|
else:
|
||||||
result = newString(bufsize)
|
result = newString(bufsize)
|
||||||
if getcwd(result, bufsize) != nil:
|
if getcwd(result, bufsize) != nil:
|
||||||
setlen(result, c_strlen(result))
|
setlen(result, c_strlen(result))
|
||||||
else:
|
else:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
|
|
||||||
proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
|
proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
|
||||||
## Sets the `current working directory`:idx:; `EOS` is raised if
|
## Sets the `current working directory`:idx:; `EOS` is raised if
|
||||||
## `newDir` cannot been set.
|
## `newDir` cannot been set.
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
if SetCurrentDirectoryW(newWideCString(newDir)) == 0'i32: OSError()
|
if SetCurrentDirectoryW(newWideCString(newDir)) == 0'i32: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
if SetCurrentDirectoryA(newDir) == 0'i32: OSError()
|
if SetCurrentDirectoryA(newDir) == 0'i32: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
if chdir(newDir) != 0'i32: OSError()
|
if chdir(newDir) != 0'i32: OSError(OSLastError())
|
||||||
|
|
||||||
proc JoinPath*(head, tail: string): string {.
|
proc JoinPath*(head, tail: string): string {.
|
||||||
noSideEffect, rtl, extern: "nos$1".} =
|
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 res = newWideCString("", bufsize div 2)
|
||||||
var L = GetFullPathNameW(newWideCString(filename), bufsize, res, unused)
|
var L = GetFullPathNameW(newWideCString(filename), bufsize, res, unused)
|
||||||
if L <= 0'i32 or L >= bufsize:
|
if L <= 0'i32 or L >= bufsize:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
result = res$L
|
result = res$L
|
||||||
else:
|
else:
|
||||||
var unused: cstring
|
var unused: cstring
|
||||||
result = newString(bufsize)
|
result = newString(bufsize)
|
||||||
var L = GetFullPathNameA(filename, bufsize, result, unused)
|
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)
|
setLen(result, L)
|
||||||
elif defined(macosx) or defined(bsd):
|
elif defined(macosx) or defined(bsd):
|
||||||
# On Mac OS X 10.5, realpath does not allocate the buffer on its own
|
# On Mac OS X 10.5, realpath does not allocate the buffer on its own
|
||||||
var pathBuffer: cstring = newString(pathMax)
|
var pathBuffer: cstring = newString(pathMax)
|
||||||
var resultBuffer = realpath(filename, pathBuffer)
|
var resultBuffer = realpath(filename, pathBuffer)
|
||||||
if resultBuffer == nil: OSError()
|
if resultBuffer == nil: OSError(OSLastError())
|
||||||
result = $resultBuffer
|
result = $resultBuffer
|
||||||
else:
|
else:
|
||||||
var res = realpath(filename, nil)
|
var res = realpath(filename, nil)
|
||||||
if res == nil: OSError()
|
if res == nil: OSError(OSLastError())
|
||||||
result = $res
|
result = $res
|
||||||
c_free(res)
|
c_free(res)
|
||||||
|
|
||||||
|
|
@ -677,6 +754,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
|
||||||
var f1 = OpenHandle(path1)
|
var f1 = OpenHandle(path1)
|
||||||
var f2 = OpenHandle(path2)
|
var f2 = OpenHandle(path2)
|
||||||
|
|
||||||
|
var lastErr: TOSErrorCode
|
||||||
if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
|
if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
|
||||||
var fi1, fi2: TBY_HANDLE_FILE_INFORMATION
|
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
|
result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and
|
||||||
fi1.nFileIndexHigh == fi2.nFileIndexHigh and
|
fi1.nFileIndexHigh == fi2.nFileIndexHigh and
|
||||||
fi1.nFileIndexLow == fi2.nFileIndexLow
|
fi1.nFileIndexLow == fi2.nFileIndexLow
|
||||||
else: success = false
|
else:
|
||||||
else: success = false
|
lastErr = OSLastError()
|
||||||
|
success = false
|
||||||
|
else:
|
||||||
|
lastErr = OSLastError()
|
||||||
|
success = false
|
||||||
|
|
||||||
discard CloseHandle(f1)
|
discard CloseHandle(f1)
|
||||||
discard CloseHandle(f2)
|
discard CloseHandle(f2)
|
||||||
|
|
||||||
if not success: OSError()
|
if not success: OSError(lastErr)
|
||||||
else:
|
else:
|
||||||
var a, b: TStat
|
var a, b: TStat
|
||||||
if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
|
if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
result = a.st_dev == b.st_dev and a.st_ino == b.st_ino
|
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:
|
when useWinUnicode:
|
||||||
let s = newWideCString(source)
|
let s = newWideCString(source)
|
||||||
let d = newWideCString(dest)
|
let d = newWideCString(dest)
|
||||||
if CopyFileW(s, d, 0'i32) == 0'i32: OSError()
|
if CopyFileW(s, d, 0'i32) == 0'i32: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
if CopyFileA(source, dest, 0'i32) == 0'i32: OSError()
|
if CopyFileA(source, dest, 0'i32) == 0'i32: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
# generic version of copyFile which works for any platform:
|
# generic version of copyFile which works for any platform:
|
||||||
const bufSize = 8000 # better for memory manager
|
const bufSize = 8000 # better for memory manager
|
||||||
var d, s: TFile
|
var d, s: TFile
|
||||||
if not open(s, source): OSError()
|
if not open(s, source): OSError(OSLastError())
|
||||||
if not open(d, dest, fmWrite):
|
if not open(d, dest, fmWrite):
|
||||||
close(s)
|
close(s)
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
var buf = alloc(bufsize)
|
var buf = alloc(bufsize)
|
||||||
while True:
|
while True:
|
||||||
var bytesread = readBuffer(s, buf, bufsize)
|
var bytesread = readBuffer(s, buf, bufsize)
|
||||||
|
|
@ -758,7 +840,7 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
dealloc(buf)
|
dealloc(buf)
|
||||||
close(s)
|
close(s)
|
||||||
close(d)
|
close(d)
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
if bytesread != bufSize: break
|
if bytesread != bufSize: break
|
||||||
dealloc(buf)
|
dealloc(buf)
|
||||||
close(s)
|
close(s)
|
||||||
|
|
@ -767,7 +849,8 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
tags: [FReadIO, FWriteIO].} =
|
tags: [FReadIO, FWriteIO].} =
|
||||||
## Moves a file from `source` to `dest`. If this fails, `EOS` is raised.
|
## 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):
|
when not defined(ENOENT):
|
||||||
var ENOENT {.importc, header: "<errno.h>".}: cint
|
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].} =
|
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
|
||||||
## Removes the `file`. If this fails, `EOS` is raised. This does not fail
|
## Removes the `file`. If this fails, `EOS` is raised. This does not fail
|
||||||
## if the file never existed in the first place.
|
## 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",
|
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
|
||||||
tags: [FExecIO].} =
|
tags: [FExecIO].} =
|
||||||
|
|
@ -907,14 +991,14 @@ proc putEnv*(key, val: string) {.tags: [FWriteEnv].} =
|
||||||
indx = high(environment)
|
indx = high(environment)
|
||||||
when defined(unix):
|
when defined(unix):
|
||||||
if cputenv(environment[indx]) != 0'i32:
|
if cputenv(environment[indx]) != 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
var k = newWideCString(key)
|
var k = newWideCString(key)
|
||||||
var v = newWideCString(val)
|
var v = newWideCString(val)
|
||||||
if SetEnvironmentVariableW(k, v) == 0'i32: OSError()
|
if SetEnvironmentVariableW(k, v) == 0'i32: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
if SetEnvironmentVariableA(key, val) == 0'i32: OSError()
|
if SetEnvironmentVariableA(key, val) == 0'i32: OSError(OSLastError())
|
||||||
|
|
||||||
iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [FReadEnv].} =
|
iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [FReadEnv].} =
|
||||||
## Iterate over all `environments variables`:idx:. In the first component
|
## Iterate over all `environments variables`:idx:. In the first component
|
||||||
|
|
@ -1044,10 +1128,12 @@ proc rawRemoveDir(dir: string) =
|
||||||
wrapUnary(res, RemoveDirectoryW, dir)
|
wrapUnary(res, RemoveDirectoryW, dir)
|
||||||
else:
|
else:
|
||||||
var res = RemoveDirectoryA(dir)
|
var res = RemoveDirectoryA(dir)
|
||||||
if res == 0'i32 and GetLastError() != 3'i32 and
|
let lastError = OSLastError()
|
||||||
GetLastError() != 18'i32: OSError()
|
if res == 0'i32 and lastError.int32 != 3'i32 and
|
||||||
|
lastError.int32 != 18'i32 and lastError.int32 != 2'i32:
|
||||||
|
OSError(lastError)
|
||||||
else:
|
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: [
|
proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
|
||||||
FWriteDir, FReadDir].} =
|
FWriteDir, FReadDir].} =
|
||||||
|
|
@ -1065,14 +1151,14 @@ proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
|
||||||
proc rawCreateDir(dir: string) =
|
proc rawCreateDir(dir: string) =
|
||||||
when defined(unix):
|
when defined(unix):
|
||||||
if mkdir(dir, 0o711) != 0'i32 and errno != EEXIST:
|
if mkdir(dir, 0o711) != 0'i32 and errno != EEXIST:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
wrapUnary(res, CreateDirectoryW, dir)
|
wrapUnary(res, CreateDirectoryW, dir)
|
||||||
else:
|
else:
|
||||||
var res = CreateDirectoryA(dir)
|
var res = CreateDirectoryA(dir)
|
||||||
if res == 0'i32 and GetLastError() != 183'i32:
|
if res == 0'i32 and GetLastError() != 183'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
|
|
||||||
proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
|
proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
|
||||||
## Creates the `directory`:idx: `dir`.
|
## Creates the `directory`:idx: `dir`.
|
||||||
|
|
@ -1213,7 +1299,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {.
|
||||||
## permission is available in any case.
|
## permission is available in any case.
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
var a: TStat
|
var a: TStat
|
||||||
if stat(filename, a) < 0'i32: OSError()
|
if stat(filename, a) < 0'i32: OSError(OSLastError())
|
||||||
result = {}
|
result = {}
|
||||||
if (a.st_mode and S_IRUSR) != 0'i32: result.incl(fpUserRead)
|
if (a.st_mode and S_IRUSR) != 0'i32: result.incl(fpUserRead)
|
||||||
if (a.st_mode and S_IWUSR) != 0'i32: result.incl(fpUserWrite)
|
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)
|
wrapUnary(res, GetFileAttributesW, filename)
|
||||||
else:
|
else:
|
||||||
var res = GetFileAttributesA(filename)
|
var res = GetFileAttributesA(filename)
|
||||||
if res == -1'i32: OSError()
|
if res == -1'i32: OSError(OSLastError())
|
||||||
if (res and FILE_ATTRIBUTE_READONLY) != 0'i32:
|
if (res and FILE_ATTRIBUTE_READONLY) != 0'i32:
|
||||||
result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead,
|
result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead,
|
||||||
fpOthersExec, fpOthersRead}
|
fpOthersExec, fpOthersRead}
|
||||||
|
|
@ -1257,13 +1343,13 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
|
||||||
if fpOthersWrite in permissions: p = p or S_IWOTH
|
if fpOthersWrite in permissions: p = p or S_IWOTH
|
||||||
if fpOthersExec in permissions: p = p or S_IXOTH
|
if fpOthersExec in permissions: p = p or S_IXOTH
|
||||||
|
|
||||||
if chmod(filename, p) != 0: OSError()
|
if chmod(filename, p) != 0: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
wrapUnary(res, GetFileAttributesW, filename)
|
wrapUnary(res, GetFileAttributesW, filename)
|
||||||
else:
|
else:
|
||||||
var res = GetFileAttributesA(filename)
|
var res = GetFileAttributesA(filename)
|
||||||
if res == -1'i32: OSError()
|
if res == -1'i32: OSError(OSLastError())
|
||||||
if fpUserWrite in permissions:
|
if fpUserWrite in permissions:
|
||||||
res = res and not FILE_ATTRIBUTE_READONLY
|
res = res and not FILE_ATTRIBUTE_READONLY
|
||||||
else:
|
else:
|
||||||
|
|
@ -1272,7 +1358,7 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
|
||||||
wrapBinary(res2, SetFileAttributesW, filename, res)
|
wrapBinary(res2, SetFileAttributesW, filename, res)
|
||||||
else:
|
else:
|
||||||
var res2 = SetFileAttributesA(filename, res)
|
var res2 = SetFileAttributesA(filename, res)
|
||||||
if res2 == - 1'i32: OSError()
|
if res2 == - 1'i32: OSError(OSLastError())
|
||||||
|
|
||||||
proc inclFilePermissions*(filename: string,
|
proc inclFilePermissions*(filename: string,
|
||||||
permissions: set[TFilePermission]) {.
|
permissions: set[TFilePermission]) {.
|
||||||
|
|
@ -1368,6 +1454,9 @@ when defined(macosx):
|
||||||
|
|
||||||
proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} =
|
proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} =
|
||||||
## Returns the filename of the application's executable.
|
## Returns the filename of the application's executable.
|
||||||
|
##
|
||||||
|
## This procedure will resolve symlinks.
|
||||||
|
##
|
||||||
## **Note**: This does not work reliably on BSD.
|
## **Note**: This does not work reliably on BSD.
|
||||||
|
|
||||||
# Linux: /proc/<pid>/exe
|
# Linux: /proc/<pid>/exe
|
||||||
|
|
@ -1397,6 +1486,8 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} =
|
||||||
result = newString(int(size))
|
result = newString(int(size))
|
||||||
if getExecPath2(result, size):
|
if getExecPath2(result, size):
|
||||||
result = "" # error!
|
result = "" # error!
|
||||||
|
if result.len > 0:
|
||||||
|
result = result.expandFilename
|
||||||
else:
|
else:
|
||||||
# little heuristic that may work on other POSIX-like systems:
|
# little heuristic that may work on other POSIX-like systems:
|
||||||
result = string(getEnv("_"))
|
result = string(getEnv("_"))
|
||||||
|
|
@ -1443,7 +1534,7 @@ proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1",
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var a: TWin32FindData
|
var a: TWin32FindData
|
||||||
var resA = findfirstFile(file, a)
|
var resA = findfirstFile(file, a)
|
||||||
if resA == -1: OSError()
|
if resA == -1: OSError(OSLastError())
|
||||||
result = rdFileSize(a)
|
result = rdFileSize(a)
|
||||||
findclose(resA)
|
findclose(resA)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1451,7 +1542,7 @@ proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1",
|
||||||
if open(f, file):
|
if open(f, file):
|
||||||
result = getFileSize(f)
|
result = getFileSize(f)
|
||||||
close(f)
|
close(f)
|
||||||
else: OSError()
|
else: OSError(OSLastError())
|
||||||
|
|
||||||
proc findExe*(exe: string): string {.tags: [FReadDir, FReadEnv].} =
|
proc findExe*(exe: string): string {.tags: [FReadDir, FReadEnv].} =
|
||||||
## Searches for `exe` in the current working directory and then
|
## 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 zero bytes returned (EOF).
|
||||||
# TRUE and n (>0) bytes returned (good data).
|
# TRUE and n (>0) bytes returned (good data).
|
||||||
# FALSE and bytes returned undefined (system error).
|
# 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
|
s.atTheEnd = br < bufLen
|
||||||
result = br
|
result = br
|
||||||
|
|
||||||
|
|
@ -272,7 +272,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
var s = PFileHandleStream(s)
|
var s = PFileHandleStream(s)
|
||||||
var bytesWritten: int32
|
var bytesWritten: int32
|
||||||
var a = winlean.writeFile(s.handle, buffer, bufLen.cint, bytesWritten, nil)
|
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 =
|
proc newFileHandleStream(handle: THandle): PFileHandleStream =
|
||||||
new(result)
|
new(result)
|
||||||
|
|
@ -313,7 +313,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
piInheritablePipe.lpSecurityDescriptor = nil
|
piInheritablePipe.lpSecurityDescriptor = nil
|
||||||
piInheritablePipe.Binherithandle = 1
|
piInheritablePipe.Binherithandle = 1
|
||||||
if CreatePipe(Rdhandle, Wrhandle, piInheritablePipe, 1024) == 0'i32:
|
if CreatePipe(Rdhandle, Wrhandle, piInheritablePipe, 1024) == 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
|
|
||||||
proc fileClose(h: THandle) {.inline.} =
|
proc fileClose(h: THandle) {.inline.} =
|
||||||
if h > 4: discard CloseHandle(h)
|
if h > 4: discard CloseHandle(h)
|
||||||
|
|
@ -370,6 +370,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
else:
|
else:
|
||||||
success = winlean.CreateProcessA(nil,
|
success = winlean.CreateProcessA(nil,
|
||||||
cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo)
|
cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo)
|
||||||
|
let lastError = OSLastError()
|
||||||
|
|
||||||
if poParentStreams notin options:
|
if poParentStreams notin options:
|
||||||
FileClose(si.hStdInput)
|
FileClose(si.hStdInput)
|
||||||
|
|
@ -379,7 +380,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
|
|
||||||
if e != nil: dealloc(e)
|
if e != nil: dealloc(e)
|
||||||
dealloc(cmdl)
|
dealloc(cmdl)
|
||||||
if success == 0: OSError()
|
if success == 0: OSError(lastError)
|
||||||
# Close the handle now so anyone waiting is woken:
|
# Close the handle now so anyone waiting is woken:
|
||||||
discard closeHandle(procInfo.hThread)
|
discard closeHandle(procInfo.hThread)
|
||||||
result.FProcessHandle = procInfo.hProcess
|
result.FProcessHandle = procInfo.hProcess
|
||||||
|
|
@ -450,7 +451,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
var res = winlean.CreateProcessA(nil, command, nil, nil, 0,
|
var res = winlean.CreateProcessA(nil, command, nil, nil, 0,
|
||||||
NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo)
|
NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo)
|
||||||
if res == 0:
|
if res == 0:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
Process = ProcInfo.hProcess
|
Process = ProcInfo.hProcess
|
||||||
discard CloseHandle(ProcInfo.hThread)
|
discard CloseHandle(ProcInfo.hThread)
|
||||||
|
|
@ -473,7 +474,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
of WAIT_TIMEOUT:
|
of WAIT_TIMEOUT:
|
||||||
return 0
|
return 0
|
||||||
of WAIT_FAILED:
|
of WAIT_FAILED:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
var i = ret - WAIT_OBJECT_0
|
var i = ret - WAIT_OBJECT_0
|
||||||
readfds.del(i)
|
readfds.del(i)
|
||||||
|
|
@ -531,7 +532,7 @@ elif not defined(useNimRtl):
|
||||||
if poParentStreams notin options:
|
if poParentStreams notin options:
|
||||||
if pipe(p_stdin) != 0'i32 or pipe(p_stdout) != 0'i32 or
|
if pipe(p_stdin) != 0'i32 or pipe(p_stdout) != 0'i32 or
|
||||||
pipe(p_stderr) != 0'i32:
|
pipe(p_stderr) != 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
|
|
||||||
var pid: TPid
|
var pid: TPid
|
||||||
when defined(posix_spawn) and not defined(useFork):
|
when defined(posix_spawn) and not defined(useFork):
|
||||||
|
|
@ -539,7 +540,7 @@ elif not defined(useNimRtl):
|
||||||
var fops: Tposix_spawn_file_actions
|
var fops: Tposix_spawn_file_actions
|
||||||
|
|
||||||
template chck(e: expr) =
|
template chck(e: expr) =
|
||||||
if e != 0'i32: OSError()
|
if e != 0'i32: OSError(OSLastError())
|
||||||
|
|
||||||
chck posix_spawn_file_actions_init(fops)
|
chck posix_spawn_file_actions_init(fops)
|
||||||
chck posix_spawnattr_init(attr)
|
chck posix_spawnattr_init(attr)
|
||||||
|
|
@ -584,20 +585,20 @@ elif not defined(useNimRtl):
|
||||||
else:
|
else:
|
||||||
|
|
||||||
Pid = fork()
|
Pid = fork()
|
||||||
if Pid < 0: OSError()
|
if Pid < 0: OSError(OSLastError())
|
||||||
if pid == 0:
|
if pid == 0:
|
||||||
## child process:
|
## child process:
|
||||||
|
|
||||||
if poParentStreams notin options:
|
if poParentStreams notin options:
|
||||||
discard close(p_stdin[writeIdx])
|
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])
|
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])
|
discard close(p_stderr[readIdx])
|
||||||
if poStdErrToStdOut in options:
|
if poStdErrToStdOut in options:
|
||||||
if dup2(p_stdout[writeIdx], 2) < 0: OSError()
|
if dup2(p_stdout[writeIdx], 2) < 0: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
if dup2(p_stderr[writeIdx], 2) < 0: OSError()
|
if dup2(p_stderr[writeIdx], 2) < 0: OSError(OSLastError())
|
||||||
|
|
||||||
# Create a new process group
|
# Create a new process group
|
||||||
if setpgid(0, 0) == -1: quit("setpgid call failed: " & $strerror(errno))
|
if setpgid(0, 0) == -1: quit("setpgid call failed: " & $strerror(errno))
|
||||||
|
|
@ -652,10 +653,10 @@ elif not defined(useNimRtl):
|
||||||
discard close(p.errorHandle)
|
discard close(p.errorHandle)
|
||||||
|
|
||||||
proc suspend(p: PProcess) =
|
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) =
|
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 =
|
proc running(p: PProcess): bool =
|
||||||
var ret = waitPid(p.id, p.exitCode, WNOHANG)
|
var ret = waitPid(p.id, p.exitCode, WNOHANG)
|
||||||
|
|
@ -665,8 +666,8 @@ elif not defined(useNimRtl):
|
||||||
proc terminate(p: PProcess) =
|
proc terminate(p: PProcess) =
|
||||||
if kill(-p.id, SIGTERM) == 0'i32:
|
if kill(-p.id, SIGTERM) == 0'i32:
|
||||||
if p.running():
|
if p.running():
|
||||||
if kill(-p.id, SIGKILL) != 0'i32: OSError()
|
if kill(-p.id, SIGKILL) != 0'i32: OSError(OSLastError())
|
||||||
else: OSError()
|
else: OSError(OSLastError())
|
||||||
|
|
||||||
proc waitForExit(p: PProcess, timeout: int = -1): int =
|
proc waitForExit(p: PProcess, timeout: int = -1): int =
|
||||||
#if waitPid(p.id, p.exitCode, 0) == int(p.id):
|
#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 p.exitCode != -3: return p.exitCode
|
||||||
if waitPid(p.id, p.exitCode, 0) < 0:
|
if waitPid(p.id, p.exitCode, 0) < 0:
|
||||||
p.exitCode = -3
|
p.exitCode = -3
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
result = int(p.exitCode) shr 8
|
result = int(p.exitCode) shr 8
|
||||||
|
|
||||||
proc peekExitCode(p: PProcess): int =
|
proc peekExitCode(p: PProcess): int =
|
||||||
|
|
@ -690,7 +691,7 @@ elif not defined(useNimRtl):
|
||||||
proc createStream(stream: var PStream, handle: var TFileHandle,
|
proc createStream(stream: var PStream, handle: var TFileHandle,
|
||||||
fileMode: TFileMode) =
|
fileMode: TFileMode) =
|
||||||
var f: TFile
|
var f: TFile
|
||||||
if not open(f, handle, fileMode): OSError()
|
if not open(f, handle, fileMode): OSError(OSLastError())
|
||||||
stream = newFileStream(f)
|
stream = newFileStream(f)
|
||||||
|
|
||||||
proc inputStream(p: PProcess): PStream =
|
proc inputStream(p: PProcess): PStream =
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,15 @@ proc recvBufferAsync(client: PAsyncClient, L: int): TReadLineResult =
|
||||||
if ret == L:
|
if ret == L:
|
||||||
return ReadFullLine
|
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) =
|
proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) =
|
||||||
case client.mode
|
case client.mode
|
||||||
of ClientReadChar:
|
of ClientReadChar:
|
||||||
|
|
@ -206,7 +215,7 @@ proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) =
|
||||||
client.mode = ClientReadContent
|
client.mode = ClientReadContent
|
||||||
else:
|
else:
|
||||||
s.handleRequest(client.c, client.input, client.headers)
|
s.handleRequest(client.c, client.input, client.headers)
|
||||||
if not client.c.isClosed: client.c.close()
|
checkCloseSocket(client)
|
||||||
of ReadPartialLine, ReadDisconnected, ReadNone: return
|
of ReadPartialLine, ReadDisconnected, ReadNone: return
|
||||||
of ClientReadContent:
|
of ClientReadContent:
|
||||||
let L = parseInt(client.headers["CONTENT_LENGTH"])-client.input.len
|
let L = parseInt(client.headers["CONTENT_LENGTH"])-client.input.len
|
||||||
|
|
@ -215,11 +224,11 @@ proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) =
|
||||||
case ret
|
case ret
|
||||||
of ReadFullLine:
|
of ReadFullLine:
|
||||||
s.handleRequest(client.c, client.input, client.headers)
|
s.handleRequest(client.c, client.input, client.headers)
|
||||||
if not client.c.isClosed: client.c.close()
|
checkCloseSocket(client)
|
||||||
of ReadPartialLine, ReadDisconnected, ReadNone: return
|
of ReadPartialLine, ReadDisconnected, ReadNone: return
|
||||||
else:
|
else:
|
||||||
s.handleRequest(client.c, client.input, client.headers)
|
s.handleRequest(client.c, client.input, client.headers)
|
||||||
if not client.c.isClosed: client.c.close()
|
checkCloseSocket(client)
|
||||||
|
|
||||||
proc handleAccept(sock: PAsyncSocket, s: PAsyncScgiState) =
|
proc handleAccept(sock: PAsyncSocket, s: PAsyncScgiState) =
|
||||||
var client: PAsyncSocket
|
var client: PAsyncSocket
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ when defined(ssl):
|
||||||
if err == 0:
|
if err == 0:
|
||||||
raise newException(ESSL, "No error reported.")
|
raise newException(ESSL, "No error reported.")
|
||||||
if err == -1:
|
if err == -1:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
var errStr = ErrErrorString(err, nil)
|
var errStr = ErrErrorString(err, nil)
|
||||||
raise newException(ESSL, $errStr)
|
raise newException(ESSL, $errStr)
|
||||||
|
|
||||||
|
|
@ -347,24 +347,23 @@ proc SocketError*(socket: TSocket, err: int = -1, async = false) =
|
||||||
else: SSLError("Unknown Error")
|
else: SSLError("Unknown Error")
|
||||||
|
|
||||||
if err == -1 and not (when defined(ssl): socket.isSSL else: false):
|
if err == -1 and not (when defined(ssl): socket.isSSL else: false):
|
||||||
|
let lastError = OSLastError()
|
||||||
if async:
|
if async:
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
# TODO: Test on Windows
|
if lastError.int32 == WSAEWOULDBLOCK:
|
||||||
var err = WSAGetLastError()
|
|
||||||
if err == WSAEWOULDBLOCK:
|
|
||||||
return
|
return
|
||||||
else: OSError()
|
else: OSError(lastError)
|
||||||
else:
|
else:
|
||||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
if lastError.int32 == EAGAIN or lastError.int32 == EWOULDBLOCK:
|
||||||
return
|
return
|
||||||
else: OSError()
|
else: OSError(lastError)
|
||||||
else: OSError()
|
else: OSError(lastError)
|
||||||
|
|
||||||
proc listen*(socket: TSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} =
|
proc listen*(socket: TSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} =
|
||||||
## Marks ``socket`` as accepting connections.
|
## Marks ``socket`` as accepting connections.
|
||||||
## ``Backlog`` specifies the maximum length of the
|
## ``Backlog`` specifies the maximum length of the
|
||||||
## queue of pending connections.
|
## 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.} =
|
proc invalidIp4(s: string) {.noreturn, noinline.} =
|
||||||
raise newException(EInvalidValue, "invalid ip4 address: " & s)
|
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)
|
var gaiResult = getAddrInfo(a, $p, addr(h), list)
|
||||||
if gaiResult != 0'i32:
|
if gaiResult != 0'i32:
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
OSError($gai_strerror(gaiResult))
|
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)
|
name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
|
||||||
if bindSocket(socket.fd, cast[ptr TSockAddr](addr(name)),
|
if bindSocket(socket.fd, cast[ptr TSockAddr](addr(name)),
|
||||||
sizeof(name).TSockLen) < 0'i32:
|
sizeof(name).TSockLen) < 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
var hints: TAddrInfo
|
var hints: TAddrInfo
|
||||||
var aiList: ptr TAddrInfo = nil
|
var aiList: ptr TAddrInfo = nil
|
||||||
|
|
@ -432,21 +431,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
|
||||||
hints.ai_protocol = toInt(IPPROTO_TCP)
|
hints.ai_protocol = toInt(IPPROTO_TCP)
|
||||||
gaiNim(address, port, hints, aiList)
|
gaiNim(address, port, hints, aiList)
|
||||||
if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrLen.TSockLen) < 0'i32:
|
if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrLen.TSockLen) < 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
proc getSockName*(socket: TSocket): TPort =
|
proc getSockName*(socket: TSocket): TPort =
|
||||||
## returns the socket's associated port number.
|
## returns the socket's associated port number.
|
||||||
|
|
@ -460,7 +445,7 @@ proc getSockName*(socket: TSocket): TPort =
|
||||||
var namelen = sizeof(name).TSockLen
|
var namelen = sizeof(name).TSockLen
|
||||||
if getsockname(socket.fd, cast[ptr TSockAddr](addr(name)),
|
if getsockname(socket.fd, cast[ptr TSockAddr](addr(name)),
|
||||||
addr(namelen)) == -1'i32:
|
addr(namelen)) == -1'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
result = TPort(sockets.ntohs(name.sin_port))
|
result = TPort(sockets.ntohs(name.sin_port))
|
||||||
|
|
||||||
template acceptAddrPlain(noClientRet, successRet: expr,
|
template acceptAddrPlain(noClientRet, successRet: expr,
|
||||||
|
|
@ -472,26 +457,25 @@ template acceptAddrPlain(noClientRet, successRet: expr,
|
||||||
addr(addrLen))
|
addr(addrLen))
|
||||||
|
|
||||||
if sock < 0:
|
if sock < 0:
|
||||||
# TODO: Test on Windows.
|
let err = OSLastError()
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var err = WSAGetLastError()
|
if err.int32 == WSAEINPROGRESS:
|
||||||
if err == WSAEINPROGRESS:
|
|
||||||
client = InvalidSocket
|
client = InvalidSocket
|
||||||
address = ""
|
address = ""
|
||||||
when noClientRet.int == -1:
|
when noClientRet.int == -1:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
return noClientRet
|
return noClientRet
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
else:
|
else:
|
||||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
|
||||||
client = InvalidSocket
|
client = InvalidSocket
|
||||||
address = ""
|
address = ""
|
||||||
when noClientRet.int == -1:
|
when noClientRet.int == -1:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
return noClientRet
|
return noClientRet
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
else:
|
else:
|
||||||
client.fd = sock
|
client.fd = sock
|
||||||
client.isBuffered = server.isBuffered
|
client.isBuffered = server.isBuffered
|
||||||
|
|
@ -644,7 +628,7 @@ proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
|
||||||
var s = winlean.getservbyname(name, proto)
|
var s = winlean.getservbyname(name, proto)
|
||||||
else:
|
else:
|
||||||
var s = posix.getservbyname(name, proto)
|
var s = posix.getservbyname(name, proto)
|
||||||
if s == nil: OSError()
|
if s == nil: OSError(OSLastError())
|
||||||
result.name = $s.s_name
|
result.name = $s.s_name
|
||||||
result.aliases = cstringArrayToSeq(s.s_aliases)
|
result.aliases = cstringArrayToSeq(s.s_aliases)
|
||||||
result.port = TPort(s.s_port)
|
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)
|
var s = winlean.getservbyport(ze(int16(port)).cint, proto)
|
||||||
else:
|
else:
|
||||||
var s = posix.getservbyport(ze(int16(port)).cint, proto)
|
var s = posix.getservbyport(ze(int16(port)).cint, proto)
|
||||||
if s == nil: OSError()
|
if s == nil: OSError(OSLastError())
|
||||||
result.name = $s.s_name
|
result.name = $s.s_name
|
||||||
result.aliases = cstringArrayToSeq(s.s_aliases)
|
result.aliases = cstringArrayToSeq(s.s_aliases)
|
||||||
result.port = TPort(s.s_port)
|
result.port = TPort(s.s_port)
|
||||||
|
|
@ -670,7 +654,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
|
var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
|
||||||
cint(sockets.AF_INET))
|
cint(sockets.AF_INET))
|
||||||
if s == nil: OSError()
|
if s == nil: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSockLen,
|
var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSockLen,
|
||||||
cint(posix.AF_INET))
|
cint(posix.AF_INET))
|
||||||
|
|
@ -687,7 +671,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
|
||||||
elif s.h_addrtype == posix.AF_INET6:
|
elif s.h_addrtype == posix.AF_INET6:
|
||||||
result.addrType = AF_INET6
|
result.addrType = AF_INET6
|
||||||
else:
|
else:
|
||||||
OSError("unknown h_addrtype")
|
raise newException(EOS, "unknown h_addrtype")
|
||||||
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
||||||
result.length = int(s.h_length)
|
result.length = int(s.h_length)
|
||||||
|
|
||||||
|
|
@ -697,7 +681,7 @@ proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
|
||||||
var s = winlean.gethostbyname(name)
|
var s = winlean.gethostbyname(name)
|
||||||
else:
|
else:
|
||||||
var s = posix.gethostbyname(name)
|
var s = posix.gethostbyname(name)
|
||||||
if s == nil: OSError()
|
if s == nil: OSError(OSLastError())
|
||||||
result.name = $s.h_name
|
result.name = $s.h_name
|
||||||
result.aliases = cstringArrayToSeq(s.h_aliases)
|
result.aliases = cstringArrayToSeq(s.h_aliases)
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
@ -708,7 +692,7 @@ proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
|
||||||
elif s.h_addrtype == posix.AF_INET6:
|
elif s.h_addrtype == posix.AF_INET6:
|
||||||
result.addrType = AF_INET6
|
result.addrType = AF_INET6
|
||||||
else:
|
else:
|
||||||
OSError("unknown h_addrtype")
|
raise newException(EOS, "unknown h_addrtype")
|
||||||
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
||||||
result.length = int(s.h_length)
|
result.length = int(s.h_length)
|
||||||
|
|
||||||
|
|
@ -719,7 +703,7 @@ proc getSockOptInt*(socket: TSocket, level, optname: int): int {.
|
||||||
var size = sizeof(res).TSockLen
|
var size = sizeof(res).TSockLen
|
||||||
if getsockopt(socket.fd, cint(level), cint(optname),
|
if getsockopt(socket.fd, cint(level), cint(optname),
|
||||||
addr(res), addr(size)) < 0'i32:
|
addr(res), addr(size)) < 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
result = int(res)
|
result = int(res)
|
||||||
|
|
||||||
proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
|
proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
|
||||||
|
|
@ -728,7 +712,7 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
|
||||||
var value = cint(optval)
|
var value = cint(optval)
|
||||||
if setsockopt(socket.fd, cint(level), cint(optname), addr(value),
|
if setsockopt(socket.fd, cint(level), cint(optname), addr(value),
|
||||||
sizeof(value).TSockLen) < 0'i32:
|
sizeof(value).TSockLen) < 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
|
|
||||||
proc connect*(socket: TSocket, address: string, port = TPort(0),
|
proc connect*(socket: TSocket, address: string, port = TPort(0),
|
||||||
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
||||||
|
|
@ -746,15 +730,17 @@ proc connect*(socket: TSocket, address: string, port = TPort(0),
|
||||||
gaiNim(address, port, hints, aiList)
|
gaiNim(address, port, hints, aiList)
|
||||||
# try all possibilities:
|
# try all possibilities:
|
||||||
var success = false
|
var success = false
|
||||||
|
var lastError: TOSErrorCode
|
||||||
var it = aiList
|
var it = aiList
|
||||||
while it != nil:
|
while it != nil:
|
||||||
if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen) == 0'i32:
|
if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen) == 0'i32:
|
||||||
success = true
|
success = true
|
||||||
break
|
break
|
||||||
|
else: lastError = OSLastError()
|
||||||
it = it.ai_next
|
it = it.ai_next
|
||||||
|
|
||||||
freeaddrinfo(aiList)
|
freeaddrinfo(aiList)
|
||||||
if not success: OSError()
|
if not success: OSError(lastError)
|
||||||
|
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
|
|
@ -807,6 +793,7 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
|
||||||
gaiNim(name, port, hints, aiList)
|
gaiNim(name, port, hints, aiList)
|
||||||
# try all possibilities:
|
# try all possibilities:
|
||||||
var success = false
|
var success = false
|
||||||
|
var lastError: TOSErrorCode
|
||||||
var it = aiList
|
var it = aiList
|
||||||
while it != nil:
|
while it != nil:
|
||||||
var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen)
|
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
|
success = true
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# TODO: Test on Windows.
|
lastError = OSLastError()
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var err = WSAGetLastError()
|
|
||||||
# Windows EINTR doesn't behave same as POSIX.
|
# Windows EINTR doesn't behave same as POSIX.
|
||||||
if err == WSAEWOULDBLOCK:
|
if lastError.int32 == WSAEWOULDBLOCK:
|
||||||
success = true
|
success = true
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if errno == EINTR or errno == EINPROGRESS:
|
if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
|
||||||
success = true
|
success = true
|
||||||
break
|
break
|
||||||
|
|
||||||
it = it.ai_next
|
it = it.ai_next
|
||||||
|
|
||||||
freeaddrinfo(aiList)
|
freeaddrinfo(aiList)
|
||||||
if not success: OSError()
|
if not success: OSError(lastError)
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
socket.sslNoHandshake = true
|
socket.sslNoHandshake = true
|
||||||
|
|
@ -1110,7 +1096,7 @@ proc waitFor(socket: TSocket, waited: var float, timeout, size: int,
|
||||||
var s = @[socket]
|
var s = @[socket]
|
||||||
var startTime = epochTime()
|
var startTime = epochTime()
|
||||||
let selRet = select(s, timeout - int(waited * 1000.0))
|
let selRet = select(s, timeout - int(waited * 1000.0))
|
||||||
if selRet < 0: OSError()
|
if selRet < 0: OSError(OSLastError())
|
||||||
if selRet != 1:
|
if selRet != 1:
|
||||||
raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
|
raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
|
||||||
waited += (epochTime() - startTime)
|
waited += (epochTime() - startTime)
|
||||||
|
|
@ -1259,14 +1245,14 @@ proc readLine*(socket: TSocket, line: var TaintedString, timeout = -1) {.
|
||||||
var c: char
|
var c: char
|
||||||
discard waitFor(socket, waited, timeout, 1, "readLine")
|
discard waitFor(socket, waited, timeout, 1, "readLine")
|
||||||
var n = recv(socket, addr(c), 1)
|
var n = recv(socket, addr(c), 1)
|
||||||
if n < 0: OSError()
|
if n < 0: OSError(OSLastError())
|
||||||
elif n == 0: return
|
elif n == 0: return
|
||||||
if c == '\r':
|
if c == '\r':
|
||||||
discard waitFor(socket, waited, timeout, 1, "readLine")
|
discard waitFor(socket, waited, timeout, 1, "readLine")
|
||||||
n = peekChar(socket, c)
|
n = peekChar(socket, c)
|
||||||
if n > 0 and c == '\L':
|
if n > 0 and c == '\L':
|
||||||
discard recv(socket, addr(c), 1)
|
discard recv(socket, addr(c), 1)
|
||||||
elif n <= 0: OSError()
|
elif n <= 0: OSError(OSLastError())
|
||||||
addNlIfEmpty()
|
addNlIfEmpty()
|
||||||
return
|
return
|
||||||
elif c == '\L':
|
elif c == '\L':
|
||||||
|
|
@ -1326,6 +1312,7 @@ proc readLineAsync*(socket: TSocket,
|
||||||
while true:
|
while true:
|
||||||
var c: char
|
var c: char
|
||||||
var n = recv(socket, addr(c), 1)
|
var n = recv(socket, addr(c), 1)
|
||||||
|
#echo(n)
|
||||||
if n < 0:
|
if n < 0:
|
||||||
if line.len == 0: errorOrNone else: return ReadPartialLine
|
if line.len == 0: errorOrNone else: return ReadPartialLine
|
||||||
elif n == 0:
|
elif n == 0:
|
||||||
|
|
@ -1352,7 +1339,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} =
|
||||||
var pos = 0
|
var pos = 0
|
||||||
while true:
|
while true:
|
||||||
var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1)
|
var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1)
|
||||||
if bytesRead == -1: OSError()
|
if bytesRead == -1: OSError(OSLastError())
|
||||||
setLen(result.string, pos + bytesRead)
|
setLen(result.string, pos + bytesRead)
|
||||||
if bytesRead != bufSize-1: break
|
if bytesRead != bufSize-1: break
|
||||||
# increase capacity:
|
# increase capacity:
|
||||||
|
|
@ -1364,7 +1351,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} =
|
||||||
while true:
|
while true:
|
||||||
var bytesRead = recv(socket, cstring(buf), bufSize-1)
|
var bytesRead = recv(socket, cstring(buf), bufSize-1)
|
||||||
# Error
|
# Error
|
||||||
if bytesRead == -1: OSError()
|
if bytesRead == -1: OSError(OSLastError())
|
||||||
|
|
||||||
buf[bytesRead] = '\0' # might not be necessary
|
buf[bytesRead] = '\0' # might not be necessary
|
||||||
setLen(buf, bytesRead)
|
setLen(buf, bytesRead)
|
||||||
|
|
@ -1421,16 +1408,15 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool {.
|
||||||
else: SSLError("Unknown Error")
|
else: SSLError("Unknown Error")
|
||||||
|
|
||||||
if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false):
|
if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false):
|
||||||
|
let err = OSLastError()
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
# TODO: Test on Windows
|
if err.int32 == WSAEWOULDBLOCK:
|
||||||
var err = WSAGetLastError()
|
|
||||||
if err == WSAEWOULDBLOCK:
|
|
||||||
return False
|
return False
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
else:
|
else:
|
||||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
|
||||||
return False
|
return False
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
|
|
||||||
setLen(s.string, pos + bytesRead)
|
setLen(s.string, pos + bytesRead)
|
||||||
if bytesRead != bufSize-1: break
|
if bytesRead != bufSize-1: break
|
||||||
|
|
@ -1475,16 +1461,15 @@ proc recvFromAsync*(socket: TSocket, data: var String, length: int,
|
||||||
result = true
|
result = true
|
||||||
var callRes = recvFrom(socket, data, length, address, port, flags)
|
var callRes = recvFrom(socket, data, length, address, port, flags)
|
||||||
if callRes < 0:
|
if callRes < 0:
|
||||||
|
let err = OSLastError()
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
# TODO: Test on Windows
|
if err.int32 == WSAEWOULDBLOCK:
|
||||||
var err = WSAGetLastError()
|
|
||||||
if err == WSAEWOULDBLOCK:
|
|
||||||
return False
|
return False
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
else:
|
else:
|
||||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
|
||||||
return False
|
return False
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
|
|
||||||
proc skip*(socket: TSocket) {.tags: [FReadIO], deprecated.} =
|
proc skip*(socket: TSocket) {.tags: [FReadIO], deprecated.} =
|
||||||
## skips all the data that is pending for the socket
|
## 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:
|
if socket.isSSL:
|
||||||
SSLError()
|
SSLError()
|
||||||
|
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
|
|
||||||
proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} =
|
proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} =
|
||||||
## sends data to a non-blocking socket.
|
## sends data to a non-blocking socket.
|
||||||
|
|
@ -1561,16 +1546,15 @@ proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} =
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
if result == -1:
|
if result == -1:
|
||||||
|
let err = OSLastError()
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var err = WSAGetLastError()
|
if err.int32 == WSAEINPROGRESS:
|
||||||
# TODO: Test on windows.
|
|
||||||
if err == WSAEINPROGRESS:
|
|
||||||
return 0
|
return 0
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
else:
|
else:
|
||||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
|
||||||
return 0
|
return 0
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
|
|
||||||
|
|
||||||
proc trySend*(socket: TSocket, data: string): bool {.tags: [FWriteIO].} =
|
proc trySend*(socket: TSocket, data: string): bool {.tags: [FWriteIO].} =
|
||||||
|
|
@ -1626,15 +1610,15 @@ proc setBlocking(s: TSocket, blocking: bool) =
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
|
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
|
||||||
if ioctlsocket(TWinSocket(s.fd), FIONBIO, addr(mode)) == -1:
|
if ioctlsocket(TWinSocket(s.fd), FIONBIO, addr(mode)) == -1:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else: # BSD sockets
|
else: # BSD sockets
|
||||||
var x: int = fcntl(s.fd, F_GETFL, 0)
|
var x: int = fcntl(s.fd, F_GETFL, 0)
|
||||||
if x == -1:
|
if x == -1:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
|
var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
|
||||||
if fcntl(s.fd, F_SETFL, mode) == -1:
|
if fcntl(s.fd, F_SETFL, mode) == -1:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
s.nonblocking = not blocking
|
s.nonblocking = not blocking
|
||||||
|
|
||||||
proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int,
|
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):
|
when defined(Windows):
|
||||||
var wsa: TWSADATA
|
var wsa: TWSADATA
|
||||||
if WSAStartup(0x0101'i16, wsa) != 0: OSError()
|
if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,11 @@ when defined(windows):
|
||||||
var hTemp = GetStdHandle(STD_OUTPUT_HANDLE)
|
var hTemp = GetStdHandle(STD_OUTPUT_HANDLE)
|
||||||
if DuplicateHandle(GetCurrentProcess(), hTemp, GetCurrentProcess(),
|
if DuplicateHandle(GetCurrentProcess(), hTemp, GetCurrentProcess(),
|
||||||
addr(conHandle), 0, 1, DUPLICATE_SAME_ACCESS) == 0:
|
addr(conHandle), 0, 1, DUPLICATE_SAME_ACCESS) == 0:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
|
|
||||||
proc getCursorPos(): tuple [x,y: int] =
|
proc getCursorPos(): tuple [x,y: int] =
|
||||||
var c: TCONSOLE_SCREEN_BUFFER_INFO
|
var c: TCONSOLE_SCREEN_BUFFER_INFO
|
||||||
if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: OSError()
|
if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: OSError(OSLastError())
|
||||||
return (int(c.dwCursorPosition.x), int(c.dwCursorPosition.y))
|
return (int(c.dwCursorPosition.x), int(c.dwCursorPosition.y))
|
||||||
|
|
||||||
proc getAttributes(): int16 =
|
proc getAttributes(): int16 =
|
||||||
|
|
@ -39,8 +39,6 @@ when defined(windows):
|
||||||
# workaround Windows bugs: try several times
|
# workaround Windows bugs: try several times
|
||||||
if GetConsoleScreenBufferInfo(conHandle, addr(c)) != 0:
|
if GetConsoleScreenBufferInfo(conHandle, addr(c)) != 0:
|
||||||
return c.wAttributes
|
return c.wAttributes
|
||||||
else:
|
|
||||||
OSError()
|
|
||||||
return 0x70'i16 # ERROR: return white background, black text
|
return 0x70'i16 # ERROR: return white background, black text
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
@ -53,7 +51,7 @@ proc setCursorPos*(x, y: int) =
|
||||||
var c: TCoord
|
var c: TCoord
|
||||||
c.x = int16(x)
|
c.x = int16(x)
|
||||||
c.y = int16(y)
|
c.y = int16(y)
|
||||||
if SetConsoleCursorPosition(conHandle, c) == 0: OSError()
|
if SetConsoleCursorPosition(conHandle, c) == 0: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
stdout.write("\e[" & $y & ';' & $x & 'f')
|
stdout.write("\e[" & $y & ';' & $x & 'f')
|
||||||
|
|
||||||
|
|
@ -63,10 +61,10 @@ proc setCursorXPos*(x: int) =
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
||||||
var hStdout = conHandle
|
var hStdout = conHandle
|
||||||
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()
|
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError(OSLastError())
|
||||||
var origin = scrbuf.dwCursorPosition
|
var origin = scrbuf.dwCursorPosition
|
||||||
origin.x = int16(x)
|
origin.x = int16(x)
|
||||||
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError()
|
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
stdout.write("\e[" & $x & 'G')
|
stdout.write("\e[" & $x & 'G')
|
||||||
|
|
||||||
|
|
@ -77,10 +75,10 @@ when defined(windows):
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
||||||
var hStdout = conHandle
|
var hStdout = conHandle
|
||||||
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()
|
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError(OSLastError())
|
||||||
var origin = scrbuf.dwCursorPosition
|
var origin = scrbuf.dwCursorPosition
|
||||||
origin.y = int16(y)
|
origin.y = int16(y)
|
||||||
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError()
|
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
nil
|
nil
|
||||||
|
|
||||||
|
|
@ -157,18 +155,18 @@ proc EraseLine* =
|
||||||
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
|
||||||
var numwrote: DWORD
|
var numwrote: DWORD
|
||||||
var hStdout = conHandle
|
var hStdout = conHandle
|
||||||
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()
|
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError(OSLastError())
|
||||||
var origin = scrbuf.dwCursorPosition
|
var origin = scrbuf.dwCursorPosition
|
||||||
origin.x = 0'i16
|
origin.x = 0'i16
|
||||||
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError()
|
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError(OSLastError())
|
||||||
var ht = scrbuf.dwSize.Y - origin.Y
|
var ht = scrbuf.dwSize.Y - origin.Y
|
||||||
var wt = scrbuf.dwSize.X - origin.X
|
var wt = scrbuf.dwSize.X - origin.X
|
||||||
if FillConsoleOutputCharacter(hStdout,' ', ht*wt,
|
if FillConsoleOutputCharacter(hStdout,' ', ht*wt,
|
||||||
origin, addr(numwrote)) == 0:
|
origin, addr(numwrote)) == 0:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, ht * wt,
|
if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, ht * wt,
|
||||||
scrbuf.dwCursorPosition, addr(numwrote)) == 0:
|
scrbuf.dwCursorPosition, addr(numwrote)) == 0:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
stdout.write("\e[2K")
|
stdout.write("\e[2K")
|
||||||
setCursorXPos(0)
|
setCursorXPos(0)
|
||||||
|
|
@ -180,14 +178,14 @@ proc EraseScreen* =
|
||||||
var numwrote: DWORD
|
var numwrote: DWORD
|
||||||
var origin: TCoord # is inititalized to 0, 0
|
var origin: TCoord # is inititalized to 0, 0
|
||||||
var hStdout = conHandle
|
var hStdout = conHandle
|
||||||
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()
|
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError(OSLastError())
|
||||||
if FillConsoleOutputCharacter(hStdout, ' ', scrbuf.dwSize.X*scrbuf.dwSize.Y,
|
if FillConsoleOutputCharacter(hStdout, ' ', scrbuf.dwSize.X*scrbuf.dwSize.Y,
|
||||||
origin, addr(numwrote)) == 0:
|
origin, addr(numwrote)) == 0:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes,
|
if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes,
|
||||||
scrbuf.dwSize.X * scrbuf.dwSize.Y,
|
scrbuf.dwSize.X * scrbuf.dwSize.Y,
|
||||||
origin, addr(numwrote)) == 0:
|
origin, addr(numwrote)) == 0:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
setCursorXPos(0)
|
setCursorXPos(0)
|
||||||
else:
|
else:
|
||||||
stdout.write("\e[2J")
|
stdout.write("\e[2J")
|
||||||
|
|
|
||||||
|
|
@ -489,7 +489,7 @@ proc FD_SET*(Socket: TWinSocket, FDSet: var TFDSet) =
|
||||||
proc FD_ZERO*(FDSet: var TFDSet) =
|
proc FD_ZERO*(FDSet: var TFDSet) =
|
||||||
FDSet.fd_count = 0
|
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.}
|
stdcall, importc: "WSAStartup", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc getaddrinfo*(nodename, servname: cstring, hints: ptr TAddrInfo,
|
proc getaddrinfo*(nodename, servname: cstring, hints: ptr TAddrInfo,
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ type
|
||||||
gshort* = cshort
|
gshort* = cshort
|
||||||
glong* = clong
|
glong* = clong
|
||||||
gint* = cint
|
gint* = cint
|
||||||
gboolean* = bool
|
gboolean* = distinct gint
|
||||||
guchar* = char
|
guchar* = char
|
||||||
gushort* = int16
|
gushort* = int16
|
||||||
gulong* = int
|
gulong* = int
|
||||||
|
|
@ -173,6 +173,12 @@ type
|
||||||
TGBoxedFreeFunc* = proc (boxed: gpointer){.cdecl.}
|
TGBoxedFreeFunc* = proc (boxed: gpointer){.cdecl.}
|
||||||
PGsource = pointer # I don't know and don't care
|
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
|
const
|
||||||
G_TYPE_FUNDAMENTAL_SHIFT* = 2
|
G_TYPE_FUNDAMENTAL_SHIFT* = 2
|
||||||
G_TYPE_FUNDAMENTAL_MAX* = 255 shl G_TYPE_FUNDAMENTAL_SHIFT
|
G_TYPE_FUNDAMENTAL_MAX* = 255 shl G_TYPE_FUNDAMENTAL_SHIFT
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
import
|
import
|
||||||
glib2, atk, pango, gdk2pixbuf, gdk2
|
glib2, atk, pango, gdk2pixbuf, gdk2
|
||||||
|
|
||||||
|
export gbool, toBool
|
||||||
|
|
||||||
when defined(win32):
|
when defined(win32):
|
||||||
const
|
const
|
||||||
lib = "libgtk-win32-2.0-0.dll"
|
lib = "libgtk-win32-2.0-0.dll"
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ const
|
||||||
|
|
||||||
proc SSL_library_init*(): cInt{.cdecl, dynlib: DLLSSLName, importc, discardable.}
|
proc SSL_library_init*(): cInt{.cdecl, dynlib: DLLSSLName, importc, discardable.}
|
||||||
proc SSL_load_error_strings*(){.cdecl, dynlib: DLLSSLName, importc.}
|
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_client_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
proc SSLv23_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_get_error*(): cInt{.cdecl, dynlib: DLLUtilName, importc.}
|
||||||
proc ERR_peek_last_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 OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
|
||||||
proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl, dynlib: DLLSSLName, importc.}
|
proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
|
||||||
proc CRYPTO_malloc_init*() =
|
proc CRYPTO_malloc_init*() =
|
||||||
CRYPTO_set_mem_functions(alloc, realloc, dealloc)
|
when not defined(windows):
|
||||||
|
CRYPTO_set_mem_functions(alloc, realloc, dealloc)
|
||||||
|
|
||||||
when True:
|
when True:
|
||||||
nil
|
nil
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ Options:
|
||||||
--ignoreCase, -i be case insensitive
|
--ignoreCase, -i be case insensitive
|
||||||
--ignoreStyle, -y be style insensitive
|
--ignoreStyle, -y be style insensitive
|
||||||
--ext:EX1|EX2|... only search the files with the given extension(s)
|
--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
|
--verbose be verbose: list every processed file
|
||||||
--help, -h shows this help
|
--help, -h shows this help
|
||||||
--version, -v shows the version
|
--version, -v shows the version
|
||||||
|
|
@ -291,6 +292,7 @@ for kind, key, val in getopt():
|
||||||
of "ignorecase", "i": incl(options, optIgnoreCase)
|
of "ignorecase", "i": incl(options, optIgnoreCase)
|
||||||
of "ignorestyle", "y": incl(options, optIgnoreStyle)
|
of "ignorestyle", "y": incl(options, optIgnoreStyle)
|
||||||
of "ext": extensions = val.split('|')
|
of "ext": extensions = val.split('|')
|
||||||
|
of "nocolor": useWriteStyled = false
|
||||||
of "verbose": incl(options, optVerbose)
|
of "verbose": incl(options, optVerbose)
|
||||||
of "help", "h": writeHelp()
|
of "help", "h": writeHelp()
|
||||||
of "version", "v": writeVersion()
|
of "version", "v": writeVersion()
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,10 @@ Changes affecting backwards compatibility
|
||||||
|
|
||||||
- The scoping rules for the ``if`` statement changed for better interaction
|
- The scoping rules for the ``if`` statement changed for better interaction
|
||||||
with the new syntactic construct ``(;)``.
|
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
|
Compiler Additions
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue