command-line-interfacechicken-scheme

chicken-scheme - how does one read all the lines passed in via standard input?


I'm trying to read all the lines of whatever's passed in to a chicken-scheme script via standard in, and put them into a list, but I don't seem to be able to correctly determine when I've hit the end of the input. Another test script seemed to indicate that testing (eof-object? results-of-last-read-line-call) was a legit test, but in the example below it just sits there infinitely reading.

I've put together the following test script. I'm calling it with cat some_file.txt | this_script.scm

#! /usr/local/bin/csi -script

(define (read-from-stdin collection line)
  (if (eof-object? line) ; bad test? 
    collection
     (read-from-stdin (cons collection line) read-line)
  ) ; yes, i know atypical formatting. Done so you can see they're all there
)

(for-each print (read-from-stdin '() (read-line)))

Solution

  • The problem is that you're passing the procedure read-line in the recursive call. This causes the test to always fail (because a procedure is never an eof-object). Instead, you probably want to call read-line and pass the line string:

    (define (read-from-stdin collection line)
      (if (eof-object? line) ; the test is fine
          collection
          (read-from-stdin (cons collection line) (read-line))))
    
    (for-each print (read-from-stdin  '() (read-line)))
    

    You were also calling cons with the arguments reversed, so I fixed that as well. Perhaps this was an attempt at adding the lines in reverse? Instead, you probably want to reverse the lines at the end, so you'd get

    (for-each print (reverse (read-from-stdin  '() (read-line))))
    

    Or of course you could call (reverse collection) in read-from-stdin.