# Can I use with\_output\_to/2 with a foreign function that calls Sprintf()?

**URL:** <https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848>\
**Category:** Help!\
**Tags:** how-to\
**Created:** [September 15, 2023, 5:22am UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848 "2023-09-15T05:22:26Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [September 15, 2023, 5:22am UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/1 "2023-09-15T05:22:26Z")

</div>

I have a foreign predicate written in C that calls `Sprintf()`. For tests, I’d like to capture its output. I tried wrapping with with\_output\_to/2 but that didn’t work.

I can modify the predicate to write to “current output”, except I can’t figure out how to specify “current output” … as far as I can tell, I can only specify `Soutput` or `Serror` … or do I need to pass in the current\_output/1 stream as an argument to the predicate?

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [September 15, 2023, 7:25am UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/2 "2023-09-15T07:25:37Z")

</div>

You can use with\_output\_to/3. It is probably more elegant to pass the stream or even better return the output. If you try to test the Sprintf() family, I’d use Ssprintf() and return the output as a string (AFAIK it is nowadays UTF-8 encoded). In the end they all call the same routine to deal with the format string and arguments, so testing one tests all of them. If you are testing something else I’d also just return a string.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [September 15, 2023, 2:37pm UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/3 "2023-09-15T14:37:26Z")

</div>

What am I doing wrong? The foreign predicate is `pl_write_atoms/1` from `foreign.doc` … the results below show that with\_output\_to/2 doesn’t work when used with write/2 with output to `user_output`:

```prolog
?- with_output_to(string(S), pl_write_atoms([a,b])).
a
b
S = "".

 ?- with_output_to(string(S), write(hello)).
S = "hello".

?- with_output_to(string(S), write(current_output, hello)).
S = "hello".

?- with_output_to(string(S), write(user_output, hello)).
hello
S = "".

```

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [September 15, 2023, 3:01pm UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/4 "2023-09-15T15:01:21Z")

</div>

`with_output_to/2` captures `current_output`. You can capture `user_output` using

```
 ?- with_output_to(string(S), write(user_output, hello),
                   [capture([user_output])]).
 S = "hello".

```

This was introduced with the new testing framework implementation to suppress output of succeeded tests and ensure that output from concurrent failed tests is not interleaved. It is a bit of an emergency that I would only use when really needed. I think it should work when nested inside a test, but I’m not sure.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [September 15, 2023, 3:05pm UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/5 "2023-09-15T15:05:56Z")

</div>

`capture([user_output])` doesn’t work with a foreign predicate, it seems. (Also, it would be nice if this option were documented …)

```prolog
?- with_output_to(string(S), write(user_output, hello), [capture([user_output])]).
S = "hello".

?- with_output_to(string(S), pl_write_atoms([a,b]), [capture([user_output])]).
a
b
S = "".

```

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [September 15, 2023, 3:10pm UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/6 "2023-09-15T15:10:57Z")

</div>

An additional question is: how would I specify `current_output` to `Sfprintf()`? As far as I can tell, there are predefined streams only for `user_output` and `user_error`.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [September 15, 2023, 3:17pm UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/7 "2023-09-15T15:17:58Z")

</div>

> [@peter.ludemann](#):
>
> Also, it would be nice if this option were documented …)

See [streams:with\_output\_to/3](https://www.swi-prolog.org/pldoc/doc_for?object=streams%3Awith_output_to/3)

> [@peter.ludemann](#):
>
> An additional question is: how would I specify `current_output` to `Sfprintf()`? As far as I can tell, there are predefined streams only for `user_output` and `user_error`.

A little search says there is `Sinput`, `Soutput` and `Serror`. these are hard bound to the streams that are the initial stdin/stdout/stderr of the process. SWI-Prolog.h however also defines

```prolog
PL_EXPORT(IOSTREAM *)*_PL_streams(void);	/* base of streams */
#ifndef PL_KERNEL
#define Suser_input (_PL_streams()[0])
#define Suser_output (_PL_streams()[1])
#define Suser_error (_PL_streams()[2])
#define Scurrent_input (_PL_streams()[3])
#define Scurrent_output (_PL_streams()[4])
#endif

```

So, I think `Sfprintf(Scurrent_output, ...)` should do the job. And yes, I fear this is not documented. At least, `git grep` in the `man` directory remains silent ☹

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [September 15, 2023, 3:22pm UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/8 "2023-09-15T15:22:27Z")

</div>

`capture([current_output])` throws an error:

```prolog
?- with_output_to(string(S), write([a,b]), [capture([current_output])]).
ERROR: Type error: `oneof([user_output,user_error])' expected, found `current_output' (an atom)
ERROR: In:
ERROR: [17] throw(error(type_error(...,current_output),_8194))
ERROR: [10] streams:with_output_to(string(_8238),user:write(...),[capture(...)]) at /home/peter/src/swipl-devel/build/home/library/streams.pl:87
ERROR: [9] toplevel_call(user:user: ...) at /home/peter/src/swipl-devel/build/home/boot/toplevel.pl:1173
ERROR: 
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.

```

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [September 15, 2023, 3:37pm UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/9 "2023-09-15T15:37:31Z")

</div>

> [@peter.ludemann](#):
>
> `capture([current_output])` throws an error:

Docs:

> As `current_output` is always captured, the only two values are `user_output` and `user_error`

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [September 15, 2023, 3:39pm UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/10 "2023-09-15T15:39:02Z")

</div>

`Sfprintf(Suser_output, ...)` works as expected with with\_output\_to/3.

However `Sprintf(...)` and `Sprintf(Suser, ...)` don’t work with with\_output\_to/3.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [September 15, 2023, 3:47pm UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/11 "2023-09-15T15:47:43Z")

</div>

> [@peter.ludemann](#):
>
> However `Sprintf(...)` and `Sprintf(Suser, ...)` don’t work with with\_output\_to/3.

`Sprintf(Suser,` is invalid Suser does not exist and Sprintf() wants a format as first argument. Sprintf() is defined to print to `Soutput` that is the stream bound to the OS file handle `1`. Whether that is a good idea or not, I don’t know. I can think of arguments either way. As is, `pl-stream.c` started life completely independent from SWI-Prolog. Later some Prolog specific things were added (notably to improve error handling).

I don’t think I ever use it. Debugging uses Sdprintf() and just about any other case you have a concrete stream handle to write to.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [September 15, 2023, 3:56pm UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/12 "2023-09-15T15:56:05Z")

</div>

> [@jan](#):
>
> `Sprintf(Suser,` is invalid Suser does not exist and Sprintf() wants a format as first argument

Sorry - typo - I used `Sfprintf(Suser, ...)`. `Suser` is defined in `SWI-Streams.h`, which is why I didn’t notice the other definitions in `SWI-Prolog.h`. I’ll update the documentation and the examples in `foreign.doc`.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [September 15, 2023, 4:12pm UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/13 "2023-09-15T16:12:30Z")

</div>

> [@peter.ludemann](#):
>
> `Suser` is defined in `SWI-Streams.h`

??

```
 grep Suser os/SWI-Stream.h
 <nothing>

```

`user` is, AFAIK, only accessible as alias at the Prolog level for backward compatibility, where it means either `user_input` or `user_output`, depending on whether we want an input or output stream. I hope it is deprecated 🙂

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [September 15, 2023, 4:26pm UTC](https://swi-prolog.discourse.group/t/can-i-use-with-output-to-2-with-a-foreign-function-that-calls-sprintf/6848/14 "2023-09-15T16:26:37Z")

</div>

> [@jan](#):
>
> `grep Suser os/SWI-Stream.h`

I really shouldn’t post things before coffee. 🙂

I meant `Soutput` and `Serror`.
