diff options
author | Araq <rumpf_a@web.de> | 2010-11-18 22:26:20 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2010-11-18 22:26:20 +0100 |
commit | adf13aaea379d482ad4289d349a9d475bc2c06a6 (patch) | |
tree | 4c18d447545c35fa7c1f4ce7db566f96db67a080 /lib/pure | |
parent | 8ee63f98364259b2d1b6c02d050e0efccecbcf9b (diff) | |
download | Nim-adf13aaea379d482ad4289d349a9d475bc2c06a6.tar.gz |
docgen understands and ignores *when false*
Diffstat (limited to 'lib/pure')
-rwxr-xr-x | lib/pure/cgi.nim | 30 | ||||
-rw-r--r-- | lib/pure/cookies.nim | 30 | ||||
-rwxr-xr-x | lib/pure/httpserver.nim | 21 | ||||
-rwxr-xr-x | lib/pure/pegs.nim | 179 | ||||
-rwxr-xr-x | lib/pure/sockets.nim | 83 |
5 files changed, 281 insertions, 62 deletions
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index 643c67bec..af222caba 100755 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -## This module implements helper procs for CGI applictions. Example: +## This module implements helper procs for CGI applications. Example: ## ## .. code-block:: Nimrod ## @@ -29,7 +29,7 @@ ## writeln(stdout, "your password: " & myData["password"]) ## writeln(stdout, "</body></html>") -import strutils, os, strtabs +import strutils, os, strtabs, cookies proc URLencode*(s: string): string = ## Encodes a value to be HTTP safe: This means that characters in the set @@ -355,32 +355,16 @@ proc setCookie*(name, value: string) = write(stdout, "Set-Cookie: ", name, "=", value, "\n") var - cookies: PStringTable = nil - -proc parseCookies(s: string): PStringTable = - result = newStringTable(modeCaseInsensitive) - var i = 0 - while true: - while s[i] == ' ' or s[i] == '\t': inc(i) - var keystart = i - while s[i] != '=' and s[i] != '\0': inc(i) - var keyend = i-1 - if s[i] == '\0': break - inc(i) # skip '=' - var valstart = i - while s[i] != ';' and s[i] != '\0': inc(i) - result[copy(s, keystart, keyend)] = copy(s, valstart, i-1) - if s[i] == '\0': break - inc(i) # skip ';' + gcookies: PStringTable = nil proc getCookie*(name: string): string = ## Gets a cookie. If no cookie of `name` exists, "" is returned. - if cookies == nil: cookies = parseCookies(getHttpCookie()) - result = cookies[name] + if gcookies == nil: gcookies = parseCookies(getHttpCookie()) + result = gcookies[name] proc existsCookie*(name: string): bool = ## Checks if a cookie of `name` exists. - if cookies == nil: cookies = parseCookies(getHttpCookie()) - result = hasKey(cookies, name) + if gcookies == nil: gcookies = parseCookies(getHttpCookie()) + result = hasKey(gcookies, name) diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim new file mode 100644 index 000000000..eed6c7512 --- /dev/null +++ b/lib/pure/cookies.nim @@ -0,0 +1,30 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2010 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements helper procs for parsing Cookies. + +import strtabs + +proc parseCookies*(s: string): PStringTable = + ## parses cookies into a string table. + result = newStringTable(modeCaseInsensitive) + var i = 0 + while true: + while s[i] == ' ' or s[i] == '\t': inc(i) + var keystart = i + while s[i] != '=' and s[i] != '\0': inc(i) + var keyend = i-1 + if s[i] == '\0': break + inc(i) # skip '=' + var valstart = i + while s[i] != ';' and s[i] != '\0': inc(i) + result[copy(s, keystart, keyend)] = copy(s, valstart, i-1) + if s[i] == '\0': break + inc(i) # skip ';' + diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim index bff1b381d..cb36ea541 100755 --- a/lib/pure/httpserver.nim +++ b/lib/pure/httpserver.nim @@ -136,9 +136,12 @@ proc executeCgi(client: TSocket, path, query: string, meth: TRequestMethod) = if meth == reqPost: # get from client and post to CGI program: var buf = alloc(contentLength) - if recv(client, buf, contentLength) != contentLength: OSError() + if recv(client, buf, contentLength) != contentLength: + dealloc(buf) + OSError() var inp = process.inputStream inp.writeData(inp, buf, contentLength) + dealloc(buf) var outp = process.outputStream while running(process) or not outp.atEnd(outp): @@ -153,10 +156,21 @@ proc acceptRequest(client: TSocket) = var query = "" var buf = "" discard recvLine(client, buf) + var path = "" var data = buf.split() var meth = reqGet + + var q = find(data[1], '?') + + # extract path + if q >= 0: + # strip "?..." from path, this may be found in both POST and GET + path = "." & data[1].copy(0, q-1) + else: + path = "." & data[1] + # path starts with "/", by adding "." in front of it we serve files from cwd + if cmpIgnoreCase(data[0], "GET") == 0: - var q = find(data[1], '?') if q >= 0: cgi = true query = data[1].copy(q+1) @@ -166,7 +180,6 @@ proc acceptRequest(client: TSocket) = else: unimplemented(client) - var path = data[1] if path[path.len-1] == '/' or existsDir(path): path = path / "index.html" @@ -221,7 +234,7 @@ proc next*(s: var TServer) = var buf = "" discard recvLine(s.client, buf) var data = buf.split() - if cmpIgnoreCase(data[0], "GET") == 0: + if cmpIgnoreCase(data[0], "GET") == 0 or cmpIgnoreCase(data[0], "POST") == 0: var q = find(data[1], '?') if q >= 0: s.query = data[1].copy(q+1) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 0a373125d..175713a0c 100755 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -37,6 +37,11 @@ type pkAny, ## any character (.) pkAnyRune, ## any Unicode character (_) pkNewLine, ## CR-LF, LF, CR + pkLetter, ## Unicode letter + pkLower, ## Unicode lower case letter + pkUpper, ## Unicode upper case letter + pkTitle, ## Unicode title character + pkWhitespace, ## Unicode whitespace character pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, @@ -71,7 +76,7 @@ type rule: TNode ## the rule that the symbol refers to TNode {.final.} = object case kind: TPegKind - of pkEmpty, pkAny, pkAnyRune, pkGreedyAny, pkNewLine: nil + of pkEmpty..pkWhitespace: nil of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string of pkChar, pkGreedyRepChar: ch: char of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char] @@ -196,6 +201,7 @@ proc `@`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsSearch".} = proc `@@`*(a: TPeg): TPeg {.noSideEffect, rtl, extern: "npgegsCapturedSearch".} = + ## constructs a "captured search" for the PEG `a` result.kind = pkCapturedSearch result.sons = @[a] @@ -237,6 +243,27 @@ proc newLine*: TPeg {.inline.} = ## constructs the PEG `newline`:idx: (``\n``) result.kind = pkNewline +proc UnicodeLetter*: TPeg {.inline.} = + ## constructs the PEG ``\letter`` which matches any Unicode letter. + result.kind = pkLetter + +proc UnicodeLower*: TPeg {.inline.} = + ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter. + result.kind = pkLower + +proc UnicodeUpper*: TPeg {.inline.} = + ## constructs the PEG ``\upper`` which matches any Unicode lowercase letter. + result.kind = pkUpper + +proc UnicodeTitle*: TPeg {.inline.} = + ## constructs the PEG ``\title`` which matches any Unicode title letter. + result.kind = pkTitle + +proc UnicodeWhitespace*: TPeg {.inline.} = + ## constructs the PEG ``\white`` which matches any Unicode + ## whitespace character. + result.kind = pkWhitespace + proc capture*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsCapture".} = ## constructs a capture with the PEG `a` result.kind = pkCapture @@ -267,8 +294,8 @@ proc spaceCost(n: TPeg): int = case n.kind of pkEmpty: nil of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar, - pkGreedyRepChar, pkCharChoice, pkGreedyRepSet, pkAny, pkAnyRune, - pkNewLine, pkGreedyAny: + pkGreedyRepChar, pkCharChoice, pkGreedyRepSet, + pkAny..pkWhitespace, pkGreedyAny: result = 1 of pkNonTerminal: # we cannot inline a rule with a non-terminal @@ -379,6 +406,12 @@ proc toStrAux(r: TPeg, res: var string) = of pkEmpty: add(res, "()") of pkAny: add(res, '.') of pkAnyRune: add(res, '_') + of pkLetter: add(res, "\\letter") + of pkLower: add(res, "\\lower") + of pkUpper: add(res, "\\upper") + of pkTitle: add(res, "\\title") + of pkWhitespace: add(res, "\\white") + of pkNewline: add(res, "\\n") of pkTerminal: add(res, singleQuoteEsc(r.term)) of pkTerminalIgnoreCase: @@ -460,10 +493,15 @@ proc `$` *(r: TPeg): string {.nosideEffect, rtl, extern: "npegsToString".} = # --------------------- core engine ------------------------------------------- type - TMatchClosure {.final.} = object + TCaptures* {.final.} = object ## contains the captured substrings. matches: array[0..maxSubpatterns-1, tuple[first, last: int]] ml: int +proc bounds*(c: TCaptures, + i: range[0..maxSubpatterns-1]): tuple[first, last: int] = + ## returns the bounds ``[first..last]`` of the `i`'th capture. + result = c.matches[i] + when not useUnicode: type TRune = char @@ -472,9 +510,17 @@ when not useUnicode: inc(i) template runeLenAt(s, i: expr): expr = 1 -proc m(s: string, p: TPeg, start: int, c: var TMatchClosure): int = - ## this implements a simple PEG interpreter. Thanks to superoperators it - ## has competitive performance nevertheless. + proc isAlpha(a: char): bool {.inline.} = return a in {'a'..'z','A'..'Z'} + proc isUpper(a: char): bool {.inline.} = return a in {'A'..'Z'} + proc isLower(a: char): bool {.inline.} = return a in {'a'..'z'} + proc isTitle(a: char): bool {.inline.} = return false + proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'} + +proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. + nosideEffect, rtl, extern: "npegs$1".} = + ## low-level matching proc that implements the PEG interpreter. Use this + ## for maximum efficiency (every other PEG operation ends up calling this + ## proc). ## Returns -1 if it does not match, else the length of the match case p.kind of pkEmpty: result = 0 # match of length 0 @@ -486,6 +532,51 @@ proc m(s: string, p: TPeg, start: int, c: var TMatchClosure): int = result = runeLenAt(s, start) else: result = -1 + of pkLetter: + if s[start] != '\0': + var a: TRune + result = start + fastRuneAt(s, result, a) + if isAlpha(a): dec(result, start) + else: result = -1 + else: + result = -1 + of pkLower: + if s[start] != '\0': + var a: TRune + result = start + fastRuneAt(s, result, a) + if isLower(a): dec(result, start) + else: result = -1 + else: + result = -1 + of pkUpper: + if s[start] != '\0': + var a: TRune + result = start + fastRuneAt(s, result, a) + if isUpper(a): dec(result, start) + else: result = -1 + else: + result = -1 + of pkTitle: + if s[start] != '\0': + var a: TRune + result = start + fastRuneAt(s, result, a) + if isTitle(a): dec(result, start) + else: result = -1 + else: + result = -1 + of pkWhitespace: + if s[start] != '\0': + var a: TRune + result = start + fastRuneAt(s, result, a) + if isWhitespace(a): dec(result, start) + else: result = -1 + else: + result = -1 of pkGreedyAny: result = len(s) - start of pkNewLine: @@ -537,14 +628,14 @@ proc m(s: string, p: TPeg, start: int, c: var TMatchClosure): int = of pkNonTerminal: var oldMl = c.ml when false: echo "enter: ", p.nt.name - result = m(s, p.nt.rule, start, c) + result = rawMatch(s, p.nt.rule, start, c) when false: echo "leave: ", p.nt.name if result < 0: c.ml = oldMl of pkSequence: var oldMl = c.ml result = 0 for i in 0..high(p.sons): - var x = m(s, p.sons[i], start+result, c) + var x = rawMatch(s, p.sons[i], start+result, c) if x < 0: c.ml = oldMl result = -1 @@ -553,14 +644,14 @@ proc m(s: string, p: TPeg, start: int, c: var TMatchClosure): int = of pkOrderedChoice: var oldMl = c.ml for i in 0..high(p.sons): - result = m(s, p.sons[i], start, c) + result = rawMatch(s, p.sons[i], start, c) if result >= 0: break c.ml = oldMl of pkSearch: var oldMl = c.ml result = 0 while start+result < s.len: - var x = m(s, p.sons[0], start+result, c) + var x = rawMatch(s, p.sons[0], start+result, c) if x >= 0: inc(result, x) return @@ -572,7 +663,7 @@ proc m(s: string, p: TPeg, start: int, c: var TMatchClosure): int = inc(c.ml) result = 0 while start+result < s.len: - var x = m(s, p.sons[0], start+result, c) + var x = rawMatch(s, p.sons[0], start+result, c) if x >= 0: if idx < maxSubpatterns: c.matches[idx] = (start, start+result-1) @@ -585,7 +676,7 @@ proc m(s: string, p: TPeg, start: int, c: var TMatchClosure): int = of pkGreedyRep: result = 0 while true: - var x = m(s, p.sons[0], start+result, c) + var x = rawMatch(s, p.sons[0], start+result, c) # if x == 0, we have an endless loop; so the correct behaviour would be # not to break. But endless loops can be easily introduced: # ``(comment / \w*)*`` is such an example. Breaking for x == 0 does the @@ -600,15 +691,15 @@ proc m(s: string, p: TPeg, start: int, c: var TMatchClosure): int = result = 0 while contains(p.charChoice^, s[start+result]): inc(result) of pkOption: - result = max(0, m(s, p.sons[0], start, c)) + result = max(0, rawMatch(s, p.sons[0], start, c)) of pkAndPredicate: var oldMl = c.ml - result = m(s, p.sons[0], start, c) + result = rawMatch(s, p.sons[0], start, c) if result >= 0: result = 0 # do not consume anything else: c.ml = oldMl of pkNotPredicate: var oldMl = c.ml - result = m(s, p.sons[0], start, c) + result = rawMatch(s, p.sons[0], start, c) if result < 0: result = 0 else: c.ml = oldMl @@ -616,7 +707,7 @@ proc m(s: string, p: TPeg, start: int, c: var TMatchClosure): int = of pkCapture: var idx = c.ml # reserve a slot for the subpattern inc(c.ml) - result = m(s, p.sons[0], start, c) + result = rawMatch(s, p.sons[0], start, c) if result >= 0: if idx < maxSubpatterns: c.matches[idx] = (start, start+result-1) @@ -629,7 +720,7 @@ proc m(s: string, p: TPeg, start: int, c: var TMatchClosure): int = var n: TPeg n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef)) n.term = s.copy(a, b) - result = m(s, n, start, c) + result = rawMatch(s, n, start, c) of pkRule, pkList: assert false proc match*(s: string, pattern: TPeg, matches: var openarray[string], @@ -638,8 +729,8 @@ proc match*(s: string, pattern: TPeg, matches: var openarray[string], ## the captured substrings in the array ``matches``. If it does not ## match, nothing is written into ``matches`` and ``false`` is ## returned. - var c: TMatchClosure - result = m(s, pattern, start, c) == len(s) -start + var c: TCaptures + result = rawMatch(s, pattern, start, c) == len(s) -start if result: for i in 0..c.ml-1: matches[i] = copy(s, c.matches[i][0], c.matches[i][1]) @@ -647,8 +738,8 @@ proc match*(s: string, pattern: TPeg, matches: var openarray[string], proc match*(s: string, pattern: TPeg, start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} = ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``. - var c: TMatchClosure - result = m(s, pattern, start, c) == len(s)-start + var c: TCaptures + result = rawMatch(s, pattern, start, c) == len(s)-start proc matchLen*(s: string, pattern: TPeg, matches: var openarray[string], start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} = @@ -656,8 +747,8 @@ proc matchLen*(s: string, pattern: TPeg, matches: var openarray[string], ## if there is no match, -1 is returned. Note that a match length ## of zero can happen. It's possible that a suffix of `s` remains ## that does not belong to the match. - var c: TMatchClosure - result = m(s, pattern, start, c) + var c: TCaptures + result = rawMatch(s, pattern, start, c) if result >= 0: for i in 0..c.ml-1: matches[i] = copy(s, c.matches[i][0], c.matches[i][1]) @@ -668,8 +759,8 @@ proc matchLen*(s: string, pattern: TPeg, ## if there is no match, -1 is returned. Note that a match length ## of zero can happen. It's possible that a suffix of `s` remains ## that does not belong to the match. - var c: TMatchClosure - result = m(s, pattern, start, c) + var c: TCaptures + result = rawMatch(s, pattern, start, c) proc find*(s: string, pattern: TPeg, matches: var openarray[string], start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} = @@ -681,6 +772,18 @@ proc find*(s: string, pattern: TPeg, matches: var openarray[string], return -1 # could also use the pattern here: (!P .)* P +proc findBounds*(s: string, pattern: TPeg, matches: var openarray[string], + start = 0): tuple[first, last: int] {. + nosideEffect, rtl, extern: "npegs$1Capture".} = + ## returns the starting position and end position of ``pattern`` in ``s`` + ## and the captured + ## substrings in the array ``matches``. If it does not match, nothing + ## is written into ``matches`` and (-1,0) is returned. + for i in start .. s.len-1: + var L = matchLen(s, pattern, matches, i) + if L >= 0: return (i, i+L-1) + return (-1, 0) + proc find*(s: string, pattern: TPeg, start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} = ## returns the starting position of ``pattern`` in ``s``. If it does not @@ -1351,6 +1454,11 @@ proc primary(p: var TPegParser): TPeg = of "a": result = charset({'a'..'z', 'A'..'Z'}) of "A": result = charset({'\1'..'\xff'} - {'a'..'z', 'A'..'Z'}) of "ident": result = pegs.ident + of "letter": result = UnicodeLetter() + of "upper": result = UnicodeUpper() + of "lower": result = UnicodeLower() + of "title": result = UnicodeTitle() + of "white": result = UnicodeWhitespace() else: pegError(p, "unknown built-in: " & p.tok.literal) getTok(p) of tkEscaped: @@ -1439,9 +1547,12 @@ proc rawParse(p: var TPegParser): TPeg = elif ntUsed notin nt.flags and i > 0: pegError(p, "unused rule: " & nt.name, nt.line, nt.col) -proc parsePeg*(input: string, filename = "pattern", line = 1, col = 0): TPeg = +proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): TPeg = + ## constructs a TPeg object from `pattern`. `filename`, `line`, `col` are + ## used for error messages, but they only provide start offsets. `parsePeg` + ## keeps track of line and column numbers within `pattern`. var p: TPegParser - init(TPegLexer(p), input, filename, line, col) + init(TPegLexer(p), pattern, filename, line, col) p.tok.kind = tkInvalid p.tok.modifier = modNone p.tok.literal = "" @@ -1505,9 +1616,9 @@ when isMainModule: expr.rule = sequence(capture(ident), *sequence( nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr))) - var c: TMatchClosure + var c: TCaptures var s = "a+b + c +d+e+f" - assert m(s, expr.rule, 0, c) == len(s) + assert rawMatch(s, expr.rule, 0, c) == len(s) var a = "" for i in 0..c.ml-1: a.add(copy(s, c.matches[i][0], c.matches[i][1])) @@ -1559,4 +1670,10 @@ when isMainModule: else: assert false - + assert match("eine übersicht und außerdem", peg"(\letter \white*)+") + # ß is not a lower cased letter?! + assert match("eine übersicht und auerdem", peg"(\lower \white*)+") + assert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+") + assert(not match("456678", peg"(\letter)+")) + + diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim index 85628db78..add41afd6 100755 --- a/lib/pure/sockets.nim +++ b/lib/pure/sockets.nim @@ -9,7 +9,7 @@ ## This module implements a simple portable type-safe sockets layer. -import os +import os, parseutils when defined(Windows): import winlean @@ -146,18 +146,66 @@ proc listen*(socket: TSocket, attempts = 5) = ## listens to socket. if listen(cint(socket), cint(attempts)) < 0'i32: OSError() -proc bindAddr*(socket: TSocket, port = TPort(0)) = - ## binds a port number to a socket. +proc invalidIp4(s: string) {.noreturn, noinline.} = + raise newException(EInvalidValue, "invalid ip4 address: " & s) + +proc parseIp4*(s: string): int32 = + ## parses an IP version 4 in dotted decimal form like "a.b.c.d". + ## Raises EInvalidValue in case of an error. + var a, b, c, d: int + var i = 0 + var j = parseInt(s, a, i) + if j <= 0: invalidIp4(s) + inc(i, j) + if s[i] == '.': inc(i) + else: invalidIp4(s) + j = parseInt(s, b, i) + if j <= 0: invalidIp4(s) + inc(i, j) + if s[i] == '.': inc(i) + else: invalidIp4(s) + j = parseInt(s, c, i) + if j <= 0: invalidIp4(s) + inc(i, j) + if s[i] == '.': inc(i) + else: invalidIp4(s) + j = parseInt(s, d, i) + if j <= 0: invalidIp4(s) + inc(i, j) + if s[i] != '\0': invalidIp4(s) + result = int32(a shl 24 or b shl 16 or c shl 8 or d) + +proc bindAddr*(socket: TSocket, port = TPort(0), address = "") = + ## binds an address/port number to a socket. + ## Use address string in dotted decimal form like "a.b.c.d" + ## or leave "" for any address. 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 address == "": + name.sin_addr.s_addr = sockets.htonl(INADDR_ANY) + else: + name.sin_addr.s_addr = parseIp4(address) if bindSocket(cint(socket), cast[ptr TSockAddr](addr(name)), sizeof(name)) < 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)) < 0'i32: + OSError() proc getSockName*(socket: TSocket): TPort = ## returns the socket's associated port number. @@ -410,6 +458,33 @@ proc send*(socket: TSocket, data: string) = if send(socket, cstring(data), data.len) != data.len: OSError() when defined(Windows): + const + SOCKET_ERROR = -1 + IOCPARM_MASK = 127 + IOC_IN = int(-2147483648) + FIONBIO = int(IOC_IN or ((sizeof(int) and IOCPARM_MASK) shl 16) or + (102 shl 8) or 126) + + proc ioctlsocket(s: TWinSocket, cmd: clong, + argptr: ptr clong): cint {. + stdcall, importc:"ioctlsocket", dynlib: "ws2_32.dll".} + +proc setBlocking*(s: TSocket, blocking: bool) = + ## sets blocking mode on socket + when defined(Windows): + var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking + if SOCKET_ERROR == ioctlsocket(TWinSocket(s), FIONBIO, addr(mode)): + OSError() + else: # BSD sockets + var x: int = fcntl(cint(s), F_GETFL, 0) + if x == -1: + OSError() + else: + var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK + if fcntl(cint(s), F_SETFL, mode) == -1: + OSError() + +when defined(Windows): var wsa: TWSADATA if WSAStartup(0x0101'i16, wsa) != 0: OSError() |