[plt-scheme] writing to subprocess's stdin and then...

From: Chongkai Zhu (czhu at cs.utah.edu)
Date: Tue Jun 17 10:28:31 EDT 2008

I have been through the same topic. First I tried to just pass #f to 
subprocess, and as Eli said, if the process write too much data, 
deadlock happens. Then I also noticed that file-port instead of a normal 
port, so my final code looks like:


      (let ((f2 (make-temporary-file)))
        (let-values (((process dummy stdin stderr)
                      (subprocess (open-output-file f2 'replace)
                                  #f #f
                                  "command line"
                                  )))
          (subprocess-wait process)
          (close-output-port stdin)
          (unless (eof-object? (read stderr))
            (error (read-line stderr)))
          (close-input-port stderr))
        (let ((stdout (open-input-file f2)))
          (read stdout)

Hope that helps.

Chongkai

Andrew Reilly wrote:
> Hi Eli,
>
> I'm glad that this topic came up, because I was playing with just
> these issues last weekend.  I had been using process rather than
> subprocess (so I had to make up some amusing string quoting to
> pass in complicated, space-containing file names), and it mostly
> worked, but I got the occasional hang, which I suspect was
> because of the blocking/deadlock issues that you mentioned.
>
> Anyway, I've just tried a variation on your version:
>
> On Tue, 17 Jun 2008 04:49:10 -0400
> Eli Barzilay <eli at barzilay.org> wrote:
>   
>> Here's the revised example -- with no use of threads.
>>
>>  | #lang scheme
>>  | 
>>  | (require scheme/port)
>>  | (define (with-input-from-subprocess exe thunk)
>>  |   (define-values (p pout pin perr)
>>  |     (subprocess #f #f (current-error-port)
>>  |                 (find-executable-path exe)))
>>  |   (close-output-port pin)
>>  |   (parameterize ([current-input-port pout])
>>  |     (begin0 (thunk)
>>  |       (subprocess-wait p))))
>>  | 
>>  | (with-input-from-subprocess "du"
>>  |   (lambda ()
>>  |     (for ([line (in-lines)])
>>  |       (printf ">> ~s\n" (regexp-split #rx"[/\t]" line)))))
>>     
>
> Specifically, my version looks like:
>
> (define (with-input-from-subprocess thunk exe . args)
>   (define-values (p pout pin perr)
>     (apply subprocess (append (list #f #f (current-error-port)
>                                     (find-executable-path exe))
>                               args)))
>   (close-output-port pin)
>   (parameterize ((current-input-port pout))
>     (begin0 (thunk)
>             (subprocess-wait p))))
>
> ; process individual tracks: do the real work
>
> (define (get-flac-meta file)
>   (make-immutable-hash
>    (with-input-from-subprocess
>     (lambda ()
>       (let all ()
>         (match (read-line)
>           ((regexp #rx"(.*)=(.*)" (list _ tag val)) (cons (cons tag val) (all)))
>           (_ '()))))
>     "metaflac" "--export-tags-to=-" (path->string file))))
>
> The problem is that this produces an error at run-time:
> subprocess: expects type <file-stream-output-port> as 3rd
> argument, given: #<output-port>; other arguments were: #f #f
> #<path:/usr/local/bin/metaflac> "--export-tags-to=-" "some file
> name..."
>
> Should subprocess really be so picky?  I suppose that it has to
> be, because the unix process wants a real file descriptor.  The
> current-error-port in this case is that of the drscheme
> environment.  Seems to work OK from mzscheme on the command line.
>
> Cheers,
>
>   


Posted on the users mailing list.