I have an coding assignment that must be done in C. I got sidetracked and decided to try to make a format macro i can use for styling text with ansi codes. My code is as follows:
<format.h>
#include <stdarg.h>
#include <string.h>
/**
* global buffer to store format arguments for prints
*/
char format_buffer[128];
/**
* Count the number of char* in variadic arguments, auxiliary for FMT macro
*/
#define FARGS(...) (sizeof((char*[]){__VA_ARGS__})/sizeof(char*))
/**
* Automatically fills in parameters buffer and argc for the format function. Buffer is a global variable, therefore it is never out of scope.
*/
#define FMT(...) format(format_buffer, FARGS(__VA_ARGS__), __VA_ARGS__)
#define A_START "\x1B["
#define A_END "m"
/**
* creates a format string based on input parameters.
* @param argc the number of ansi flags to use
* @param buffer the buffer to write the format string into. A size of 64 should be enough for most reasonable uses
* @param ... the ansi flags to use. Examples include RED, BLUE, DASH, etc
* @return the same pointer buffer, for ease of use in printf functions
*/
char* format(char* buffer, int argc, ...);
// ansi macros for formatting, all of the style ";NN"
<format.c>
#include "format.h"
char format_buffer[128] = {};
char* format(char* buffer, int argc, ...){
buffer[0] = '\0';
va_list argv;
int i;
// initialize argv to get data from the variable arguments
va_start(argv, argc);
strcat(buffer, A_START);
/* access all the arguments assigned to valist */
for (i = 0; i < argc; i++) {
strcat(buffer, va_arg(argv, char*));
}
strcat(buffer, A_END);
/* clean memory reserved for valist */
va_end(argv);
return buffer;
}
Using that, I can call the macro as follows, which is what I want:
printf("%sHello!\n", FMT(RED, BOLD)) //prints <Hello!\n> in red and bold
The problem
The problem I have is when I try to use multiple calls in the same print statement:
printf("%sHello, %sWorld!\n", FMT(RED, BOLD), FMT(YELLOW)) //prints <Hello, World!\n> in yellow
I’m positive it’s not working as expected because FMT(...) always returns the same global char*, but I don’t know how could i change it so that:
- I can call the format macro as shown above:
printf("%sHello!\n", FMT(RED, BOLD)). - I can use multiple FMT calls in the same print statement, as in
printf("%sHello, %sWorld!\n", FMT(RED, BOLD), FMT(YELLOW))should print <Hello, > in red and bold and <World!\n> in yellow.
As a final note, I’d rather code the solution instead of using a library or header that already has an implementation of this.
I first tried creating a new char[] inside the format function, but it would be stored in the stack so I assume that’s a much worse outcome.
>Solution :
Simply change the macro to:
#define FMT(...) format((char[128]){}, FARGS(__VA_ARGS__), __VA_ARGS__)
https://godbolt.org/z/KvWWcYfPb