The printf family of functions includes (among others) printf(3), fprintf(3), vprintf(3), and vfprintf(3). The first three can easily be written in terms of the fourth.
Write four similar functions
void msg(char const *type, char const *fmt, ...);
void vmsg(char const *type, char const *fmt, va_list ap);
void fmsg(FILE *fp, char const *type, char const *fmt, ...);
void vfmsg(FILE *fp, char const *type, char const *fmt, va_list ap);
where the intended behavior is
msg("Info", "0x%x %d", 32, 5);
prints [Info] 0x20 5.
Implement the first three in terms of the fourth. Feel free to use fprintf(3), vfprintf(3), or other standard I/O functions to implement vfmsg.
Write a short program that tests them.
The execl(3) function takes a path and a variable number of arguments. The end of the argument list is denoted by an explicit (char *)0.
Using the same strategy of marking the end of the list with (char *)0, write a function
char *join(char const *sep, ...)
That allocates and returns a string consisting of the variable number of strings joined together but separated the string sep. For example,
join(" ", "This", "is", "a", "sentence.", (char *)0);`
should return the string "This is a sentence.";
should return the empty string ""; and
join("+-+" "a", "b", "c", (char *)0);
should return the string "a+-+b+-+c".
In all cases, the string should be allocated via malloc(3) or realloc(3). Make sure you don’t leak memory.
Write a short program to test your functions. The strings returned from join should ultimately be passed to free(3).