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
This commit is contained in:
parent
d5ed4fba3e
commit
cd9af6b804
22 changed files with 852 additions and 356 deletions
|
|
@ -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:
|
||||
## **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
|
||||
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")
|
||||
|
||||
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 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()
|
||||
var strm = openFileStream("somefile.txt")
|
||||
echo strm.readLine()
|
||||
## Output:
|
||||
## The first line
|
||||
strm.close()
|
||||
except:
|
||||
stderr.write getCurrentExceptionMsg()
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue