diff options
Diffstat (limited to 'lib/impure')
-rw-r--r-- | lib/impure/db_mysql.nim | 43 | ||||
-rw-r--r-- | lib/impure/db_sqlite.nim | 9 | ||||
-rw-r--r-- | lib/impure/nre.nim | 9 | ||||
-rw-r--r-- | lib/impure/rdstdin.nim | 46 | ||||
-rw-r--r-- | lib/impure/re.nim | 54 |
5 files changed, 65 insertions, 96 deletions
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index 1b79b3543..ca0e29d11 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -89,7 +89,7 @@ import db_common export db_common type - DbConn* = PMySQL ## encapsulates a database connection + DbConn* = distinct PMySQL ## encapsulates a database connection Row* = seq[string] ## a row of a dataset. NULL database values will be ## converted to nil. InstantRow* = object ## a handle that can be used to get a row's @@ -102,7 +102,7 @@ proc dbError*(db: DbConn) {.noreturn.} = ## raises a DbError exception. var e: ref DbError new(e) - e.msg = $mysql.error(db) + e.msg = $mysql.error(PMySQL db) raise e when false: @@ -128,7 +128,7 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string = var a = 0 for c in items(string(formatstr)): if c == '?': - if args[a] == nil: + if args[a].isNil: add(result, "NULL") else: add(result, dbQuote(args[a])) @@ -140,17 +140,17 @@ proc tryExec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): bool {. tags: [ReadDbEffect, WriteDbEffect].} = ## tries to execute the query and returns true if successful, false otherwise. var q = dbFormat(query, args) - return mysql.realQuery(db, q, q.len) == 0'i32 + return mysql.realQuery(PMySQL db, q, q.len) == 0'i32 proc rawExec(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) = var q = dbFormat(query, args) - if mysql.realQuery(db, q, q.len) != 0'i32: dbError(db) + if mysql.realQuery(PMySQL db, q, q.len) != 0'i32: dbError(db) proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {. tags: [ReadDbEffect, WriteDbEffect].} = ## executes the query and raises EDB if not successful. var q = dbFormat(query, args) - if mysql.realQuery(db, q, q.len) != 0'i32: dbError(db) + if mysql.realQuery(PMySQL db, q, q.len) != 0'i32: dbError(db) proc newRow(L: int): Row = newSeq(result, L) @@ -171,7 +171,7 @@ iterator fastRows*(db: DbConn, query: SqlQuery, ## Breaking the fastRows() iterator during a loop will cause the next ## database query to raise an [EDb] exception ``Commands out of sync``. rawExec(db, query, args) - var sqlres = mysql.useResult(db) + var sqlres = mysql.useResult(PMySQL db) if sqlres != nil: var L = int(mysql.numFields(sqlres)) @@ -210,7 +210,7 @@ iterator instantRows*(db: DbConn, query: SqlQuery, ## Same as fastRows but returns a handle that can be used to get column text ## on demand using []. Returned handle is valid only within the iterator body. rawExec(db, query, args) - var sqlres = mysql.useResult(db) + var sqlres = mysql.useResult(PMySQL db) if sqlres != nil: let L = int(mysql.numFields(sqlres)) var row: cstringArray @@ -290,7 +290,7 @@ iterator instantRows*(db: DbConn; columns: var DbColumns; query: SqlQuery; ## Same as fastRows but returns a handle that can be used to get column text ## on demand using []. Returned handle is valid only within the iterator body. rawExec(db, query, args) - var sqlres = mysql.useResult(db) + var sqlres = mysql.useResult(PMySQL db) if sqlres != nil: let L = int(mysql.numFields(sqlres)) setColumnInfo(columns, sqlres, L) @@ -315,7 +315,7 @@ proc getRow*(db: DbConn, query: SqlQuery, ## Retrieves a single row. If the query doesn't return any rows, this proc ## will return a Row with empty strings for each column. rawExec(db, query, args) - var sqlres = mysql.useResult(db) + var sqlres = mysql.useResult(PMySQL db) if sqlres != nil: var L = int(mysql.numFields(sqlres)) result = newRow(L) @@ -334,7 +334,7 @@ proc getAllRows*(db: DbConn, query: SqlQuery, ## executes the query and returns the whole result dataset. result = @[] rawExec(db, query, args) - var sqlres = mysql.useResult(db) + var sqlres = mysql.useResult(PMySQL db) if sqlres != nil: var L = int(mysql.numFields(sqlres)) var row: cstringArray @@ -369,10 +369,10 @@ proc tryInsertId*(db: DbConn, query: SqlQuery, ## executes the query (typically "INSERT") and returns the ## generated ID for the row or -1 in case of an error. var q = dbFormat(query, args) - if mysql.realQuery(db, q, q.len) != 0'i32: + if mysql.realQuery(PMySQL db, q, q.len) != 0'i32: result = -1'i64 else: - result = mysql.insertId(db) + result = mysql.insertId(PMySQL db) proc insertId*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): int64 {.tags: [WriteDbEffect].} = @@ -387,32 +387,33 @@ proc execAffectedRows*(db: DbConn, query: SqlQuery, ## runs the query (typically "UPDATE") and returns the ## number of affected rows rawExec(db, query, args) - result = mysql.affectedRows(db) + result = mysql.affectedRows(PMySQL db) proc close*(db: DbConn) {.tags: [DbEffect].} = ## closes the database connection. - if db != nil: mysql.close(db) + if PMySQL(db) != nil: mysql.close(PMySQL db) proc open*(connection, user, password, database: string): DbConn {. tags: [DbEffect].} = ## opens a database connection. Raises `EDb` if the connection could not ## be established. - result = mysql.init(nil) - if result == nil: dbError("could not open database connection") + var res = mysql.init(nil) + if res == nil: dbError("could not open database connection") let colonPos = connection.find(':') host = if colonPos < 0: connection else: substr(connection, 0, colonPos-1) port: int32 = if colonPos < 0: 0'i32 else: substr(connection, colonPos+1).parseInt.int32 - if mysql.realConnect(result, host, user, password, database, + if mysql.realConnect(res, host, user, password, database, port, nil, 0) == nil: - var errmsg = $mysql.error(result) - db_mysql.close(result) + var errmsg = $mysql.error(res) + mysql.close(res) dbError(errmsg) + result = DbConn(res) proc setEncoding*(connection: DbConn, encoding: string): bool {. tags: [DbEffect].} = ## sets the encoding of a database connection, returns true for ## success, false for failure. - result = mysql.set_character_set(connection, encoding) == 0 + result = mysql.set_character_set(PMySQL connection, encoding) == 0 diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index 21049571f..fd25b2b94 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -31,7 +31,7 @@ ## ## .. code-block:: Nim ## import db_sqlite -## let db = open("localhost", "user", "password", "dbname") +## let db = open("mytest.db", nil, nil, nil) # user, password, database name can be nil ## db.close() ## ## Creating a table @@ -57,7 +57,7 @@ ## ## import db_sqlite, math ## -## let theDb = open("mytest.db", nil, nil, nil) +## let theDb = open("mytest.db", "", "", "") ## ## theDb.exec(sql"Drop table if exists myTestTbl") ## theDb.exec(sql("""create table myTestTbl ( @@ -81,7 +81,7 @@ ## ## theDb.close() -{.deadCodeElim:on.} +{.deadCodeElim: on.} # dce option deprecated import strutils, sqlite3 @@ -126,6 +126,7 @@ proc tryExec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): bool {. tags: [ReadDbEffect, WriteDbEffect].} = ## tries to execute the query and returns true if successful, false otherwise. + assert(not db.isNil, "Database not connected.") var q = dbFormat(query, args) var stmt: sqlite3.Pstmt if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK: @@ -144,6 +145,7 @@ proc newRow(L: int): Row = proc setupQuery(db: DbConn, query: SqlQuery, args: varargs[string]): Pstmt = + assert(not db.isNil, "Database not connected.") var q = dbFormat(query, args) if prepare_v2(db, q, q.len.cint, result, nil) != SQLITE_OK: dbError(db) @@ -267,6 +269,7 @@ proc tryInsertID*(db: DbConn, query: SqlQuery, {.tags: [WriteDbEffect], raises: [].} = ## executes the query (typically "INSERT") and returns the ## generated ID for the row or -1 in case of an error. + assert(not db.isNil, "Database not connected.") var q = dbFormat(query, args) var stmt: sqlite3.Pstmt result = -1 diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 3d4afc0ae..6058128dd 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -10,7 +10,7 @@ from pcre import nil import nre.private.util import tables -from strutils import toLower, `%` +from strutils import `%` from math import ceil import options from unicode import runeLenAt @@ -326,15 +326,15 @@ proc `$`*(pattern: RegexMatch): string = proc `==`*(a, b: Regex): bool = if not a.isNil and not b.isNil: - return a.pattern == b.pattern and - a.pcreObj == b.pcreObj and + return a.pattern == b.pattern and + a.pcreObj == b.pcreObj and a.pcreExtra == b.pcreExtra else: return system.`==`(a, b) proc `==`*(a, b: RegexMatch): bool = return a.pattern == b.pattern and - a.str == b.str + a.str == b.str # }}} # Creation & Destruction {{{ @@ -645,7 +645,6 @@ template replaceImpl(str: string, pattern: Regex, let bounds = match.matchBounds result.add(str.substr(lastIdx, bounds.a - 1)) let nextVal = replacement - assert(nextVal != nil) result.add(nextVal) lastIdx = bounds.b + 1 diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index b06e8de6c..54bab82f0 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -13,7 +13,7 @@ ## is used. This suffices because Windows' console already provides the ## wanted functionality. -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated when defined(Windows): proc readLineFromStdin*(prompt: string): TaintedString {. @@ -73,32 +73,6 @@ when defined(Windows): discard readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead) return result - from unicode import toUTF8, Rune, runeLenAt - - proc readPasswordFromStdin*(prompt: string, password: var TaintedString): - bool {.tags: [ReadIOEffect, WriteIOEffect].} = - ## Reads a `password` from stdin without printing it. `password` must not - ## be ``nil``! Returns ``false`` if the end of the file has been reached, - ## ``true`` otherwise. - password.setLen(0) - stdout.write(prompt) - while true: - let c = getch() - case c.char - of '\r', chr(0xA): - break - of '\b': - # ensure we delete the whole UTF-8 character: - var i = 0 - var x = 1 - while i < password.len: - x = runeLenAt(password, i) - inc i, x - password.setLen(max(password.len - x, 0)) - else: - password.add(toUTF8(c.Rune)) - stdout.write "\n" - else: import linenoise, termios @@ -124,21 +98,3 @@ else: linenoise.free(buffer) result = true - proc readPasswordFromStdin*(prompt: string, password: var TaintedString): - bool {.tags: [ReadIOEffect, WriteIOEffect].} = - password.setLen(0) - let fd = stdin.getFileHandle() - var cur, old: Termios - discard fd.tcgetattr(cur.addr) - old = cur - cur.c_lflag = cur.c_lflag and not Cflag(ECHO) - discard fd.tcsetattr(TCSADRAIN, cur.addr) - stdout.write prompt - result = stdin.readLine(password) - stdout.write "\n" - discard fd.tcsetattr(TCSADRAIN, old.addr) - -proc readPasswordFromStdin*(prompt: string): TaintedString = - ## Reads a password from stdin without printing it. - result = TaintedString("") - discard readPasswordFromStdin(prompt, result) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index c7f8f336b..201c490f3 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -7,18 +7,14 @@ # distribution, for details about the copyright. # -## Regular expression support for Nim. This module still has some -## obscure bugs and limitations, -## consider using the ``nre`` or ``pegs`` modules instead. -## We had to de-deprecate this module since too much code relies on it -## and many people prefer its API over ``nre``'s. +## Regular expression support for Nim. ## ## 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 +## `PCRE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_ +## C library. This means that your application will depend on the PCRE ## library's licence when using this module, which should not be a problem ## though. -## PRCE's licence follows: +## PCRE's licence follows: ## ## .. include:: ../../doc/regexprs.txt ## @@ -502,7 +498,7 @@ proc transformFile*(infile, outfile: string, var x = readFile(infile).string writeFile(outfile, x.multiReplace(subs)) -iterator split*(s: string, sep: Regex): string = +iterator split*(s: string, sep: Regex; maxsplit = -1): string = ## Splits the string ``s`` into substrings. ## ## Substrings are separated by the regular expression ``sep`` @@ -524,22 +520,28 @@ iterator split*(s: string, sep: Regex): string = ## "example" ## "" ## - var - first = -1 - last = -1 - while last < len(s): - var x = matchLen(s, sep, last) - if x > 0: inc(last, x) - first = last - if x == 0: inc(last) + var last = 0 + var splits = maxsplit + var x: int + while last <= len(s): + var first = last + var sepLen = 1 while last < len(s): x = matchLen(s, sep, last) - if x >= 0: break + if x >= 0: + sepLen = x + break inc(last) - if first <= last: - yield substr(s, first, last-1) - -proc split*(s: string, sep: Regex): seq[string] {.inline.} = + if x == 0: + if last >= len(s): break + inc last + if splits == 0: last = len(s) + yield substr(s, first, last-1) + if splits == 0: break + dec(splits) + inc(last, sepLen) + +proc split*(s: string, sep: Regex, maxsplit = -1): seq[string] {.inline.} = ## Splits the string ``s`` into a seq of substrings. ## ## The portion matched by ``sep`` is not returned. @@ -636,6 +638,14 @@ when isMainModule: accum.add(word) doAssert(accum == @["AAA", "", "BBB"]) + doAssert(split("abc", re"") == @["a", "b", "c"]) + doAssert(split("", re"") == @[]) + + doAssert(split("a;b;c", re";") == @["a", "b", "c"]) + doAssert(split(";a;b;c", re";") == @["", "a", "b", "c"]) + doAssert(split(";a;b;c;", re";") == @["", "a", "b", "c", ""]) + doAssert(split("a;b;c;", re";") == @["a", "b", "c", ""]) + for x in findAll("abcdef", re"^{.}", 3): doAssert x == "d" accum = @[] |