diff options
Diffstat (limited to 'lib')
-rwxr-xr-x | lib/impure/db_mysql.nim | 22 | ||||
-rw-r--r--[-rwxr-xr-x] | lib/pure/httpserver.nim (renamed from lib/devel/httpserver.nim) | 39 | ||||
-rwxr-xr-x | lib/pure/pegs.nim | 2 | ||||
-rwxr-xr-x | lib/pure/re.nim | 211 |
4 files changed, 192 insertions, 82 deletions
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index ee37a88c3..9c427ae3b 100755 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -50,22 +50,22 @@ proc dbQuote(s: string): string = else: add(result, c) add(result, '\'') -proc dbFormat(formatstr: string, args: openarray[string]): string = +proc dbFormat(formatstr: TSqlQuery, args: openarray[string]): string = result = "" var a = 0 - for c in items(formatstr): + for c in items(string(formatstr)): if c == '?': add(result, dbQuote(args[a])) inc(a) else: add(result, c) -proc TryQuery*(db: TDbConn, query: string, args: openarray[string]): bool = +proc TryQuery*(db: TDbConn, query: TSqlQuery, args: openarray[string]): bool = ## tries to execute the query and returns true if successful, false otherwise. var q = dbFormat(query, args) return mysqlRealQuery(db, q, q.len) == 0'i32 -proc Query*(db: TDbConn, query: string, args: openarray[string]) = +proc Query*(db: TDbConn, query: TSqlQuery, args: openarray[string]) = ## executes the query and raises EDB if not successful. var q = dbFormat(query, args) if mysqlRealQuery(db, q, q.len) != 0'i32: dbError(db) @@ -79,7 +79,7 @@ proc properFreeResult(sqlres: PMYSQL_RES, row: cstringArray) = while mysqlFetchRow(sqlres) != nil: nil mysqlFreeResult(sqlres) -iterator FastRows*(db: TDbConn, query: string, +iterator FastRows*(db: TDbConn, query: TSqlQuery, args: openarray[string]): TRow = ## executes the query and iterates over the result dataset. This is very ## fast, but potenially dangerous: If the for-loop-body executes another @@ -99,7 +99,7 @@ iterator FastRows*(db: TDbConn, query: string, yield result properFreeResult(sqlres, row) -proc GetAllRows*(db: TDbConn, query: string, +proc GetAllRows*(db: TDbConn, query: TSqlQuery, args: openarray[string]): seq[TRow] = ## executes the query and returns the whole result dataset. result = @[] @@ -118,12 +118,12 @@ proc GetAllRows*(db: TDbConn, query: string, inc(j) mysqlFreeResult(sqlres) -iterator Rows*(db: TDbConn, query: string, +iterator Rows*(db: TDbConn, query: TSqlQuery, args: openarray[string]): TRow = ## same as `FastRows`, but slower and safe. for r in items(GetAllRows(db, query, args)): yield r -proc GetValue*(db: TDbConn, query: string, +proc GetValue*(db: TDbConn, query: TSqlQuery, args: openarray[string]): string = ## executes the query and returns the result dataset's the first column ## of the first row. Returns "" if the dataset contains no rows. This uses @@ -133,7 +133,7 @@ proc GetValue*(db: TDbConn, query: string, result = row[0] break -proc TryInsertID*(db: TDbConn, query: string, +proc TryInsertID*(db: TDbConn, query: TSqlQuery, args: openarray[string]): int64 = ## executes the query (typically "INSERT") and returns the ## generated ID for the row or -1 in case of an error. @@ -143,13 +143,13 @@ proc TryInsertID*(db: TDbConn, query: string, else: result = mysql_insert_id(db) -proc InsertID*(db: TDbConn, query: string, args: openArray[string]): int64 = +proc InsertID*(db: TDbConn, query: TSqlQuery, args: openArray[string]): int64 = ## executes the query (typically "INSERT") and returns the ## generated ID for the row. result = TryInsertID(db, query, args) if result < 0: dbError(db) -proc QueryAffectedRows*(db: TDbConn, query: string, +proc QueryAffectedRows*(db: TDbConn, query: TSqlQuery, args: openArray[string]): int64 = ## runs the query (typically "UPDATE") and returns the ## number of affected rows diff --git a/lib/devel/httpserver.nim b/lib/pure/httpserver.nim index 61d95cc2e..2c85d8137 100755..100644 --- a/lib/devel/httpserver.nim +++ b/lib/pure/httpserver.nim @@ -8,6 +8,20 @@ # ## This module implements a simple HTTP-Server. +## +## Example: +## +## .. code-block:: nimrod +## import strutils, sockets, httpserver +## +## var counter = 0 +## proc handleRequest(client: TSocket, path, query: string): bool {.procvar.} = +## inc(counter) +## client.send("Hallo for the $#th time." % $counter & wwwNL) +## return false # do not stop processing +## +## run(handleRequest, TPort(80)) +## import strutils, os, osproc, strtabs, streams, sockets @@ -180,15 +194,18 @@ type client*: TSocket ## the socket to write the file data to path*, query*: string ## path and query the client requested -proc open*(s: var TServer, port = TPort(0)) = +proc open*(s: var TServer, port = TPort(80)) = ## creates a new server at port `port`. If ``port == 0`` a free port is ## aquired that can be accessed later by the ``port`` proc. s.socket = socket(AF_INET) if s.socket == InvalidSocket: OSError() - bindAddr(s.socket) + bindAddr(s.socket, port) listen(s.socket) - s.port = getSockName(s.socket) + if port == TPort(0): + s.port = getSockName(s.socket) + else: + s.port = port s.client = InvalidSocket s.path = "" s.query = "" @@ -220,7 +237,7 @@ proc close*(s: TServer) = close(s.socket) proc run*(handleRequest: proc (client: TSocket, path, query: string): bool, - port = TPort(0)) = + port = TPort(80)) = ## encapsulates the server object and main loop var s: TServer open(s, port) @@ -231,18 +248,6 @@ proc run*(handleRequest: proc (client: TSocket, path, query: string): bool, close(s.client) close(s) -when false: - proc main = - var (server, port) = startup() - echo("httpserver running on port ", int16(port)) - - while true: - var client = accept(server) - if client == InvalidSocket: OSError() - acceptRequest(client) - close(client) - close(server) - when isMainModule: var counter = 0 proc handleRequest(client: TSocket, path, query: string): bool {.procvar.} = @@ -250,5 +255,5 @@ when isMainModule: client.send("Hallo, Andreas for the $#th time." % $counter & wwwNL) return false # do not stop processing - run(handleRequest) + run(handleRequest, TPort(80)) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 488e42c7d..5ba0351ad 100755 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2009 Andreas Rumpf +# (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. diff --git a/lib/pure/re.nim b/lib/pure/re.nim index cef7c85ac..fbe4179ce 100755 --- a/lib/pure/re.nim +++ b/lib/pure/re.nim @@ -9,27 +9,170 @@ ## Regular expression support for Nimrod. Consider using the pegs module ## instead. +## Currently this module is implemented by providing a wrapper around the +## `PRCE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_ +## C library. This means that your application will depend on the PRCE +## library's licence when using this module, which should not be a problem +## though. +## PRCE's licence follows: +## +## .. include:: ../doc/regexprs.txt +## + +import + pcre, strutils -{.compile: "tre/tre_all.c".} - -from strutils import addf +const + MaxSubpatterns* = 10 + ## defines the maximum number of subpatterns that can be captured. + ## More subpatterns cannot be captured! type - TRegExDesc {.pure, final.} = object - re_nsub: int # Number of parenthesized subexpressions. - value: pointer # For internal use only. - - TRegEx* = ref TRegExDesc ## a compiled regular expression + TRegExOptions* = enum ## options for regular expressions + reIgnoreCase = 0, ## do caseless matching + reMultiLine = 1, ## ``^`` and ``$`` match newlines within data + reDotAll = 2, ## ``.`` matches anything including NL + reExtended = 3, ## ignore whitespace and ``#`` comments + + + PCRE_ANCHORED* = 0x00000010 + PCRE_DOLLAR_ENDONLY* = 0x00000020 + PCRE_EXTRA* = 0x00000040 + PCRE_NOTBOL* = 0x00000080 + PCRE_NOTEOL* = 0x00000100 + PCRE_UNGREEDY* = 0x00000200 + PCRE_NOTEMPTY* = 0x00000400 + PCRE_UTF8* = 0x00000800 + PCRE_NO_AUTO_CAPTURE* = 0x00001000 + + + TRegExDesc {.pure, final.} = object + h: PPcre + + TRegEx* = ref TRegExDesc ## a compiled regular expression + EInvalidRegEx* = object of EInvalidValue ## is raised if the pattern is no valid regular expression. - - TRegMatch {.pure.} = object - so, eo: cint -const - MaxSubpatterns* = 10 - ## defines the maximum number of subpatterns that can be captured. - ## More subpatterns cannot be captured! +proc rawCompile(pattern: string, flags: cint): PPcre = + var + msg: CString + offset: int + com = pcreCompile(pattern, flags, addr(msg), addr(offset), nil) + if com == nil: + var e: ref EInvalidRegEx + new(e) + e.msg = $msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n" + raise e + return com + +proc finalizeRegEx(x: TRegEx) = dealloc(x.h) + +proc re*(s: string): TRegEx = + ## Constructor of regular expressions. Note that Nimrod's + ## extended raw string literals supports this syntax ``re"[abc]"`` as + ## a short form for ``re(r"[abc]")``. + new(result, finalizeRegEx) + result.h = rawCompile(s, + + var err = int(regncomp(addr(result^), s, s.len, + cint(REG_EXTENDED or REG_NEWLINE))) + if err != 0: + var e: ref EInvalidRegEx + new(e) + e.msg = ErrorMessages[err] + raise e + +proc xre*(pattern: string): TRegEx = + ## deletes whitespace from a pattern that is not escaped or in a character + ## class. Then it constructs a regular expresion object via `re`. + ## This is modelled after Perl's ``/x`` modifier. + var p = "" + var i = 0 + while i < pattern.len: + case pattern[i] + of ' ', '\t': + inc i + of '\\': + add p, '\\' + add p, pattern[i+1] + inc i, 2 + of '[': + while pattern[i] != ']' and pattern[i] != '\0': + add p, pattern[i] + inc i + else: + add p, pattern[i] + inc i + result = re(p) + +proc matchOrFind(s: string, pattern: PPcre, matches: var openarray[string], + start: cint): cint = + var + rawMatches: array [0..maxSubpatterns * 3 - 1, cint] + res = int(pcreExec(pattern, nil, s, len(s), start, 0, + cast[ptr cint](addr(rawMatches)), maxSubpatterns * 3)) + dealloc(pattern) + if res < 0: return res + for i in 0..res-1: + var + a = rawMatches[i * 2] + b = rawMatches[i * 2 + 1] + if a >= 0'i32: matches[i] = copy(s, a, int(b)-1) + else: matches[i] = "" + return res + +proc matchOrFind(s: string, pattern: PPcre, start: cint): cint = + var + rawMatches: array [0..maxSubpatterns * 3 - 1, cint] + res = pcreExec(pattern, nil, s, len(s), start, 0, + cast[ptr cint](addr(rawMatches)), maxSubpatterns * 3) + dealloc(pattern) + return res + +proc match(s, pattern: string, matches: var openarray[string], + start: int = 0): bool = + return matchOrFind(s, rawCompile(pattern, PCRE_ANCHORED), + matches, start) >= 0'i32 + +proc matchLen(s, pattern: string, matches: var openarray[string], + start: int = 0): int = + return matchOrFind(s, rawCompile(pattern, PCRE_ANCHORED), matches, start) + +proc find(s, pattern: string, matches: var openarray[string], + start: int = 0): bool = + return matchOrFind(s, rawCompile(pattern, PCRE_MULTILINE), + matches, start) >= 0'i32 + +proc match(s, pattern: string, start: int = 0): bool = + return matchOrFind(s, rawCompile(pattern, PCRE_ANCHORED), start) >= 0'i32 + +proc find(s, pattern: string, start: int = 0): bool = + return matchOrFind(s, rawCompile(pattern, PCRE_MULTILINE), start) >= 0'i32 + +template `=~` *(s, pattern: expr): expr = + ## This calls ``match`` with an implicit declared ``matches`` array that + ## can be used in the scope of the ``=~`` call: + ## + ## .. code-block:: nimrod + ## + ## if line =~ r"\s*(\w+)\s*\=\s*(\w+)": + ## # matches a key=value pair: + ## echo("Key: ", matches[1]) + ## echo("Value: ", matches[2]) + ## elif line =~ r"\s*(\#.*)": + ## # matches a comment + ## # note that the implicit ``matches`` array is different from the + ## # ``matches`` array of the first branch + ## echo("comment: ", matches[1]) + ## else: + ## echo("syntax error") + ## + when not definedInScope(matches): + var matches: array[0..maxSubPatterns-1, string] + match(s, pattern, matches) + + proc regnexec(preg: ptr TRegExDesc, s: cstring, len, nmatch: int, pmatch: ptr array [0..maxSubpatterns-1, TRegMatch], @@ -75,44 +218,6 @@ const "Invalid use of repetition operators" ] -proc finalizeRegEx(x: TRegEx) = regfree(addr(x^)) - -proc re*(s: string): TRegEx = - ## Constructor of regular expressions. Note that Nimrod's - ## extended raw string literals supports this syntax ``re"[abc]"`` as - ## a short form for ``re(r"[abc]")``. - new(result, finalizeRegEx) - var err = int(regncomp(addr(result^), s, s.len, - cint(REG_EXTENDED or REG_NEWLINE))) - if err != 0: - var e: ref EInvalidRegEx - new(e) - e.msg = ErrorMessages[err] - raise e - -proc xre*(pattern: string): TRegEx = - ## deletes whitespace from a pattern that is not escaped or in a character - ## class. Then it constructs a regular expresion object via `re`. - ## This is modelled after Perl's ``/x`` modifier. - var p = "" - var i = 0 - while i < pattern.len: - case pattern[i] - of ' ', '\t': - inc i - of '\\': - add p, '\\' - add p, pattern[i+1] - inc i, 2 - of '[': - while pattern[i] != ']' and pattern[i] != '\0': - add p, pattern[i] - inc i - else: - add p, pattern[i] - inc i - result = re(p) - proc rawmatch(s: string, pattern: TRegEx, matches: var openarray[string], start: int): tuple[first, last: int] = var |