0

I have implemented a cat program in SWI-Prolog by using copy_stream_data.

File args.pl:

:- module(args, [withFilesOrUserInput/2]).

withFilesOrUserInput(StreamFunction, []) :-
    call(StreamFunction, user_input).

withFilesOrUserInput(StreamFunction, [Filename]) :-
    withFile(StreamFunction, Filename).

withFilesOrUserInput(StreamFunction, [Head|Tail]) :-
    withFile(StreamFunction, Head),
    withFilesOrUserInput(StreamFunction, Tail).

withFile(StreamFunction, Filename) :-
    open(Filename, read, StreamIn),
    call(StreamFunction, StreamIn),
    close(StreamIn).

File cat.pl:

:- use_module(args).

main(Argv) :-
    withFilesOrUserInput(catStream, Argv).

catStream(Stream) :-
    copy_stream_data(Stream, user_output),
    flush_output(user_output).

When I use the program to cat from stdin to stdout, it prints a prompt |: where it expects input from stdin. How can I avoid that prompt?

false
  • 10,264
  • 13
  • 101
  • 209
Christian Hujer
  • 17,035
  • 5
  • 40
  • 47
  • 1
    (Not an answer, but a comment to your code) There is `setup_call_cleanup/3` to handle such situations properly. In your version, a failing or erroneous `call(StreamFunction, StreamIn)` would not close the stream. And if you have several answers, you will try to access an already closed stream. – false Aug 27 '15 at 06:47
  • Ya I'm still learning how to do I/O in Prolog properly. Let's see when I learn how to use `setup_call_cleanup/3` properly, maybe today, maybe tomorrow. However, I don't see how several answers would lead to accessing an already closed stream, but maybe there's something about this which I don't understand yet? – Christian Hujer Aug 27 '15 at 14:45

1 Answers1

0

The |: prompt only appears when stdout is a terminal. It does not appear when stdout is a file. So, it won't cause garbage in the output when your output is redirected to a file. But still, it's not nice.

In order to avoid the prompt, clear it using the built-in predicate prompt, like this: prompt(_, ''), which you could insert into your main(Argv) predicate:

main(Argv) :-
    prompt(_, ''),
    withFilesOrUserInput(catStream, Argv).

You could also put a clause with the prompt(_, '') predicate at program start, by inserting the following at the top of the code:

 :- prompt(_, '').

You could even do that in the module, after the :- module() clause.

Christian Hujer
  • 17,035
  • 5
  • 40
  • 47
  • Avoid that hack at any price. – false Aug 27 '15 at 06:44
  • @false Why do you think that it is a hack that should be avoided? I'm not aware that any other language starts prompting in such a strange way just because the program starts reading from `stdin` when `stdout` is a terminal. It is not even logical, I think it's a bug. It only makes sense to prompt when both, `stdin` and `stdout` are a terminal. But when the program is called like `prolog -qt main cat.pl – Christian Hujer Aug 27 '15 at 08:10
  • It's a hack because you are changing global state for something that was written to be used interactively. You got some point on this though. Other, more conforming systems (e.g. SICStus) only show this prompt when the input is a terminal. – false Aug 27 '15 at 09:53