diff options
author | hlaaftana <10591326+hlaaftana@users.noreply.github.com> | 2020-04-28 20:44:52 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-28 19:44:52 +0200 |
commit | cd9af6b8040bc72985d457e5169e18ded7c107d6 (patch) | |
tree | 62807f310d4483b9e14db0ae5a639ff3c1b029a9 /lib/pure/streams.nim | |
parent | d5ed4fba3e9225e687d916fd4129e3c61550e193 (diff) | |
download | Nim-cd9af6b8040bc72985d457e5169e18ded7c107d6.tar.gz |
StringStream & more stdlib modules support for JS/NimScript (#14095)
* StringStream & more stdlib modules support for JS/NimScript * change back pegs test in line with #14134
Diffstat (limited to 'lib/pure/streams.nim')
-rw-r--r-- | lib/pure/streams.nim | 476 |
1 files changed, 287 insertions, 189 deletions
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 4af4ae2ec..8efe5b227 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -216,6 +216,9 @@ proc getPosition*(s: Stream): int = proc readData*(s: Stream, buffer: pointer, bufLen: int): int = ## Low level proc that reads data into an untyped `buffer` of `bufLen` size. + ## + ## **JS note:** `buffer` is treated as a ``ptr string`` and written to between + ## ``0..<bufLen``. runnableExamples: var strm = newStringStream("abcde") var buffer: array[6, char] @@ -241,11 +244,21 @@ proc readDataStr*(s: Stream, buffer: var string, slice: Slice[int]): int = # fallback result = s.readData(addr buffer[0], buffer.len) -when not defined(js): +template jsOrVmBlock(caseJsOrVm, caseElse: untyped): untyped = + when nimvm: + block: + caseJsOrVm + else: + block: + when defined(js) or defined(nimscript): + # nimscript has to be here to avoid semantic checking of caseElse + caseJsOrVm + else: + caseElse + +when (NimMajor, NimMinor) >= (1, 3) or not defined(js): proc readAll*(s: Stream): string = ## Reads all available data. - ## - ## **Note:** Not available for JS backend. runnableExamples: var strm = newStringStream("The first line\nthe second line\nthe third line") doAssert strm.readAll() == "The first line\nthe second line\nthe third line" @@ -253,7 +266,7 @@ when not defined(js): strm.close() const bufferSize = 1024 - when nimvm: + jsOrVmBlock: var buffer2: string buffer2.setLen(bufferSize) while true: @@ -265,7 +278,7 @@ when not defined(js): result[prevLen..<prevLen+readBytes] = buffer2[0..<readBytes] if readBytes < bufferSize: break - else: + do: # not JS or VM var buffer {.noinit.}: array[bufferSize, char] while true: let readBytes = readData(s, addr(buffer[0]), bufferSize) @@ -280,6 +293,9 @@ when not defined(js): proc peekData*(s: Stream, buffer: pointer, bufLen: int): int = ## Low level proc that reads data into an untyped `buffer` of `bufLen` size ## without moving stream position. + ## + ## **JS note:** `buffer` is treated as a ``ptr string`` and written to between + ## ``0..<bufLen``. runnableExamples: var strm = newStringStream("abcde") var buffer: array[6, char] @@ -293,6 +309,9 @@ proc peekData*(s: Stream, buffer: pointer, bufLen: int): int = proc writeData*(s: Stream, buffer: pointer, bufLen: int) = ## Low level proc that writes an untyped `buffer` of `bufLen` size ## to the stream `s`. + ## + ## **JS note:** `buffer` is treated as a ``ptr string`` and read between + ## ``0..<bufLen``. runnableExamples: ## writeData var strm = newStringStream("") @@ -311,6 +330,9 @@ proc writeData*(s: Stream, buffer: pointer, bufLen: int) = proc write*[T](s: Stream, x: T) = ## Generic write procedure. Writes `x` to the stream `s`. Implementation: ## + ## **Note:** Not available for JS backend. Use `write(Stream, string) + ## <#write,Stream,string>`_ for now. + ## ## .. code-block:: Nim ## ## s.writeData(s, unsafeAddr(x), sizeof(x)) @@ -336,7 +358,12 @@ proc write*(s: Stream, x: string) = when nimvm: writeData(s, cstring(x), x.len) else: - if x.len > 0: writeData(s, cstring(x), x.len) + if x.len > 0: + when defined(js): + var x = x + writeData(s, addr(x), x.len) + else: + writeData(s, cstring(x), x.len) proc write*(s: Stream, args: varargs[string, `$`]) = ## Writes one or more strings to the the stream. No length fields or @@ -366,6 +393,8 @@ proc writeLine*(s: Stream, args: varargs[string, `$`]) = proc read*[T](s: Stream, result: var T) = ## Generic read procedure. Reads `result` from the stream `s`. + ## + ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream("012") ## readInt @@ -383,6 +412,8 @@ proc read*[T](s: Stream, result: var T) = proc peek*[T](s: Stream, result: var T) = ## Generic peek procedure. Peeks `result` from the stream `s`. + ## + ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream("012") ## peekInt @@ -412,11 +443,11 @@ proc readChar*(s: Stream): char = doAssert strm.readChar() == '\x00' strm.close() - when nimvm: + jsOrVmBlock: var str = " " - if readDataStr(s, str, 0..<sizeof(result)) != 1: result = '\0' + if readDataStr(s, str, 0..0) != 1: result = '\0' else: result = str[0] - else: + do: if readData(s, addr(result), sizeof(result)) != 1: result = '\0' proc peekChar*(s: Stream): char = @@ -430,7 +461,12 @@ proc peekChar*(s: Stream): char = doAssert strm.peekChar() == '\x00' strm.close() - if peekData(s, addr(result), sizeof(result)) != 1: result = '\0' + when defined(js): + var str = " " + if peekData(s, addr(str), sizeof(result)) != 1: result = '\0' + else: result = str[0] + else: + if peekData(s, addr(result), sizeof(result)) != 1: result = '\0' proc readBool*(s: Stream): bool = ## Reads a bool from the stream `s`. @@ -438,6 +474,8 @@ proc readBool*(s: Stream): bool = ## A bool is one byte long and it is `true` for every non-zero ## (`0000_0000`) value. ## Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -461,6 +499,8 @@ proc peekBool*(s: Stream): bool = ## A bool is one byte long and it is `true` for every non-zero ## (`0000_0000`) value. ## Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -482,6 +522,8 @@ proc peekBool*(s: Stream): bool = proc readInt8*(s: Stream): int8 = ## Reads an int8 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -499,6 +541,8 @@ proc readInt8*(s: Stream): int8 = proc peekInt8*(s: Stream): int8 = ## Peeks an int8 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -518,6 +562,8 @@ proc peekInt8*(s: Stream): int8 = proc readInt16*(s: Stream): int16 = ## Reads an int16 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -535,6 +581,8 @@ proc readInt16*(s: Stream): int16 = proc peekInt16*(s: Stream): int16 = ## Peeks an int16 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -554,6 +602,8 @@ proc peekInt16*(s: Stream): int16 = proc readInt32*(s: Stream): int32 = ## Reads an int32 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -571,6 +621,8 @@ proc readInt32*(s: Stream): int32 = proc peekInt32*(s: Stream): int32 = ## Peeks an int32 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -590,6 +642,8 @@ proc peekInt32*(s: Stream): int32 = proc readInt64*(s: Stream): int64 = ## Reads an int64 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -607,6 +661,8 @@ proc readInt64*(s: Stream): int64 = proc peekInt64*(s: Stream): int64 = ## Peeks an int64 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -626,6 +682,8 @@ proc peekInt64*(s: Stream): int64 = proc readUint8*(s: Stream): uint8 = ## Reads an uint8 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -643,6 +701,8 @@ proc readUint8*(s: Stream): uint8 = proc peekUint8*(s: Stream): uint8 = ## Peeks an uint8 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -662,6 +722,8 @@ proc peekUint8*(s: Stream): uint8 = proc readUint16*(s: Stream): uint16 = ## Reads an uint16 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -679,6 +741,8 @@ proc readUint16*(s: Stream): uint16 = proc peekUint16*(s: Stream): uint16 = ## Peeks an uint16 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -698,6 +762,8 @@ proc peekUint16*(s: Stream): uint16 = proc readUint32*(s: Stream): uint32 = ## Reads an uint32 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -716,6 +782,8 @@ proc readUint32*(s: Stream): uint32 = proc peekUint32*(s: Stream): uint32 = ## Peeks an uint32 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -735,6 +803,8 @@ proc peekUint32*(s: Stream): uint32 = proc readUint64*(s: Stream): uint64 = ## Reads an uint64 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -752,6 +822,8 @@ proc readUint64*(s: Stream): uint64 = proc peekUint64*(s: Stream): uint64 = ## Peeks an uint64 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -771,6 +843,8 @@ proc peekUint64*(s: Stream): uint64 = proc readFloat32*(s: Stream): float32 = ## Reads a float32 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -788,6 +862,8 @@ proc readFloat32*(s: Stream): float32 = proc peekFloat32*(s: Stream): float32 = ## Peeks a float32 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -807,6 +883,8 @@ proc peekFloat32*(s: Stream): float32 = proc readFloat64*(s: Stream): float64 = ## Reads a float64 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -824,6 +902,8 @@ proc readFloat64*(s: Stream): float64 = proc peekFloat64*(s: Stream): float64 = ## Peeks a float64 from the stream `s`. Raises `IOError` if an error occurred. + ## + ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. runnableExamples: var strm = newStringStream() ## setup for reading data @@ -841,10 +921,19 @@ proc peekFloat64*(s: Stream): float64 = peek(s, result) +template untaint(s: var TaintedString): var string = + when taintMode: # for VM, bug #12282 + s.string + else: + s + proc readStrPrivate(s: Stream, length: int, str: var TaintedString) = - if length > len(str): setLen(str.string, length) - var L = readData(s, cstring(str), length) - if L != len(str): setLen(str.string, L) + if length > len(str): setLen(str.untaint, length) + when defined(js): + let L = readData(s, addr(str), length) + else: + let L = readData(s, cstring(str.string), length) + if L != len(str): setLen(str.untaint, L) proc readStr*(s: Stream, length: int, str: var TaintedString) {.since: (1, 3).} = ## Reads a string of length `length` from the stream `s`. Raises `IOError` if @@ -865,9 +954,12 @@ proc readStr*(s: Stream, length: int): TaintedString = readStrPrivate(s, length, result) proc peekStrPrivate(s: Stream, length: int, str: var TaintedString) = - if length > len(str): setLen(str.string, length) - var L = peekData(s, cstring(str), length) - if L != len(str): setLen(str.string, L) + if length > len(str): setLen(str.untaint, length) + when defined(js): + let L = peekData(s, addr(str), length) + else: + let L = peekData(s, cstring(str.string), length) + if L != len(str): setLen(str.untaint, L) proc peekStr*(s: Stream, length: int, str: var TaintedString) {.since: (1, 3).} = ## Peeks a string of length `length` from the stream `s`. Raises `IOError` if @@ -918,13 +1010,7 @@ proc readLine*(s: Stream, line: var TaintedString): bool = result = s.readLineImpl(s, line) else: # fallback - when nimvm: #Bug #12282 - when taintMode: - line.string.setLen(0) - else: - line.setLen(0) - else: - line.string.setLen(0) + line.untaint.setLen(0) while true: var c = readChar(s) if c == '\c': @@ -934,13 +1020,7 @@ proc readLine*(s: Stream, line: var TaintedString): bool = elif c == '\0': if line.len > 0: break else: return false - when nimvm: #Bug #12282 - when taintMode: - line.string.add(c) - else: - line.add(c) - else: - line.string.add(c) + line.untaint.add(c) result = true proc peekLine*(s: Stream, line: var TaintedString): bool = @@ -1002,7 +1082,7 @@ proc readLine*(s: Stream): TaintedString = if c == '\L' or c == '\0': break else: - result.string.add(c) + result.untaint.add(c) proc peekLine*(s: Stream): TaintedString = ## Peeks a line from a stream `s`. Raises `IOError` if an error occurred. @@ -1048,17 +1128,13 @@ iterator lines*(s: Stream): TaintedString = type StringStream* = ref StringStreamObj ## A stream that encapsulates a string. - ## - ## **Note:** Not available for JS backend. StringStreamObj* = object of StreamObj ## A string stream object. - ## - ## **Note:** Not available for JS backend. data*: string ## A string data. ## This is updated when called `writeLine` etc. pos: int -when defined(js): #This section exists so that string streams work at compile time for the js backend +when (NimMajor, NimMinor) < (1, 3) and defined(js): proc ssAtEnd(s: Stream): bool {.compileTime.} = var s = StringStream(s) return s.pos >= s.data.len @@ -1111,7 +1187,7 @@ when defined(js): #This section exists so that string streams work at compile ti if readBytes < bufferSize: break -else: +else: # after 1.3 or JS not defined proc ssAtEnd(s: Stream): bool = var s = StringStream(s) return s.pos >= s.data.len @@ -1128,9 +1204,9 @@ else: var s = StringStream(s) result = min(slice.b + 1 - slice.a, s.data.len - s.pos) if result > 0: - when nimvm: + jsOrVmBlock: buffer[slice.a..<slice.a+result] = s.data[s.pos..<s.pos+result] - else: + do: copyMem(unsafeAddr buffer[slice.a], addr s.data[s.pos], result) inc(s.pos, result) else: @@ -1140,7 +1216,14 @@ else: var s = StringStream(s) result = min(bufLen, s.data.len - s.pos) if result > 0: - copyMem(buffer, addr(s.data[s.pos]), result) + when defined(js): + try: + cast[ptr string](buffer)[][0..<result] = s.data[s.pos..<s.pos+result] + except: + raise newException(Defect, "could not read string stream, " & + "did you use a non-string buffer pointer?", getCurrentException()) + elif not defined(nimscript): + copyMem(buffer, addr(s.data[s.pos]), result) inc(s.pos, result) else: result = 0 @@ -1149,7 +1232,14 @@ else: var s = StringStream(s) result = min(bufLen, s.data.len - s.pos) if result > 0: - copyMem(buffer, addr(s.data[s.pos]), result) + when defined(js): + try: + cast[ptr string](buffer)[][0..<result] = s.data[s.pos..<s.pos+result] + except: + raise newException(Defect, "could not peek string stream, " & + "did you use a non-string buffer pointer?", getCurrentException()) + elif not defined(nimscript): + copyMem(buffer, addr(s.data[s.pos]), result) else: result = 0 @@ -1159,7 +1249,14 @@ else: return if s.pos + bufLen > s.data.len: setLen(s.data, s.pos + bufLen) - copyMem(addr(s.data[s.pos]), buffer, bufLen) + when defined(js): + try: + s.data[s.pos..<s.pos+bufLen] = cast[ptr string](buffer)[][0..<bufLen] + except: + raise newException(Defect, "could not write to string stream, " & + "did you use a non-string buffer pointer?", getCurrentException()) + elif not defined(nimscript): + copyMem(addr(s.data[s.pos]), buffer, bufLen) inc(s.pos, bufLen) proc ssClose(s: Stream) = @@ -1172,8 +1269,6 @@ else: proc newStringStream*(s: string = ""): owned StringStream = ## Creates a new stream from the string `s`. ## - ## **Note:** Not available for JS backend. - ## ## See also: ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from ## opened File. @@ -1195,163 +1290,166 @@ else: result.atEndImpl = ssAtEnd result.setPositionImpl = ssSetPosition result.getPositionImpl = ssGetPosition - result.readDataImpl = ssReadData - result.peekDataImpl = ssPeekData - result.writeDataImpl = ssWriteData result.readDataStrImpl = ssReadDataStr + when nimvm: + discard + else: + result.readDataImpl = ssReadData + result.peekDataImpl = ssPeekData + result.writeDataImpl = ssWriteData - type - FileStream* = ref FileStreamObj - ## A stream that encapsulates a `File`. - ## - ## **Note:** Not available for JS backend. - FileStreamObj* = object of Stream - ## A file stream object. - ## - ## **Note:** Not available for JS backend. - f: File - - proc fsClose(s: Stream) = - if FileStream(s).f != nil: - close(FileStream(s).f) - FileStream(s).f = nil - proc fsFlush(s: Stream) = flushFile(FileStream(s).f) - proc fsAtEnd(s: Stream): bool = return endOfFile(FileStream(s).f) - proc fsSetPosition(s: Stream, pos: int) = setFilePos(FileStream(s).f, pos) - proc fsGetPosition(s: Stream): int = return int(getFilePos(FileStream(s).f)) - - proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = - result = readBuffer(FileStream(s).f, buffer, bufLen) - - proc fsReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int = - result = readBuffer(FileStream(s).f, addr buffer[slice.a], slice.b + 1 - slice.a) - - proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int = - let pos = fsGetPosition(s) - defer: fsSetPosition(s, pos) - result = readBuffer(FileStream(s).f, buffer, bufLen) - - proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) = - if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen: - raise newEIO("cannot write to stream") - - proc fsReadLine(s: Stream, line: var TaintedString): bool = - result = readLine(FileStream(s).f, line) - - proc newFileStream*(f: File): owned FileStream = - ## Creates a new stream from the file `f`. +type + FileStream* = ref FileStreamObj + ## A stream that encapsulates a `File`. ## ## **Note:** Not available for JS backend. + FileStreamObj* = object of Stream + ## A file stream object. ## - ## See also: - ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream - ## from string. - ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ is the same - ## as using `open proc <io.html#open,File,string,FileMode,int>`_ - ## on Examples. - ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a - ## file stream from the file name and the mode. - runnableExamples: - ## Input (somefile.txt): + ## **Note:** Not available for JS backend. + f: File + +proc fsClose(s: Stream) = + if FileStream(s).f != nil: + close(FileStream(s).f) + FileStream(s).f = nil +proc fsFlush(s: Stream) = flushFile(FileStream(s).f) +proc fsAtEnd(s: Stream): bool = return endOfFile(FileStream(s).f) +proc fsSetPosition(s: Stream, pos: int) = setFilePos(FileStream(s).f, pos) +proc fsGetPosition(s: Stream): int = return int(getFilePos(FileStream(s).f)) + +proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = + result = readBuffer(FileStream(s).f, buffer, bufLen) + +proc fsReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int = + result = readBuffer(FileStream(s).f, addr buffer[slice.a], slice.b + 1 - slice.a) + +proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int = + let pos = fsGetPosition(s) + defer: fsSetPosition(s, pos) + result = readBuffer(FileStream(s).f, buffer, bufLen) + +proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) = + if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen: + raise newEIO("cannot write to stream") + +proc fsReadLine(s: Stream, line: var TaintedString): bool = + result = readLine(FileStream(s).f, line) + +proc newFileStream*(f: File): owned FileStream = + ## Creates a new stream from the file `f`. + ## + ## **Note:** Not available for JS backend. + ## + ## See also: + ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream + ## from string. + ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ is the same + ## as using `open proc <io.html#open,File,string,FileMode,int>`_ + ## on Examples. + ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a + ## file stream from the file name and the mode. + runnableExamples: + ## Input (somefile.txt): + ## The first line + ## the second line + ## the third line + var f: File + if open(f, "somefile.txt", fmRead, -1): + var strm = newFileStream(f) + var line = "" + while strm.readLine(line): + echo line + ## Output: ## The first line ## the second line ## the third line - var f: File - if open(f, "somefile.txt", fmRead, -1): - var strm = newFileStream(f) - var line = "" - while strm.readLine(line): - echo line - ## Output: - ## The first line - ## the second line - ## the third line - strm.close() + strm.close() - new(result) - result.f = f - result.closeImpl = fsClose - result.atEndImpl = fsAtEnd - result.setPositionImpl = fsSetPosition - result.getPositionImpl = fsGetPosition - result.readDataStrImpl = fsReadDataStr - result.readDataImpl = fsReadData - result.readLineImpl = fsReadLine - result.peekDataImpl = fsPeekData - result.writeDataImpl = fsWriteData - result.flushImpl = fsFlush - - proc newFileStream*(filename: string, mode: FileMode = fmRead, - bufSize: int = -1): owned FileStream = - ## Creates a new stream from the file named `filename` with the mode `mode`. - ## - ## If the file cannot be opened, `nil` is returned. See the `io module - ## <io.html>`_ for a list of available `FileMode enums <io.html#FileMode>`_. - ## - ## **Note:** - ## * **This function returns nil in case of failure.** - ## To prevent unexpected behavior and ensure proper error handling, - ## use `openFileStream proc <#openFileStream,string,FileMode,int>`_ - ## instead. - ## * Not available for JS backend. - ## - ## See also: - ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream - ## from string. - ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from - ## opened File. - ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a - ## file stream from the file name and the mode. - runnableExamples: - from os import removeFile - var strm = newFileStream("somefile.txt", fmWrite) - if not isNil(strm): - strm.writeLine("The first line") - strm.writeLine("the second line") - strm.writeLine("the third line") - strm.close() - ## Output (somefile.txt) - ## The first line - ## the second line - ## the third line - removeFile("somefile.txt") + new(result) + result.f = f + result.closeImpl = fsClose + result.atEndImpl = fsAtEnd + result.setPositionImpl = fsSetPosition + result.getPositionImpl = fsGetPosition + result.readDataStrImpl = fsReadDataStr + result.readDataImpl = fsReadData + result.readLineImpl = fsReadLine + result.peekDataImpl = fsPeekData + result.writeDataImpl = fsWriteData + result.flushImpl = fsFlush + +proc newFileStream*(filename: string, mode: FileMode = fmRead, + bufSize: int = -1): owned FileStream = + ## Creates a new stream from the file named `filename` with the mode `mode`. + ## + ## If the file cannot be opened, `nil` is returned. See the `io module + ## <io.html>`_ for a list of available `FileMode enums <io.html#FileMode>`_. + ## + ## **Note:** + ## * **This function returns nil in case of failure.** + ## To prevent unexpected behavior and ensure proper error handling, + ## use `openFileStream proc <#openFileStream,string,FileMode,int>`_ + ## instead. + ## * Not available for JS backend. + ## + ## See also: + ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream + ## from string. + ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from + ## opened File. + ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a + ## file stream from the file name and the mode. + runnableExamples: + from os import removeFile + var strm = newFileStream("somefile.txt", fmWrite) + if not isNil(strm): + strm.writeLine("The first line") + strm.writeLine("the second line") + strm.writeLine("the third line") + strm.close() + ## Output (somefile.txt) + ## The first line + ## the second line + ## the third line + removeFile("somefile.txt") - var f: File - if open(f, filename, mode, bufSize): result = newFileStream(f) + var f: File + if open(f, filename, mode, bufSize): result = newFileStream(f) - proc openFileStream*(filename: string, mode: FileMode = fmRead, - bufSize: int = -1): owned FileStream = - ## Creates a new stream from the file named `filename` with the mode `mode`. - ## If the file cannot be opened, an IO exception is raised. - ## - ## **Note:** Not available for JS backend. - ## - ## See also: - ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream - ## from string. - ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from - ## opened File. - ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ creates a - ## file stream from the file name and the mode. - runnableExamples: - try: - ## Input (somefile.txt): - ## The first line - ## the second line - ## the third line - var strm = openFileStream("somefile.txt") - echo strm.readLine() - ## Output: - ## The first line - strm.close() - except: - stderr.write getCurrentExceptionMsg() +proc openFileStream*(filename: string, mode: FileMode = fmRead, + bufSize: int = -1): owned FileStream = + ## Creates a new stream from the file named `filename` with the mode `mode`. + ## If the file cannot be opened, an IO exception is raised. + ## + ## **Note:** Not available for JS backend. + ## + ## See also: + ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream + ## from string. + ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from + ## opened File. + ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ creates a + ## file stream from the file name and the mode. + runnableExamples: + try: + ## Input (somefile.txt): + ## The first line + ## the second line + ## the third line + var strm = openFileStream("somefile.txt") + echo strm.readLine() + ## Output: + ## The first line + strm.close() + except: + stderr.write getCurrentExceptionMsg() - var f: File - if open(f, filename, mode, bufSize): - return newFileStream(f) - else: - raise newEIO("cannot open file stream: " & filename) + var f: File + if open(f, filename, mode, bufSize): + return newFileStream(f) + else: + raise newEIO("cannot open file stream: " & filename) when false: type |