Piping terminal output to file from within C program - c

I would like everything that gets output to stdout to also be saved in a file in my C code. I know that I can do this by calling the process on the command line and piping it to a file:
myprogram.exe 1>logfile.txt
for example. But I am wondering if there is a way to do this from within the C code itself. Is there a function in the printf() family that can output to both the terminal and a specified file with the same arguments?
If not, what would be the syntax required to write my own printf()-style function which calls both printf() and fprintf() within it, using the same argument style as printf()?

Going off the suggestion to use variadic functions:
#include <stdio.h>
#include <stdarg.h>
/*
* Not all compilers provide va_copy(), but __va_copy() is a
* relatively common pre-C99 extension.
*/
#ifndef va_copy
#ifdef __va_copy
#define va_copy(dst, src) __va_copy((dst), (src))
#endif
#endif
#ifdef va_copy
#define HAVE_VACOPY 1
#endif
int
ftee(FILE *outfile, const char *format, ...)
{
int result;
va_list ap;
#if HAVE_VACOPY
va_list ap_copy;
#endif
va_start(ap, format);
#if HAVE_VACOPY
va_copy(ap_copy, ap);
result = vfprintf(outfile, format, ap_copy);
va_end(ap_copy);
if (result >= 0)
result = vprintf(format, ap);
#else
result = vfprintf(outfile, format, ap);
if (result >= 0) {
va_end(ap);
va_start(ap, outfile);
result = vprintf(format, ap);
}
#endif
va_end(ap);
return result;
}
That can be used like the standard fprintf function in that you specify an output file, except it will also write the normal output to stdout. I attempted to support relatively recent compilers that still didn't have a va_copy() macro (defined in C99) such as that which comes with Visual Studio 2012 (VS2013 finally has one). Some C runtimes also conditionally define va_copy() such that compiling with strict C89/C90 mode enabled will make it undefined while __va_copy() may remain defined.

You can use the fprintf() function, which is quite similar to printf() in the way it works.
Here is an example:
FILE *fp;
int var = 5;
fp = fopen("file_name.txt", "w");// "w" means that we are going to write on this file
fprintf(fp, "Writting to the file. This is an int variable: %d", var);
The output on your file would be this:
This is being written in the file. This is an int variable: 5
N.B: Opening the file using w as parameter will destroy the file's content every time you open it.
For writing to a file you have to use file operation commands, it is not possible to write to a file using printf (it prints only to the stdout). You can use:
sprintf(buf,"%d",var); //for storing in the buffer
printf(buf); //output to stdout
fputs(buf, fp); //output to file

Related

C: passing arguments from variadic function to variadic macro

I have a standard logging API built into my C code, a nice simple logF(const char *pFormat, ...) thing which has always, so far, been mapped to vprintf(), i.e.:
void logF(const char *pFormat, ...)
{
va_list args;
va_start(args, pFormat);
vprintf(pFormat, args);
va_end(args);
}
The C code above this API must work on multiple embedded platforms. I've just reached a platform (Nordic NRF52840) where the underlying logging interface I have to work with is presented as a variadic macro of the form NRF_LOG_INFO(...).
QUESTION: how do I correctly pass fn(const char *pFormat, ...) into a BLAH(...) macro? My brain hurts....
This is with GCC 4.9.3, though it would be nice to have a solution that is relatively relaxed about C compiler version.
EDIT 1: noted that I could redefine my logF() function to be a variadic macro and map it there, the issue is that I would then have a platform-specific header file rather than a generic one, I would have to move it down into the platform code and have one for each. Not impossible but more messy.
EDIT 2: I was asked for the trail of how NRF_LOG_INFO() expands. Here's the relevant output of the pre-processor:
#define NRF_LOG_INFO(...) NRF_LOG_INTERNAL_INFO( __VA_ARGS__)
#define NRF_LOG_INTERNAL_INFO(...) NRF_LOG_INTERNAL_MODULE(NRF_LOG_SEVERITY_INFO, NRF_LOG_SEVERITY_INFO, __VA_ARGS__)
#define NRF_LOG_INTERNAL_MODULE(level,level_id,...) if (NRF_LOG_ENABLED && (NRF_LOG_LEVEL >= level) && (level <= NRF_LOG_DEFAULT_LEVEL)) { if (NRF_LOG_FILTER >= level) { LOG_INTERNAL(LOG_SEVERITY_MOD_ID(level_id), __VA_ARGS__); } }
#define LOG_INTERNAL(type,...) LOG_INTERNAL_X(NUM_VA_ARGS_LESS_1( __VA_ARGS__), type, __VA_ARGS__)
#define LOG_INTERNAL_X(N,...) CONCAT_2(LOG_INTERNAL_, N) (__VA_ARGS__)
Then depending on number of args, anything up to:
#define LOG_INTERNAL_6(type,str,arg0,arg1,arg2,arg3,arg4,arg5) nrf_log_frontend_std_6(type, str, (uint32_t)(arg0), (uint32_t)(arg1), (uint32_t)(arg2), (uint32_t)(arg3), (uint32_t)(arg4), (uint32_t)(arg5))
void nrf_log_frontend_std_6(uint32_t severity_mid,
char const * const p_str,
uint32_t val0,
uint32_t val1,
uint32_t val2,
uint32_t val3,
uint32_t val4,
uint32_t val5);
It is not possible to pass the arguments from a variadic function to a variadic macro.
As you want to hide the platform specific macro call from the API header you can process the function arguments with vsnprintf instead of vprintf and call the logging macro with format "%s" and the resulting string buffer.
void logF(const char *pFormat, ...)
{
va_list args;
/* Choose a reasonable size or replace with dynamic allocation based on the return value of vsnprintf */
/* This could also be a static variable or a global variable to avoid allocation of a big buffer on the stack. */
char buffer[1024];
va_start(args, pFormat);
vsnprintf(buffer, sizeof(buffer), pFormat, args);
NRF_LOG_INFO("%s", buffer);
va_end(args);
}
Note that you may have to call NRF_LOG_FLUSH before the buffer goes out of scope or gets overwritten. See https://devzone.nordicsemi.com/f/nordic-q-a/22647/nrf_log_info-how-to-print-log-with-string-parameter

Programming with verbose option in C

Does someone know how to write a program in C with the verbose option (the option to choose if messages are printed or not) in a nice way.
I mean, not writing an if(verbose) for each printf in the code.
Is there a more elegant solution?
Just use a (variadic) macro / vararg function that tests a flag before calling something like vfprintf.
/* Crude example. */
void my_log(char *format, ...)
{
va_list args;
if (!ok_to_log)
return;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
EDIT As requested
How about a slightly modified gnu example:
#define eprintf(format, ...) do { \
if (ok_to_print) \
fprintf(stderr, format, ##__VA_ARGS__); \
} while(0)
Make an array of function pointers
print_function_type fx[2] = {quietprint, verboseprint};
and instead of using an if when printing, use the correct element of the array
// if verbosemode is 0 call quietprint
// if verbosemode is 1 call verboseprint
fx[verbosemode]("%d", foo);
You can write your own printf-like function that checks for the verbose flag and then calls printf, if necessary.

Good Verbosity Macro (C99)

I'm looking to write what I would imagine is a fairly common macro. I want to emulate the repeated "-v" options on many POSIX programs by defining a bunch of macros of the following form:
#define V1(str, ...) if(optv >= 1){printf("%s: "str,prog,__VA_ARGS__);}
int main(int argc, char* argv[])
{
// ... stuff ...
int i = 1;
V1("This contains a variable: %d\n",i);
}
// Output:
// ./program: This contains a variable: 1
where optv counts the number of "-v" options found on the command line and prog contains the program name (neither shown). This works well, but the problem is that I have to use a variable. V1("Output") will generate a compiler error. I could always use V1("Output%s","") but there should be a cleaner solution.
The GNU C preprocessor has a special feature that lets you delete the trailing comma when there are no arguments filling the variadic portion by prepending the token-pasting operator ## to __VA_ARGS__:
#define V1(str, ...) if(optv < 1); else printf("%s: "str,prog, ## __VA_ARGS__)
Alternatively, if you wish to remain fully C99 compliant, you could incorporate the the format string parameter into the ellipsis, but in this instance you'll also need to refactor your code since you want to include the extra prog parameter between the format string and the varargs. Something like this might work:
#define V1(...) if(optv < 1); else myprintf(prog, __VA_ARGS__)
int myprintf(const char *prog, const char *fmt, ...)
{
// Print out the program name, then forward the rest onto printf
printf("%s: ", prog);
va_list ap;
va_start(ap, fmt);
int ret = vprintf(fmt, ap);
va_end(ap);
return ret;
}
Then, V1("Output") expands to myprintf(prog, "Output") without using any non-C99 compiler extensions.
EDIT
Also note that I inverted the if condition in the macro, due to some weird issues that can arise if you invoke the macro inside an if statement without braces—see this FAQ for a detailed explanation.
Why don't you use 2 different macros for each verbosity level; one which prints a message and variable, and one which just prints a message?
You should probably write yourself a small support function so that you can do the job cleanly:
extern void vb_print(const char *format, ...);
#define V1(...) do { if (optv >= 1) vb_print(__VA_ARGS__); } while (0)
I assume that both optv and prog are global variables. These would go into a header (you wouldn't write them out in the programs themselves, would you?).
The function can be:
#include <stdio.h>
#include <stdarg.h>
extern const char *prog;
void vb_print(const char *format, ...)
{
va_list args;
va_start(args, format);
printf("%s:", prog);
vprintf(format, args);
va_end(args);
}
There's no rocket science in there. You can tweak the system to your heart's content, allowing a choice of where the information is written, flushing the output, ensuring there's a newline at the end, etc.
Try this:
#define V1X(str, ...) if(optv >= 1) {printf("%s: "str,prog,__VA_ARGS__);} else
#define V1(...) V1X(__VA_ARGS__,0)
I believe that fixes the problem you described, and the else at the end fixed another problem.

Why and how do we redirect debug statements?

I want to know why is it preferred to redirect the debug statements to stderr like it is done here:
#ifdef DEBUG_TEST
#define DEBUG_TEST 1
#else
#define DEBUG_TEST 0
#endif
#define DEBUG_PRINT(fmt, ...) \
do { if (DEBUG_TEST) fprintf(stderr, fmt, ##__VA_ARGS__); } while (0)
Also: How can we redirect these debug statements to a separate log file with a timestamp on that file? I want to do this using a macro in my code.
Platform: Linux, gcc compiler
Advantage of using stderr over stdout is that if you are redirecting the output to a file or streaming it (using a pipe) to another process, the debugging messages do not get in the way.
If you want to redirect stderr to a file on Unix, you can run your program like this:
./program 2>logfile
I can give you two examples of why you would do this: You could then easily redirect standard output to a file while keeping standard error in your terminal (and this seems to be exactly what you want to do in your second question). Your tool(s) might highlight messages sent to stderr making them easier to spot right away.
You could use the command line version to redirect stderr, as thesamet suggests. To get a timestamp in the filename, you could do something like this when you run your program:
./program 2>"logfile-`date`.txt"
If you want to do it in the program itself, one way is to simply use fopen to open another file and write to that. Here is a fully working example you can play with:
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#define DEBUG_TEST true
FILE *debug_file;
#define DEBUG_PRINT(fmt, ...) \
do { if (DEBUG_TEST) fprintf(debug_file, fmt, ##__VA_ARGS__); } while (false);
int main()
{
time_t timestamp = time(NULL);
char * s = malloc(snprintf(NULL, 0, "debug-%d.txt", timestamp));
sprintf(s, "debug-%d.txt", timestamp);
debug_file=fopen(s, "w");
DEBUG_PRINT("YEAH\n");
fclose(debug_file);
return EXIT_SUCCESS;
}
One of the reasons you report debug information to stderr rather than stdout because stdout might be sent down a pipeline and your diagnostics would go with the actual data, confusing the subsequent phases of the pipeline.
If you might want to redirect the output, or add timestamps (or PID, or any other information), then do not use fprintf() directly. Call a function of your own devising which deals with the information you want in the way you want.
Thus, your macro could be:
extern void dbg_print(const char *fmt, ...);
#define DEBUG_PRINT(fmt, ...) \
do { if (DEBUG_TEST) dbg_print(fmt, __VA_ARGS__); } while (0)
Or:
extern void dbg_print(const char *func, const char *file, int line, const char *fmt, ...);
#define DEBUG_PRINT(fmt, ...) \
do { if (DEBUG_TEST) dbg_print(__func__, __FILE__, __LINE__, fmt, __VA_ARGS__); } while (0)
This includes the function name, file name and line number in the information
For example, I have a moderately complex package that does that. One of the core internal routines is:
/* err_stdio - report error via stdio */
static void err_stdio(FILE *fp, int flags, int errnum, const char *format, va_list args)
{
if ((flags & ERR_NOARG0) == 0)
fprintf(fp, "%s: ", arg0);
if (flags & ERR_STAMP)
{
char timbuf[32];
fprintf(fp, "%s - ", err_time(timbuf, sizeof(timbuf)));
}
if (flags & ERR_PID)
fprintf(fp, "pid=%d: ", (int)getpid());
vfprintf(fp, format, args);
if (flags & ERR_ERRNO)
fprintf(fp, "error (%d) %s\n", errnum, strerror(errnum));
}
The debug wrappers can call onto that function with appropriate flags, and generate the desired output. Other parts of the system control the file stream used (stderr is the default, but there's a function to redirect the output to any other stream), and so on.
If you limit yourself by using fprintf() directly in the debug macro, you are stuck with what fprintf() can do, or recompiling everything.
See also my answer to 'C #define macro for debug printing' for more information about debugging macros and how to use them (though it looks as if you've taken much of what I say there on board already).
Forgive if I am wrong but it seems like no one mentioned buffering.
By default stdout is line buffered on most platforms and stderr is unbuffered. Basically this means that by default writes to stdout are written to memory and written to the file or console in chunks because doing output character by character is slooooow.
If you are debugging you don't want the message to appear much later then you actually mean to print it (or even potentially never print in if your program crashes or is stuck in an infinite loop(this can really mess you up when you think its looping or crashing in the wrong place) and you usually don't mind the speed hit. It could theoretically make a difference due to timing and synchronisation bugs but those it can be hard to catch/debug those in any case.
TL;DR when debugging print to stderr not stdout (other people might suggest logging to a file instead and or allowing runtime options like enabling/disabling printing file,style,threshold,ect).

Pass format string through procedure to fprintf

I'm working on a program that generates an FDF file for filling in an Adobe PDF form. Currently, I have various procedures that are called, as before each one terminates, it opens the FDF file, writes its particular data, and closes the file.
I'm trying to put the code for writing the data to the FDF file in a separate procedure, and then have the other procedures call it. This would allow for a greater separation of the code by task, and if I had to change it in the future, I could do so easily.
I'm having some problems though, as I need to pass varying amounts of variables to fprintf. That is, I used to have a line like this:
fprintf(fp,"<</T(f1_44(0))/V(%d)>>\n",wages);
I wrote the below function, but I can't get it to work:
void writeToFDF(FILE *fp, char *filename, char *data, char *arg)
{
/* independent method for writing to FDF file */
/* open file */
fp=fopen(filename,"a");
fprintf(fp,data,arg);
/* close file */
fclose(fp);
}
So in theory, I would then in the parent function call:
writeToFDF(fp,"1040.fdf","<</T(f1_44(0))/V(%d)>>\n",wages);
I'm getting errors right now, and I believe it has to do with the last part of the function's arguments. Also, how can I get it to work if I have multiple arguments?
Thank you.
You need vfprintf. It will accept a variable list of arguments.
Like this:
void writeToFDF(FILE *fp, char *filename, char *data, ...)
{
va_list pl;
/* independent method for writing to FDF file */
/* open file */
fp=fopen(filename,"a");
va_start (pl, data);
vfprintf(fp,data,pl);
/* close file */
fclose(fp);
va_end(pl);
}
EDIT: while I tried to stay as close to your original code, ephemient's solution that omits the FILE *fp argument is in fact better: fp has only local significance (it's opened and closed in this function) so it should not be passed around.
This is what vfprintf is for.
#include <stdarg.h>
#include <stdio.h>
void writeToFDF(const char *filename, const char *format, ...) {
va_list ap;
FILE *fp = fopen(filename, "a");
va_begin(ap, format);
vfprintf(fp, format, ap);
va_end(ap);
fclose(fp);
}
You will need to use a Variadic function. See Forward an invocation of a variadic function in C
#include <stdio.h>
#include <stdarg.h>
void foo(FILE *file, char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(file, fmt, ap);
va_end(ap);
}

Resources