Skip to content

Add COB_SET_RUNTIME_STDOUT_FILE and COB_SET_RUNTIME_STDERR_FILE runtime options to enable redirection of stdout/stderr output#296

Draft
oguzcankirmemis wants to merge 24 commits into
OCamlPro:gitside-gnucobol-3.xfrom
oguzcankirmemis:feature/stdout-stderr-redirect
Draft

Add COB_SET_RUNTIME_STDOUT_FILE and COB_SET_RUNTIME_STDERR_FILE runtime options to enable redirection of stdout/stderr output#296
oguzcankirmemis wants to merge 24 commits into
OCamlPro:gitside-gnucobol-3.xfrom
oguzcankirmemis:feature/stdout-stderr-redirect

Conversation

@oguzcankirmemis

Copy link
Copy Markdown

This PR adds runtime options COB_SET_RUNTIME_STDOUT_FILE and COB_SET_RUNTIME_STDERR_FILE which allows control over the location where the stdout/stderr output is written.

Motivation

For modules written in C that interact with libcob, it is currently difficult to change the location of stdout/stderr output without disturbing the stdout/stderr of the whole process (i.e., other threads). This is especially useful for thread applications, where it is desired that each thread gets its own stdout/stderr without disturbing the one another.

With these options, the main program can easily redirect the output of the COBOL program (including the messages from the runtime itself) and decide what to do with it. For that reason, the main program is also responsible for managing the lifetime of the passed stdout/stderr files, should they be used.

Implementation

  • Add COB_SET_RUNTIME_STDOUT_FILE and COB_SET_RUNTIME_STDERR_FILE options to cob_runtime_option_switch in common.h.
  • Extend the cob_settings in coblocal.h to store the location of configured stdout/stderr. By default, they are initialized to stdout/stderr of the process.
  • Add support for both options in cob_set_runtime_option and cob_get_runtime_option in common.c.
  • Adjust all print statements in across all various files in the runtime, i.e., under ./libcob, so that they behave accordingly.
  • Document both options in doc/gnucobol.texi.

- Defaults back to regular stdout and stderr, if the runtime configurations are not set

Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
@oguzcankirmemis

Copy link
Copy Markdown
Author

@GitMensch Here is the promised PR for stdout/stderr redirection. I opened it in draft for now to clarify a small issue in libcob/cobgetopt.c: Since the cobsetptr is currently not exposed in this file, my naive way of doing the redirection is not possible without further adjustment. How should we proceed here?

I also feel like implementing the redirection in some places seemed unnecessary to me, with the thought that they were meant for direct usage over the command line, rather than a C module interacting with GnuCOBOL. I would appreciate if you could check in general where it makes sense, or whether there are still places missing, where we need to the redirection.

As always, always glad and available for further questions and discussions. Thanks for the support!

@oguzcankirmemis

Copy link
Copy Markdown
Author

I can confirm that the failing tests in CI (should be seven in total) are related to the PR, will investigate.

Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
…f cobsetptr not initialized

Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
@oguzcankirmemis

Copy link
Copy Markdown
Author

All tests should be fixed now, the issue was cob_runtime_warning, cob_runtime_error and cob_runtime_hint can be called from other modules (like cobc) without initializing the cobsetptr (i.e. cob_settings) in common.c. Upon looking closer, I also discovered that there is also cob_runtime_warning_ss for the signal handler, that directly uses the file descriptor of stderr. I believe, we can't use the FILE pointer there since fileno would not be signal handler safe.. I am leaving as it is for now, is this fine?

@oguzcankirmemis

Copy link
Copy Markdown
Author

Not sure what is going on with Windows CI tests, and the vbisam one, but I believe it is unrelated?

@GitMensch GitMensch left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also add those two as "normal" runtime settings COB_STDOUT_FILE and COB_STDERR_FILE with the common file handling (like + opening the file as append), this allows users to both set the filename within a COBOL thread via SET ENVIRONMENT as well as easily having one per PID (which would be your example).

Not sure, but... would it be reasonable to redirect stdin the same way?

Comment thread libcob/common.c Outdated
Comment thread libcob/fileio.c Outdated
Comment on lines +3637 to +3639
bdb_env->set_errfile (bdb_env, cobsetptr->cob_stderr);
#if (DB_VERSION_MAJOR > 4) || ((DB_VERSION_MAJOR == 4) && (DB_VERSION_MINOR > 2))
bdb_env->set_msgfile (bdb_env, stderr);
bdb_env->set_msgfile (bdb_env, cobsetptr->cob_stderr);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be re-set if the current thread changes the file* ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would I trigger the refresh/re-set in cob_set_runtime_option in that case, by simply adding a non-static getter for bdb_env?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the right way would be to do the same as in screenio - see cob_settings_screenio and its callers... but at least add one exported function into fileio.c that you can call when this specific runtime setting changed

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, let me know if it is missing something.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the only question here is shouldn't the code be moved to the setting function (and that function either be called in the caller or inside this function)?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense, I guess I was trying to be as uninvasive as possible, hence redundant stuff.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have moved the unused (probably deprecated) part of the ifdef to settings as well. My gut feeling was telling me they should stay together.

Comment thread libcob/common.c
Comment thread tests/testsuite.src/run_misc.at Outdated
Comment thread tests/testsuite.src/run_misc.at Outdated
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
@oguzcankirmemis

oguzcankirmemis commented Jul 10, 2026

Copy link
Copy Markdown
Author

Please also add those two as "normal" runtime settings COB_STDOUT_FILE and COB_STDERR_FILE with the common file handling (like + opening the file as append), this allows users to both set the filename within a COBOL thread via SET ENVIRONMENT as well as easily having one per PID (which would be your example).

Not sure, but... would it be reasonable to redirect stdin the same way?

For stdin, I don't have a clue whether it would be useful, so you can decide. I think it wouldn't be too much of an effort.

For adding them as normal runtime settings, how does "SET ENVIRONMENT" work right now for IO files? I thought GnuCOBOL already implements changing the stdout/stderr via SET ENVIRONMENT inside COBOL, that is why I am a little bit confused. I also think if COBOL is the main process, it is actually relatively easy to redirect stdout/stderr 2> /tmp/stderr-location etc., at least in a conventional OS/Shell, so I don't see the benefit there. What am I missing?

Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
@GitMensch

Copy link
Copy Markdown
Collaborator

If stdin is not a big effort, then please add it the same way, covering all internally used streams. We may even use it later for other tests.

For the SET ENVIRONMENT part (possibly more used with runtime configuration file): see cob_check_trace_file - the setting would name a file and it would be internally opened as soon as the runtime setting is set.

Comment thread libcob/common.c Outdated

@GitMensch GitMensch left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there seems to be one missing element used when calling libcob from cobc, but only on Win32 - I guess that's the place where the binary mode is set (unix_lf), as that will only happen this way on win32

That and the stderr_f assignment inlined should fix CI; adding stdin redirection + reassignment for BDB would then finalize the changes.

If you feel that you can't get the part done soon that works on those changes and are likely more often used by "normal" users (three matching runtime settings to assign the streams to a filename) then we can get this in with a follow-up PR or work by someone else.

Comment thread tests/testsuite.src/run_misc.at
- Defaults back to regular stdin, if the runtime configurations are not set

Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
@oguzcankirmemis

oguzcankirmemis commented Jul 12, 2026

Copy link
Copy Markdown
Author

If stdin is not a big effort, then please add it the same way, covering all internally used streams. We may even use it later for other tests.

For the SET ENVIRONMENT part (possibly more used with runtime configuration file): see cob_check_trace_file - the setting would name a file and it would be internally opened as soon as the runtime setting is set.

there seems to be one missing element used when calling libcob from cobc, but only on Win32 - I guess that's the place where the binary mode is set (unix_lf), as that will only happen this way on win32

That and the stderr_f assignment inlined should fix CI; adding stdin redirection + reassignment for BDB would then finalize the changes.

If you feel that you can't get the part done soon that works on those changes and are likely more often used by "normal" users (three matching runtime settings to assign the streams to a filename) then we can get this in with a follow-up PR or work by someone else.

I have added the stdin redirection as well, remaining parts are:

  • Runtime configuration files
  • The issue with Win32

Apart from TODOs I have commented on, some stylings and docs, all parts should be there now. I have changed the test slightly to make it Windows compatible, let's see if CI passes.

Comment thread libcob/cobgetopt.c
{
if (ambig_fallback)
{
/* TODO: Decide how to do stdout/stderr redirection here

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about here? Solve it similarly by adding an exported init function?

Comment thread libcob/common.c Outdated
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
- introduces following runtime configurations: COB_STDIN_FILENAME, COB_STDOUT_FILENAME, COB_STDERR_FILENAME

Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
@oguzcankirmemis

oguzcankirmemis commented Jul 12, 2026

Copy link
Copy Markdown
Author

Remaining failing CI tests should be hopefully unrelated.

Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
@oguzcankirmemis

oguzcankirmemis commented Jul 13, 2026

Copy link
Copy Markdown
Author

Updated docs/changelogs, will mark the PR non-draft, once all the todos are cleared. The one extra failed CI with Ubuntu+MSYS1 should actually pass (i.e. I haven't touched anything other than docs)? Instead, it got broken pipe in SIGPIPE test for some reason.

Comment thread config/runtime.cfg

@GitMensch GitMensch left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ci failures unrelated, most important adjustment is the handling of the setting of the runtime option - the current version won't work if those come from SET ENVIRONMENT (explicit setting in the COBOL main instead of runtime config file / environment)

Comment thread libcob/fileio.c Outdated
Comment on lines +3637 to +3639
bdb_env->set_errfile (bdb_env, cobsetptr->cob_stderr);
#if (DB_VERSION_MAJOR > 4) || ((DB_VERSION_MAJOR == 4) && (DB_VERSION_MINOR > 2))
bdb_env->set_msgfile (bdb_env, stderr);
bdb_env->set_msgfile (bdb_env, cobsetptr->cob_stderr);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the only question here is shouldn't the code be moved to the setting function (and that function either be called in the caller or inside this function)?

Comment thread tests/ChangeLog
Comment thread NEWS Outdated
Comment thread config/runtime.cfg
Comment thread libcob/common.c Outdated
Comment thread libcob/ChangeLog
Comment thread doc/gnucobol.texi
Comment thread libcob/common.c Outdated
Comment thread libcob/common.c Outdated
Comment on lines +10499 to +10529
if (cobsetptr->cob_stdin_filename) {
if (!cobsetptr->cob_unix_lf) {
cobsetptr->cob_stdin =
fopen (cobsetptr->cob_stdin_filename, "r");
} else {
cobsetptr->cob_stdin =
fopen (cobsetptr->cob_stdin_filename, "rb");
}
if (!cobsetptr->cob_stdin) {
cobsetptr->cob_stdin_filename = NULL;
cobsetptr->cob_stdin = stdin;
}
}

if (cobsetptr->cob_stdout_filename) {
cobsetptr->cob_stdout =
cob_open_logfile (cobsetptr->cob_stdout_filename);
if (!cobsetptr->cob_stdout) {
cobsetptr->cob_stdout_filename = NULL;
cobsetptr->cob_stdout = stdout;
}
}

if (cobsetptr->cob_stderr_filename) {
cobsetptr->cob_stderr =
cob_open_logfile (cobsetptr->cob_stderr_filename);
if (!cobsetptr->cob_stderr) {
cobsetptr->cob_stderr_filename = NULL;
cobsetptr->cob_stderr = stderr;
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that part needs to be moved (maybe to termio.c?) and called when one of those runtime settings are changed - and in that case close the old pointer, before opening it again (if the pointer changed and the content differs)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved it, see comment at the bottom.

Comment thread tests/testsuite.src/run_misc.at Outdated
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
@oguzcankirmemis

Copy link
Copy Markdown
Author

ci failures unrelated, most important adjustment is the handling of the setting of the runtime option - the current version won't work if those come from SET ENVIRONMENT (explicit setting in the COBOL main instead of runtime config file / environment)

Makes sense, I will take a look.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 56.32911% with 69 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (gitside-gnucobol-3.x@568531b). Learn more about missing BASE report.

Files with missing lines Patch % Lines
libcob/common.c 52.98% 48 Missing and 15 partials ⚠️
libcob/termio.c 50.00% 5 Missing ⚠️
libcob/screenio.c 66.66% 1 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@                   Coverage Diff                   @@
##             gitside-gnucobol-3.x     #296   +/-   ##
=======================================================
  Coverage                        ?   67.44%           
=======================================================
  Files                           ?       34           
  Lines                           ?    61604           
  Branches                        ?    16045           
=======================================================
  Hits                            ?    41547           
  Misses                          ?    14103           
  Partials                        ?     5954           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
Signed-off-by: Oguzcan Kirmemis <oguzcan.kirmemis@gmail.com>
@oguzcankirmemis

oguzcankirmemis commented Jul 17, 2026

Copy link
Copy Markdown
Author

I think SET ENVIRONMENT should work now, added a test for it. It is kind of messy how I do it in cobsetptr, i.e. having cob_stdout_filename and cob_stdout_filename_set both to remember the old setting in termio.c. I was against the idea of storing them as globals inside termio.c. Let me know if you think there is a better way to achieve the functionality.

There is also the print_version and print_info functions in common.c, that still print to process stdout. I haven't converted them, because I don't see the use case to be honest. But for completeness sake, if you want it, I can change them as well.

Otherwise, from my side all that is missing is what we should with cobgetopt.c. I will make a final pass for news/changelogs etc. once the other changes are finalized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants