better streams implemenation; fixes #63
This commit is contained in:
parent
3b6d831549
commit
40fa4bb52d
5 changed files with 112 additions and 45 deletions
|
|
@ -75,10 +75,10 @@ proc mySourceCallback(state, data: pointer, len: int,
|
||||||
var src = cast[PStream](state)
|
var src = cast[PStream](state)
|
||||||
case cmd
|
case cmd
|
||||||
of ZIP_SOURCE_OPEN:
|
of ZIP_SOURCE_OPEN:
|
||||||
if src.setPosition != nil: src.setPosition(src, 0) # reset
|
if src.setPositionImpl != nil: setPosition(src, 0) # reset
|
||||||
of ZIP_SOURCE_READ:
|
of ZIP_SOURCE_READ:
|
||||||
result = src.readData(src, data, len)
|
result = readData(src, data, len)
|
||||||
of ZIP_SOURCE_CLOSE: src.close(src)
|
of ZIP_SOURCE_CLOSE: close(src)
|
||||||
of ZIP_SOURCE_STAT:
|
of ZIP_SOURCE_STAT:
|
||||||
var stat = cast[PZipStat](data)
|
var stat = cast[PZipStat](data)
|
||||||
zip_stat_init(stat)
|
zip_stat_init(stat)
|
||||||
|
|
@ -120,8 +120,8 @@ proc fsReadData(s: PStream, buffer: pointer, bufLen: int): int =
|
||||||
proc newZipFileStream(f: PZipFile): PZipFileStream =
|
proc newZipFileStream(f: PZipFile): PZipFileStream =
|
||||||
new(result)
|
new(result)
|
||||||
result.f = f
|
result.f = f
|
||||||
result.close = fsClose
|
result.closeImpl = fsClose
|
||||||
result.readData = fsReadData
|
result.readDataImpl = fsReadData
|
||||||
# other methods are nil!
|
# other methods are nil!
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
when defined(debugExecProcesses):
|
when defined(debugExecProcesses):
|
||||||
var err = ""
|
var err = ""
|
||||||
var outp = outputStream(q[r])
|
var outp = outputStream(q[r])
|
||||||
while running(q[r]) or not outp.atEnd(outp):
|
while running(q[r]) or not atEnd(outp):
|
||||||
err.add(outp.readLine())
|
err.add(outp.readLine())
|
||||||
err.add("\n")
|
err.add("\n")
|
||||||
echo(err)
|
echo(err)
|
||||||
|
|
@ -213,10 +213,10 @@ when not defined(useNimRtl):
|
||||||
var p = startCmd(command, options=options)
|
var p = startCmd(command, options=options)
|
||||||
var outp = outputStream(p)
|
var outp = outputStream(p)
|
||||||
result = TaintedString""
|
result = TaintedString""
|
||||||
while running(p) or not outp.atEnd(outp):
|
while running(p) or not atEnd(outp):
|
||||||
result.string.add(outp.readLine().string)
|
result.string.add(outp.readLine().string)
|
||||||
result.string.add("\n")
|
result.string.add("\n")
|
||||||
outp.close(outp)
|
close(outp)
|
||||||
close(p)
|
close(p)
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
|
|
@ -259,10 +259,10 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
proc newFileHandleStream(handle: THandle): PFileHandleStream =
|
proc newFileHandleStream(handle: THandle): PFileHandleStream =
|
||||||
new(result)
|
new(result)
|
||||||
result.handle = handle
|
result.handle = handle
|
||||||
result.close = hsClose
|
result.closeImpl = hsClose
|
||||||
result.atEnd = hsAtEnd
|
result.atEndImpl = hsAtEnd
|
||||||
result.readData = hsReadData
|
result.readDataImpl = hsReadData
|
||||||
result.writeData = hsWriteData
|
result.writeDataImpl = hsWriteData
|
||||||
|
|
||||||
proc buildCommandLine(a: string, args: openarray[string]): cstring =
|
proc buildCommandLine(a: string, args: openarray[string]): cstring =
|
||||||
var res = quoteIfContainsWhite(a)
|
var res = quoteIfContainsWhite(a)
|
||||||
|
|
@ -643,10 +643,10 @@ proc execCmdEx*(command: string, options: set[TProcessOption] = {
|
||||||
result = (TaintedString"", -1)
|
result = (TaintedString"", -1)
|
||||||
while true:
|
while true:
|
||||||
if result[1] == -1: result[1] = peekExitCode(p)
|
if result[1] == -1: result[1] = peekExitCode(p)
|
||||||
if result[1] != -1 and outp.atEnd(outp): break
|
if result[1] != -1 and atEnd(outp): break
|
||||||
result[0].string.add(outp.readLine().string)
|
result[0].string.add(outp.readLine().string)
|
||||||
result[0].string.add("\n")
|
result[0].string.add("\n")
|
||||||
outp.close(outp)
|
close(outp)
|
||||||
close(p)
|
close(p)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,75 @@ proc newEIO(msg: string): ref EIO =
|
||||||
type
|
type
|
||||||
PStream* = ref TStream
|
PStream* = ref TStream
|
||||||
TStream* = object of TObject ## Stream interface that supports
|
TStream* = object of TObject ## Stream interface that supports
|
||||||
## writing or reading.
|
## writing or reading. Note that these fields
|
||||||
close*: proc (s: PStream)
|
## here shouldn't be used directly. They are
|
||||||
atEnd*: proc (s: PStream): bool
|
## accessible so that a stream implementation
|
||||||
setPosition*: proc (s: PStream, pos: int)
|
## can override them.
|
||||||
getPosition*: proc (s: PStream): int
|
closeImpl*: proc (s: PStream)
|
||||||
readData*: proc (s: PStream, buffer: pointer, bufLen: int): int
|
atEndImpl*: proc (s: PStream): bool
|
||||||
writeData*: proc (s: PStream, buffer: pointer, bufLen: int)
|
setPositionImpl*: proc (s: PStream, pos: int)
|
||||||
|
getPositionImpl*: proc (s: PStream): int
|
||||||
|
readDataImpl*: proc (s: PStream, buffer: pointer, bufLen: int): int
|
||||||
|
writeDataImpl*: proc (s: PStream, buffer: pointer, bufLen: int)
|
||||||
|
flushImpl*: proc (s: PStream)
|
||||||
|
|
||||||
|
proc flush*(s: PStream) =
|
||||||
|
## flushes the buffers that the stream `s` might use.
|
||||||
|
if not isNil(s.flushImpl): s.flushImpl(s)
|
||||||
|
|
||||||
|
proc close*(s: PStream) =
|
||||||
|
## closes the stream `s`.
|
||||||
|
if not isNil(s.closeImpl): s.closeImpl(s)
|
||||||
|
|
||||||
|
proc close*(s, unused: PStream) {.deprecated.} =
|
||||||
|
## closes the stream `s`.
|
||||||
|
s.closeImpl(s)
|
||||||
|
|
||||||
|
proc atEnd*(s: PStream): bool =
|
||||||
|
## checks if more data can be read from `f`. Returns true if all data has
|
||||||
|
## been read.
|
||||||
|
result = s.atEndImpl(s)
|
||||||
|
|
||||||
|
proc atEnd*(s, unused: PStream): bool {.deprecated.} =
|
||||||
|
## checks if more data can be read from `f`. Returns true if all data has
|
||||||
|
## been read.
|
||||||
|
result = s.atEndImpl(s)
|
||||||
|
|
||||||
|
proc setPosition*(s: PStream, pos: int) =
|
||||||
|
## sets the position `pos` of the stream `s`.
|
||||||
|
s.setPositionImpl(s, pos)
|
||||||
|
|
||||||
|
proc setPosition*(s, unused: PStream, pos: int) {.deprecated.} =
|
||||||
|
## sets the position `pos` of the stream `s`.
|
||||||
|
s.setPositionImpl(s, pos)
|
||||||
|
|
||||||
|
proc getPosition*(s: PStream): int =
|
||||||
|
## retrieves the current position in the stream `s`.
|
||||||
|
result = s.getPositionImpl(s)
|
||||||
|
|
||||||
|
proc getPosition*(s, unused: PStream): int {.deprecated.} =
|
||||||
|
## retrieves the current position in the stream `s`.
|
||||||
|
result = s.getPositionImpl(s)
|
||||||
|
|
||||||
|
proc readData*(s: PStream, buffer: pointer, bufLen: int): int =
|
||||||
|
## low level proc that reads data into an untyped `buffer` of `bufLen` size.
|
||||||
|
result = s.readDataImpl(s, buffer, bufLen)
|
||||||
|
|
||||||
|
proc readData*(s, unused: PStream, buffer: pointer,
|
||||||
|
bufLen: int): int {.deprecated.} =
|
||||||
|
## low level proc that reads data into an untyped `buffer` of `bufLen` size.
|
||||||
|
result = s.readDataImpl(s, buffer, bufLen)
|
||||||
|
|
||||||
|
proc writeData*(s: PStream, buffer: pointer, bufLen: int) =
|
||||||
|
## low level proc that writes an untyped `buffer` of `bufLen` size
|
||||||
|
## to the stream `s`.
|
||||||
|
s.writeDataImpl(s, buffer, bufLen)
|
||||||
|
|
||||||
|
proc writeData*(s, unused: PStream, buffer: pointer,
|
||||||
|
bufLen: int) {.deprecated.} =
|
||||||
|
## low level proc that writes an untyped `buffer` of `bufLen` size
|
||||||
|
## to the stream `s`.
|
||||||
|
s.writeDataImpl(s, buffer, bufLen)
|
||||||
|
|
||||||
proc write*[T](s: PStream, x: T) =
|
proc write*[T](s: PStream, x: T) =
|
||||||
## generic write procedure. Writes `x` to the stream `s`. Implementation:
|
## generic write procedure. Writes `x` to the stream `s`. Implementation:
|
||||||
|
|
@ -35,22 +97,22 @@ proc write*[T](s: PStream, x: T) =
|
||||||
## s.writeData(s, addr(x), sizeof(x))
|
## s.writeData(s, addr(x), sizeof(x))
|
||||||
var y: T
|
var y: T
|
||||||
shallowCopy(y, x)
|
shallowCopy(y, x)
|
||||||
s.writeData(s, addr(y), sizeof(y))
|
writeData(s, addr(y), sizeof(y))
|
||||||
|
|
||||||
proc write*(s: PStream, x: string) =
|
proc write*(s: PStream, x: string) =
|
||||||
## writes the string `x` to the the stream `s`. No length field or
|
## writes the string `x` to the the stream `s`. No length field or
|
||||||
## terminating zero is written.
|
## terminating zero is written.
|
||||||
s.writeData(s, cstring(x), x.len)
|
writeData(s, cstring(x), x.len)
|
||||||
|
|
||||||
proc read[T](s: PStream, result: var T) =
|
proc read[T](s: PStream, result: var T) =
|
||||||
## generic read procedure. Reads `result` from the stream `s`.
|
## generic read procedure. Reads `result` from the stream `s`.
|
||||||
if s.readData(s, addr(result), sizeof(T)) != sizeof(T):
|
if readData(s, addr(result), sizeof(T)) != sizeof(T):
|
||||||
raise newEIO("cannot read from stream")
|
raise newEIO("cannot read from stream")
|
||||||
|
|
||||||
proc readChar*(s: PStream): char =
|
proc readChar*(s: PStream): char =
|
||||||
## reads a char from the stream `s`. Raises `EIO` if an error occured.
|
## reads a char from the stream `s`. Raises `EIO` if an error occured.
|
||||||
## Returns '\0' as an EOF marker.
|
## Returns '\0' as an EOF marker.
|
||||||
discard s.readData(s, addr(result), sizeof(result))
|
discard readData(s, addr(result), sizeof(result))
|
||||||
|
|
||||||
proc readBool*(s: PStream): bool =
|
proc readBool*(s: PStream): bool =
|
||||||
## reads a bool from the stream `s`. Raises `EIO` if an error occured.
|
## reads a bool from the stream `s`. Raises `EIO` if an error occured.
|
||||||
|
|
@ -84,14 +146,14 @@ proc readStr*(s: PStream, length: int): TaintedString =
|
||||||
## reads a string of length `length` from the stream `s`. Raises `EIO` if
|
## reads a string of length `length` from the stream `s`. Raises `EIO` if
|
||||||
## an error occured.
|
## an error occured.
|
||||||
result = newString(length).TaintedString
|
result = newString(length).TaintedString
|
||||||
var L = s.readData(s, addr(string(result)[0]), length)
|
var L = readData(s, addr(string(result)[0]), length)
|
||||||
if L != length: setLen(result.string, L)
|
if L != length: setLen(result.string, L)
|
||||||
|
|
||||||
proc readLine*(s: PStream): TaintedString =
|
proc readLine*(s: PStream): TaintedString =
|
||||||
## Reads a line from a stream `s`. Note: This is not very efficient. Raises
|
## Reads a line from a stream `s`. Note: This is not very efficient. Raises
|
||||||
## `EIO` if an error occured.
|
## `EIO` if an error occured.
|
||||||
result = TaintedString""
|
result = TaintedString""
|
||||||
while not s.atEnd(s):
|
while not atEnd(s):
|
||||||
var c = readChar(s)
|
var c = readChar(s)
|
||||||
if c == '\c':
|
if c == '\c':
|
||||||
c = readChar(s)
|
c = readChar(s)
|
||||||
|
|
@ -140,12 +202,12 @@ proc newStringStream*(s: string = ""): PStringStream =
|
||||||
new(result)
|
new(result)
|
||||||
result.data = s
|
result.data = s
|
||||||
result.pos = 0
|
result.pos = 0
|
||||||
result.close = ssClose
|
result.closeImpl = ssClose
|
||||||
result.atEnd = ssAtEnd
|
result.atEndImpl = ssAtEnd
|
||||||
result.setPosition = ssSetPosition
|
result.setPositionImpl = ssSetPosition
|
||||||
result.getPosition = ssGetPosition
|
result.getPositionImpl = ssGetPosition
|
||||||
result.readData = ssReadData
|
result.readDataImpl = ssReadData
|
||||||
result.writeData = ssWriteData
|
result.writeDataImpl = ssWriteData
|
||||||
|
|
||||||
type
|
type
|
||||||
PFileStream* = ref TFileStream ## a stream that encapsulates a `TFile`
|
PFileStream* = ref TFileStream ## a stream that encapsulates a `TFile`
|
||||||
|
|
@ -153,6 +215,7 @@ type
|
||||||
f: TFile
|
f: TFile
|
||||||
|
|
||||||
proc fsClose(s: PStream) = close(PFileStream(s).f)
|
proc fsClose(s: PStream) = close(PFileStream(s).f)
|
||||||
|
proc fsFlush(s: PStream) = flushFile(PFileStream(s).f)
|
||||||
proc fsAtEnd(s: PStream): bool = return EndOfFile(PFileStream(s).f)
|
proc fsAtEnd(s: PStream): bool = return EndOfFile(PFileStream(s).f)
|
||||||
proc fsSetPosition(s: PStream, pos: int) = setFilePos(PFileStream(s).f, pos)
|
proc fsSetPosition(s: PStream, pos: int) = setFilePos(PFileStream(s).f, pos)
|
||||||
proc fsGetPosition(s: PStream): int = return int(getFilePos(PFileStream(s).f))
|
proc fsGetPosition(s: PStream): int = return int(getFilePos(PFileStream(s).f))
|
||||||
|
|
@ -168,12 +231,13 @@ proc newFileStream*(f: TFile): PFileStream =
|
||||||
## creates a new stream from the file `f`.
|
## creates a new stream from the file `f`.
|
||||||
new(result)
|
new(result)
|
||||||
result.f = f
|
result.f = f
|
||||||
result.close = fsClose
|
result.closeImpl = fsClose
|
||||||
result.atEnd = fsAtEnd
|
result.atEndImpl = fsAtEnd
|
||||||
result.setPosition = fsSetPosition
|
result.setPositionImpl = fsSetPosition
|
||||||
result.getPosition = fsGetPosition
|
result.getPositionImpl = fsGetPosition
|
||||||
result.readData = fsReadData
|
result.readDataImpl = fsReadData
|
||||||
result.writeData = fsWriteData
|
result.writeDataImpl = fsWriteData
|
||||||
|
result.flushImpl = fsFlush
|
||||||
|
|
||||||
proc newFileStream*(filename: string, mode: TFileMode): PFileStream =
|
proc newFileStream*(filename: string, mode: TFileMode): PFileStream =
|
||||||
## creates a new stream from the file named `filename` with the mode `mode`.
|
## creates a new stream from the file named `filename` with the mode `mode`.
|
||||||
|
|
|
||||||
|
|
@ -2040,23 +2040,23 @@ proc `+=`*[T](x, y: ordinal[T]) {.magic: "Inc", noSideEffect.}
|
||||||
proc `-=`*[T](x, y: ordinal[T]) {.magic: "Dec", noSideEffect.}
|
proc `-=`*[T](x, y: ordinal[T]) {.magic: "Dec", noSideEffect.}
|
||||||
## Decrements an ordinal
|
## Decrements an ordinal
|
||||||
|
|
||||||
proc `*=`*[T](x: var ordinal[T], y: ordinal[T]) {.inline noSideEffect.} =
|
proc `*=`*[T](x: var ordinal[T], y: ordinal[T]) {.inline, noSideEffect.} =
|
||||||
## Binary `*=` operator for oridinals
|
## Binary `*=` operator for ordinals
|
||||||
x = x * y
|
x = x * y
|
||||||
|
|
||||||
proc `+=` *(x: var float, y:float) {.inline noSideEffect.} =
|
proc `+=` *(x: var float, y:float) {.inline, noSideEffect.} =
|
||||||
## Increments in placee a floating point number
|
## Increments in placee a floating point number
|
||||||
x = x + y
|
x = x + y
|
||||||
|
|
||||||
proc `-=` *(x: var float, y:float) {.inline noSideEffect.} =
|
proc `-=` *(x: var float, y:float) {.inline, noSideEffect.} =
|
||||||
## Decrements in place a floating point number
|
## Decrements in place a floating point number
|
||||||
x = x - y
|
x = x - y
|
||||||
|
|
||||||
proc `*=` *(x: var float, y:float) {.inline noSideEffect.} =
|
proc `*=` *(x: var float, y:float) {.inline, noSideEffect.} =
|
||||||
## Multiplies in place a floating point number
|
## Multiplies in place a floating point number
|
||||||
x = x * y
|
x = x * y
|
||||||
|
|
||||||
proc `/=` *(x: var float, y:float) {.inline noSideEffect.} =
|
proc `/=` *(x: var float, y:float) {.inline, noSideEffect.} =
|
||||||
## Divides in place a floating point number
|
## Divides in place a floating point number
|
||||||
x = x / y
|
x = x / y
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,9 @@ Changes affecting backwards compatibility
|
||||||
``os.removeDir``.
|
``os.removeDir``.
|
||||||
- Operators now have diffent precedence rules: Assignment-like operators
|
- Operators now have diffent precedence rules: Assignment-like operators
|
||||||
(like ``*=``) are now special-cased.
|
(like ``*=``) are now special-cased.
|
||||||
|
- The fields in ``TStream`` have been renamed to have an ``Impl`` suffix
|
||||||
|
because they should not be used directly anymore.
|
||||||
|
Wrapper procs have been created that should be used instead.
|
||||||
|
|
||||||
|
|
||||||
Language Additions
|
Language Additions
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue