I wrote a function that is supposed to take a format string similar to what date
accepts and replace all format specifiers with strings provided by a callback function.
- Format specifiers are sequences of a
%
plus another character;%%
for a literal%
- Replace the format specifier with the string provided by the callback function
- If the callback function returns
NULL
, no replacement should take place (leave the specifier in) - The callback function receives the character following
%
as argument - An optional pointer can be passed through to the callback function
- If the last character of the format string is
%
, it should be left as-is - The result of the processing is to be placed in the provided buffer
- If the provided buffer isn't big enough, simply stop processing
- Always null-terminate the provided buffer, even if it isn't big enough
The function works fine as far as I can tell. I'm looking for any feedback I can get.
char*
format(const char* format, char *buf, size_t len, char* (*cb)(char c, void* ctx), void *ctx)
{
const char *curr; // current char from format
const char *next; // next char from format
size_t i = 0; // index into buf
char *ins = NULL; // string to insert
// iterate `format`, abort once we exhaust the output buffer
for (; *format && i < (len-1); ++format)
{
curr = format;
next = format+1;
if (*curr == '%' && *next)
{
if (*next == '%') // escaped %, copy it over and skip
{
buf[i++] = *format++;
continue;
}
if ((ins = cb(*next, ctx))) // get string to insert
{
// copy string, again aborting once buffer full
while (*ins && i < (len-1))
{
buf[i++] = *ins++;
}
++format;
continue;
}
}
// any other character, just copy over
buf[i++] = *curr;
}
// null terminate
buf[i] = '\0';
return buf;
}
Examples for (tested) input and output, assuming the callback function always returns FOO
:
- (empty string): (empty string)
%
:%
%%
:%
%f
:FOO
%%f
:%f
%%%f
:%FOO
%%%%f
:%%f
If so requested, I can provide a link to the context/project where this is used.