diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/impure/db_mysql.nim | 27 | ||||
-rw-r--r-- | lib/impure/db_postgres.nim | 21 | ||||
-rw-r--r-- | lib/impure/db_sqlite.nim | 24 | ||||
-rw-r--r-- | lib/pure/httpclient.nim | 6 | ||||
-rw-r--r-- | lib/pure/pegs.nim | 1 | ||||
-rw-r--r-- | lib/pure/streams.nim | 2 | ||||
-rw-r--r-- | lib/pure/terminal.nim | 103 | ||||
-rw-r--r-- | lib/pure/unicode.nim | 10 | ||||
-rw-r--r-- | lib/system.nim | 3 |
9 files changed, 165 insertions, 32 deletions
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index 619c2a656..7c2901efd 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -16,6 +16,9 @@ type DbConn* = PMySQL ## encapsulates a database connection Row* = seq[string] ## a row of a dataset. NULL database values will be ## transformed always to the empty string. + InstantRow* = tuple[row: cstringArray, len: int] ## a handle that can be + ## used to get a row's + ## column text on demand EDb* = object of IOError ## exception that is raised if a database error occurs SqlQuery* = distinct string ## an SQL query string @@ -127,6 +130,30 @@ iterator fastRows*(db: DbConn, query: SqlQuery, yield result properFreeResult(sqlres, row) +iterator instantRows*(db: DbConn, query: SqlQuery, + args: varargs[string, `$`]): InstantRow + {.tags: [FReadDb].} = + ## same as fastRows but returns a handle that can be used to get column text + ## on demand using []. Returned handle is valid only within interator body. + rawExec(db, query, args) + var sqlres = mysql.useResult(db) + if sqlres != nil: + let L = int(mysql.numFields(sqlres)) + var row: cstringArray + while true: + row = mysql.fetchRow(sqlres) + if row == nil: break + yield (row: row, len: L) + properFreeResult(sqlres, row) + +proc `[]`*(row: InstantRow, col: int): string {.inline.} = + ## returns text for given column of the row + $row.row[col] + +proc len*(row: InstantRow): int {.inline.} = + ## returns number of columns in the row + row.len + proc getRow*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): Row {.tags: [FReadDB].} = ## retrieves a single row. If the query doesn't return any rows, this proc diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim index 774cb1510..c88e660f4 100644 --- a/lib/impure/db_postgres.nim +++ b/lib/impure/db_postgres.nim @@ -16,6 +16,9 @@ type DbConn* = PPGconn ## encapsulates a database connection Row* = seq[string] ## a row of a dataset. NULL database values will be ## transformed always to the empty string. + InstantRow* = tuple[res: PPGresult, line: int32] ## a handle that can be + ## used to get a row's + ## column text on demand EDb* = object of IOError ## exception that is raised if a database error occurs SqlQuery* = distinct string ## an SQL query string @@ -159,6 +162,24 @@ iterator fastRows*(db: DbConn, stmtName: SqlPrepared, yield result pqClear(res) +iterator instantRows*(db: DbConn, query: SqlQuery, + args: varargs[string, `$`]): InstantRow + {.tags: [FReadDb].} = + ## same as fastRows but returns a handle that can be used to get column text + ## on demand using []. Returned handle is valid only within interator body. + var res = setupQuery(db, query, args) + for i in 0..pqNtuples(res)-1: + yield (res: res, line: i) + pqClear(res) + +proc `[]`*(row: InstantRow, col: int32): string {.inline.} = + ## returns text for given column of the row + $pqgetvalue(row.res, row.line, col) + +proc len*(row: InstantRow): int32 {.inline.} = + ## returns number of columns in the row + pqNfields(row.res) + proc getRow*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): Row {.tags: [FReadDB].} = ## retrieves a single row. If the query doesn't return any rows, this proc diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index 47e7c1900..1a037becc 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -16,6 +16,8 @@ type DbConn* = PSqlite3 ## encapsulates a database connection Row* = seq[string] ## a row of a dataset. NULL database values will be ## transformed always to the empty string. + InstantRow* = Pstmt ## a handle that can be used to get a row's column + ## text on demand EDb* = object of IOError ## exception that is raised if a database error occurs SqlQuery* = distinct string ## an SQL query string @@ -109,6 +111,24 @@ iterator fastRows*(db: DbConn, query: SqlQuery, yield result if finalize(stmt) != SQLITE_OK: dbError(db) +iterator instantRows*(db: DbConn, query: SqlQuery, + args: varargs[string, `$`]): InstantRow + {.tags: [FReadDb].} = + ## same as fastRows but returns a handle that can be used to get column text + ## on demand using []. Returned handle is valid only within interator body. + var stmt = setupQuery(db, query, args) + while step(stmt) == SQLITE_ROW: + yield stmt + if finalize(stmt) != SQLITE_OK: dbError(db) + +proc `[]`*(row: InstantRow, col: int32): string {.inline.} = + ## returns text for given column of the row + $column_text(row, col) + +proc len*(row: InstantRow): int32 {.inline.} = + ## returns number of columns in the row + column_count(row) + proc getRow*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): Row {.tags: [FReadDb].} = ## retrieves a single row. If the query doesn't return any rows, this proc @@ -216,5 +236,7 @@ when not defined(testing) and isMainModule: #db.query("insert into tbl1 values('goodbye', 20)") for r in db.rows(sql"select * from tbl1", []): echo(r[0], r[1]) - + for r in db.instantRows(sql"select * from tbl1", []): + echo(r[0], r[1]) + db_sqlite.close(db) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index e083d44ea..6a2913713 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -569,7 +569,7 @@ proc downloadFile*(url: string, outputFilename: string, fileError("Unable to open file") proc generateHeaders(r: Uri, httpMethod: string, - headers: StringTableRef): string = + headers: StringTableRef, body: string): string = # TODO: Use this in the blocking HttpClient once it supports proxies. result = substr(httpMethod, len("http")) # TODO: Proxies @@ -582,6 +582,8 @@ proc generateHeaders(r: Uri, httpMethod: string, add(result, "Host: " & r.hostname & "\c\L") add(result, "Connection: Keep-Alive\c\L") + if body.len > 0 and not headers.hasKey("Content-Length"): + add(result, "Content-Length: " & $body.len & "\c\L") for key, val in headers: add(result, key & ": " & val & "\c\L") @@ -786,7 +788,7 @@ proc request*(client: AsyncHttpClient, url: string, httpMethod: string, if not client.headers.hasKey("user-agent") and client.userAgent != "": client.headers["User-Agent"] = client.userAgent - var headers = generateHeaders(r, $httpMethod, client.headers) + var headers = generateHeaders(r, $httpMethod, client.headers, body) await client.socket.send(headers) if body != "": diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index ce837d9d1..e165d7dca 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -1060,7 +1060,6 @@ type lineStart: int ## index of last line start in buffer colOffset: int ## column to add filename: string -{.deprecated: [TTokKind: TokKind, TToken: Token, TModifier: Modifier].} const tokKindToStr: array[TokKind, string] = [ diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index e6004b5d0..50b5c219a 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -279,7 +279,7 @@ proc ssAtEnd(s: Stream): bool = proc ssSetPosition(s: Stream, pos: int) = var s = StringStream(s) - s.pos = clamp(pos, 0, s.data.high) + s.pos = clamp(pos, 0, s.data.len) proc ssGetPosition(s: Stream): int = var s = StringStream(s) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 1e9c40f06..15e2eefec 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -17,28 +17,87 @@ import macros when defined(windows): - import windows, os + import winlean, os + + const + DUPLICATE_SAME_ACCESS = 2 + FOREGROUND_BLUE = 1 + FOREGROUND_GREEN = 2 + FOREGROUND_RED = 4 + FOREGROUND_INTENSITY = 8 + BACKGROUND_BLUE = 16 + BACKGROUND_GREEN = 32 + BACKGROUND_RED = 64 + BACKGROUND_INTENSITY = 128 + + type + SHORT = int16 + COORD = object + X: SHORT + Y: SHORT + + SMALL_RECT = object + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT + + CONSOLE_SCREEN_BUFFER_INFO = object + dwSize: COORD + dwCursorPosition: COORD + wAttributes: int16 + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD + + proc duplicateHandle(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE, + hTargetProcessHandle: HANDLE, lpTargetHandle: ptr HANDLE, + dwDesiredAccess: DWORD, bInheritHandle: WINBOOL, + dwOptions: DWORD): WINBOOL{.stdcall, dynlib: "kernel32", + importc: "DuplicateHandle".} + proc getCurrentProcess(): HANDLE{.stdcall, dynlib: "kernel32", + importc: "GetCurrentProcess".} + proc getConsoleScreenBufferInfo(hConsoleOutput: HANDLE, + lpConsoleScreenBufferInfo: ptr CONSOLE_SCREEN_BUFFER_INFO): WINBOOL{.stdcall, + dynlib: "kernel32", importc: "GetConsoleScreenBufferInfo".} + + proc setConsoleCursorPosition(hConsoleOutput: HANDLE, + dwCursorPosition: COORD): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "SetConsoleCursorPosition".} + + proc fillConsoleOutputCharacter(hConsoleOutput: Handle, cCharacter: char, + nLength: DWORD, dwWriteCoord: Coord, + lpNumberOfCharsWritten: ptr DWORD): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "FillConsoleOutputCharacterA".} + + proc fillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: int16, + nLength: DWORD, dwWriteCoord: COORD, + lpNumberOfAttrsWritten: ptr DWORD): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "FillConsoleOutputAttribute".} + + proc setConsoleTextAttribute(hConsoleOutput: HANDLE, + wAttributes: int16): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "SetConsoleTextAttribute".} var conHandle: Handle # = createFile("CONOUT$", GENERIC_WRITE, 0, nil, OPEN_ALWAYS, 0, 0) block: - var hTemp = GetStdHandle(STD_OUTPUT_HANDLE) - if DuplicateHandle(GetCurrentProcess(), hTemp, GetCurrentProcess(), + var hTemp = getStdHandle(STD_OUTPUT_HANDLE) + if duplicateHandle(getCurrentProcess(), hTemp, getCurrentProcess(), addr(conHandle), 0, 1, DUPLICATE_SAME_ACCESS) == 0: raiseOSError(osLastError()) proc getCursorPos(): tuple [x,y: int] = var c: CONSOLESCREENBUFFERINFO - if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: + if getConsoleScreenBufferInfo(conHandle, addr(c)) == 0: raiseOSError(osLastError()) return (int(c.dwCursorPosition.X), int(c.dwCursorPosition.Y)) proc getAttributes(): int16 = var c: CONSOLESCREENBUFFERINFO # workaround Windows bugs: try several times - if GetConsoleScreenBufferInfo(conHandle, addr(c)) != 0: + if getConsoleScreenBufferInfo(conHandle, addr(c)) != 0: return c.wAttributes return 0x70'i16 # ERROR: return white background, black text @@ -67,7 +126,7 @@ proc setCursorPos*(x, y: int) = var c: COORD c.X = int16(x) c.Y = int16(y) - if SetConsoleCursorPosition(conHandle, c) == 0: raiseOSError(osLastError()) + if setConsoleCursorPosition(conHandle, c) == 0: raiseOSError(osLastError()) else: stdout.write("\e[" & $y & ';' & $x & 'f') @@ -77,11 +136,11 @@ proc setCursorXPos*(x: int) = when defined(windows): var scrbuf: CONSOLESCREENBUFFERINFO var hStdout = conHandle - if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: + if getConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: raiseOSError(osLastError()) var origin = scrbuf.dwCursorPosition origin.X = int16(x) - if SetConsoleCursorPosition(conHandle, origin) == 0: + if setConsoleCursorPosition(conHandle, origin) == 0: raiseOSError(osLastError()) else: stdout.write("\e[" & $x & 'G') @@ -93,11 +152,11 @@ when defined(windows): when defined(windows): var scrbuf: CONSOLESCREENBUFFERINFO var hStdout = conHandle - if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: + if getConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: raiseOSError(osLastError()) var origin = scrbuf.dwCursorPosition origin.Y = int16(y) - if SetConsoleCursorPosition(conHandle, origin) == 0: + if setConsoleCursorPosition(conHandle, origin) == 0: raiseOSError(osLastError()) else: discard @@ -175,18 +234,18 @@ proc eraseLine* = var scrbuf: CONSOLESCREENBUFFERINFO var numwrote: DWORD var hStdout = conHandle - if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: + if getConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: raiseOSError(osLastError()) var origin = scrbuf.dwCursorPosition origin.X = 0'i16 - if SetConsoleCursorPosition(conHandle, origin) == 0: + if setConsoleCursorPosition(conHandle, origin) == 0: raiseOSError(osLastError()) var ht = scrbuf.dwSize.Y - origin.Y var wt = scrbuf.dwSize.X - origin.X - if FillConsoleOutputCharacter(hStdout,' ', ht*wt, + if fillConsoleOutputCharacter(hStdout,' ', ht*wt, origin, addr(numwrote)) == 0: raiseOSError(osLastError()) - if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, ht * wt, + if fillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, ht * wt, scrbuf.dwCursorPosition, addr(numwrote)) == 0: raiseOSError(osLastError()) else: @@ -201,14 +260,14 @@ proc eraseScreen* = var origin: COORD # is inititalized to 0, 0 var hStdout = conHandle - if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: + if getConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: raiseOSError(osLastError()) let numChars = int32(scrbuf.dwSize.X)*int32(scrbuf.dwSize.Y) - if FillConsoleOutputCharacter(hStdout, ' ', numChars, + if fillConsoleOutputCharacter(hStdout, ' ', numChars, origin, addr(numwrote)) == 0: raiseOSError(osLastError()) - if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, numChars, + if fillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, numChars, origin, addr(numwrote)) == 0: raiseOSError(osLastError()) setCursorXPos(0) @@ -219,7 +278,7 @@ proc resetAttributes* {.noconv.} = ## resets all attributes; it is advisable to register this as a quit proc ## with ``system.addQuitProc(resetAttributes)``. when defined(windows): - discard SetConsoleTextAttribute(conHandle, oldAttr) + discard setConsoleTextAttribute(conHandle, oldAttr) else: stdout.write("\e[0m") @@ -249,7 +308,7 @@ proc setStyle*(style: set[Style]) = if styleBlink in style: a = a or int16(BACKGROUND_INTENSITY) if styleReverse in style: a = a or 0x4000'i16 # COMMON_LVB_REVERSE_VIDEO if styleUnderscore in style: a = a or 0x8000'i16 # COMMON_LVB_UNDERSCORE - discard SetConsoleTextAttribute(conHandle, a) + discard setConsoleTextAttribute(conHandle, a) else: for s in items(style): stdout.write("\e[" & $ord(s) & 'm') @@ -260,7 +319,7 @@ proc writeStyled*(txt: string, style: set[Style] = {styleBright}) = var old = getAttributes() setStyle(style) stdout.write(txt) - discard SetConsoleTextAttribute(conHandle, old) + discard setConsoleTextAttribute(conHandle, old) else: setStyle(style) stdout.write(txt) @@ -309,7 +368,7 @@ proc setForegroundColor*(fg: ForegroundColor, bright=false) = (FOREGROUND_RED or FOREGROUND_BLUE), (FOREGROUND_BLUE or FOREGROUND_GREEN), (FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED)] - discard SetConsoleTextAttribute(conHandle, toU16(old or lookup[fg])) + discard setConsoleTextAttribute(conHandle, toU16(old or lookup[fg])) else: gFG = ord(fg) if bright: inc(gFG, 60) @@ -330,7 +389,7 @@ proc setBackgroundColor*(bg: BackgroundColor, bright=false) = (BACKGROUND_RED or BACKGROUND_BLUE), (BACKGROUND_BLUE or BACKGROUND_GREEN), (BACKGROUND_BLUE or BACKGROUND_GREEN or BACKGROUND_RED)] - discard SetConsoleTextAttribute(conHandle, toU16(old or lookup[bg])) + discard setConsoleTextAttribute(conHandle, toU16(old or lookup[bg])) else: gBG = ord(bg) if bright: inc(gBG, 60) diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index 5fd3c2418..4446eaa0c 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -372,11 +372,17 @@ const 0xfe74] # spaceRanges = [ - 0x0009, 0x000a, # tab and newline + 0x0009, 0x000d, # tab and newline 0x0020, 0x0020, # space + 0x0085, 0x0085, # next line 0x00a0, 0x00a0, # - 0x2000, 0x200b, # - + 0x1680, 0x1680, # Ogham space mark + 0x2000, 0x200b, # en dash .. zero-width space + 0x200e, 0x200f, # LTR mark .. RTL mark (pattern whitespace) 0x2028, 0x2029, # - 0x3000, 0x3000, # + 0x202f, 0x202f, # narrow no-break space + 0x205f, 0x205f, # medium mathematical space + 0x3000, 0x3000, # ideographic space 0xfeff, 0xfeff] # toupperRanges = [ diff --git a/lib/system.nim b/lib/system.nim index 90587f306..949443dd9 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2859,9 +2859,6 @@ proc `/`*(x, y: int): float {.inline, noSideEffect.} = ## integer division that results in a float. result = toFloat(x) / toFloat(y) -template `-|`*(b, s: expr): expr = - (if b >= 0: b else: s.len + b) - template spliceImpl(s, a, L, b: expr): stmt {.immediate.} = # make room for additional elements or cut: var slen = s.len |