better streams implemenation; fixes #63

This commit is contained in:
Araq 2011-11-12 02:10:07 +01:00
commit 40fa4bb52d
5 changed files with 112 additions and 45 deletions

View file

@ -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!
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------

View file

@ -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)

View file

@ -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`.

View file

@ -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

View file

@ -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