• Read from memory like from a file

    From Helmut Giese@21:1/5 to All on Sun Dec 18 17:00:40 2022
    Hello out there,
    I have a script which expects to receive its input via a file handle.
    I, however, have the prospective input in form of a string in memory
    and I would hate to have to write it to a file just to be able to use
    the script.
    Q: Is there some mechanism to get a file a handle to memory which I
    then could pass to 'gets'? I thought of 'memchan' but wasn't
    successful.
    Any help or tip will be greatly appreciated
    Helmut

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Helmut Giese@21:1/5 to Helmut Giese on Sun Dec 18 17:40:36 2022
    Helmut Giese <hgiese@ratiosoft.com> schrieb:

    Hello out there,
    I have a script which expects to receive its input via a file handle.
    I, however, have the prospective input in form of a string in memory
    and I would hate to have to write it to a file just to be able to use
    the script.
    Q: Is there some mechanism to get a file a handle to memory which I
    then could pass to 'gets'? I thought of 'memchan' but wasn't
    successful.
    Any help or tip will be greatly appreciated
    Helmut
    Never mind, I think I found a simple solution: faking 'gets':
    - Starting from the beginning look for the next '\n'.
    - Return the text just up to the '\n' and increment 'start' just past
    the '\n'.
    - Repeat till the end of text.

    It helps to formulate a question - sometimes soon afterwards a
    solution presents itself.
    Helmut

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From heinrichmartin@21:1/5 to Helmut Giese on Mon Dec 19 00:59:24 2022
    On Sunday, December 18, 2022 at 5:40:42 PM UTC+1, Helmut Giese wrote:
    Helmut Giese schrieb:
    I thought of 'memchan' but wasn't
    successful.

    You meant tcl::chan::string, didn't you?
    I remember me also quitting these memchans, but I cannot recall the exact reason/problem.
    Can your issue be reproduced/presented with feasible effort?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Schelte@21:1/5 to Helmut Giese on Mon Dec 19 11:37:22 2022
    On 18/12/2022 17:00, Helmut Giese wrote:
    Q: Is there some mechanism to get a file a handle to memory which I
    then could pass to 'gets'? I thought of 'memchan' but wasn't
    successful.

    What do you mean with "memory"? Is the data a constant in your script,
    do you have a variable that contains the data, is the data the result of
    some command, or something else?

    If the data is in a variable, you can use tcl::chan::variable:

    package require tcl::chan::variable
    set var "Some string\ncontaining multiple lines"

    set fd [::tcl::chan::variable var]

    puts [gets $fd]
    puts [tell $fd]
    seek $fd 0
    puts [read $fd]
    close $fd

    For other cases, tcl::chan::string may be a better fit. It works pretty
    much the same as the above code.


    Schelte.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Helmut Giese@21:1/5 to All on Tue Dec 20 17:32:26 2022
    Hi heinrichmartin,

    You meant tcl::chan::string, didn't you?
    ähem, no - I really meant memchan.

    I remember me also quitting these memchans, but I cannot recall the exact reason/problem.
    Can your issue be reproduced/presented with feasible effort?
    I only did really naively something like
    set chan [tcl::chan::memchan]
    set txt <some file>
    puts $chan $txt
    while {[gets $chan line] >= 0} {
    puts "[incr lineNumber]: $line"
    }
    which didn't work.

    But now that I know about chan::variable and friends I think I know
    what is needed.
    Thanks Helmut

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Helmut Giese@21:1/5 to All on Tue Dec 20 17:23:31 2022
    Hi Schelte,
    What do you mean with "memory"? Is the data a constant in your script,
    do you have a variable that contains the data, is the data the result of
    some command, or something else?

    If the data is in a variable, you can use tcl::chan::variable:

    package require tcl::chan::variable
    set var "Some string\ncontaining multiple lines"

    set fd [::tcl::chan::variable var]

    puts [gets $fd]
    puts [tell $fd]
    seek $fd 0
    puts [read $fd]
    close $fd

    For other cases, tcl::chan::string may be a better fit. It works pretty
    much the same as the above code.
    that's a good tip. I wasn't aware of the 'channel' command.
    Thanks
    Helmut

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Ralf Fassel on Tue Dec 20 17:12:25 2022
    Ralf Fassel <ralfixx@gmx.de> wrote:
    * Helmut Giese <hgiese@ratiosoft.com>
    | >I remember me also quitting these memchans, but I cannot recall
    | >the exact reason/problem.
    | >Can your issue be reproduced/presented with feasible effort?
    | I only did really naively something like
    | set chan [tcl::chan::memchan]
    | set txt <some file>
    | puts $chan $txt
    | while {[gets $chan line] >= 0} {
    | puts "[incr lineNumber]: $line"
    | }
    | which didn't work.

    Playing around with that it seems that the input and output positions
    of the stream share a common state, i.e. after the 'puts $chan $txt'
    the reading side is also at EOF.
    If you do a seek to the beginning

    puts $chan $txt
    chan seek $chan 0

    prior to the following gets, you can read the $txt line by line.

    Assuming that 'memchan' presents the usual file semantics, then this is identical to how one has to access a file. Writing data leaves the
    file pointer at EOF, and to read previously written data requires [1]
    seeking back to the beginning (or the start of the part that is to be
    reread).

    Just normal file semantics.

    [1] As well as the file having been opened in read/write mode -- which memchan's seem to be default read/write.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ralf Fassel@21:1/5 to All on Tue Dec 20 17:50:15 2022
    * Helmut Giese <hgiese@ratiosoft.com>
    | >I remember me also quitting these memchans, but I cannot recall the exact reason/problem.
    | >Can your issue be reproduced/presented with feasible effort?
    | I only did really naively something like
    | set chan [tcl::chan::memchan]
    | set txt <some file>
    | puts $chan $txt
    | while {[gets $chan line] >= 0} {
    | puts "[incr lineNumber]: $line"
    | }
    | which didn't work.

    Playing around with that it seems that the input and output positions of
    the stream share a common state, i.e. after the 'puts $chan $txt' the
    reading side is also at EOF.
    If you do a seek to the beginning

    puts $chan $txt
    chan seek $chan 0

    prior to the following gets, you can read the $txt line by line.

    R'

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Helmut Giese on Tue Dec 20 17:09:44 2022
    Helmut Giese <hgiese@ratiosoft.com> wrote:
    Hi heinrichmartin,

    You meant tcl::chan::string, didn't you?
    ähem, no - I really meant memchan.

    I remember me also quitting these memchans, but I cannot recall the
    exact reason/problem.
    Can your issue be reproduced/presented with feasible effort?
    I only did really naively something like
    set chan [tcl::chan::memchan]
    set txt <some file>
    puts $chan $txt
    while {[gets $chan line] >= 0} {
    puts "[incr lineNumber]: $line"
    }
    which didn't work.

    You forgot to 'seek $chan 0' there to rewind the channel to the
    beginning before trying to read it. You should have gotten an eof
    immediately with that code, which would be why it did not seem to work.

    $ rlwrap tclsh
    % package require tcl::chan::memchan
    1.0.4
    % set chan [tcl::chan::memchan]
    rc0
    % set txt "line 1\nline 2\nline 3\n"
    line 1
    line 2
    line 3

    % puts $chan $txt
    % seek $chan 0
    % while {[gets $chan line] >= 0} {
    puts "[incr lineNumber]: $line"
    }
    1: line 1
    2: line 2
    3: line 3
    4:
    %

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Helmut Giese@21:1/5 to All on Tue Dec 20 21:21:24 2022
    You forgot to 'seek $chan 0' there to rewind the channel to the
    beginning before trying to read it. You should have gotten an eof >immediately with that code, which would be why it did not seem to work.

    $ rlwrap tclsh
    % package require tcl::chan::memchan
    1.0.4
    % set chan [tcl::chan::memchan]
    rc0
    % set txt "line 1\nline 2\nline 3\n"
    line 1
    line 2
    line 3

    % puts $chan $txt
    % seek $chan 0
    % while {[gets $chan line] >= 0} {
    puts "[incr lineNumber]: $line"
    }
    1: line 1
    2: line 2
    3: line 3
    4:
    %
    Tcl never ceases to surprise me. Thank you both, Rich and Ralf, for
    teaching me.
    Helmut

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)