Skip to main content
added 91 characters in body
Source Link
domsson
  • 238
  • 1
  • 7

If so requested, I can provide a link to the context/project where this is used.

If so requested, I can provide a link to the context/project where this is used.

Source Link
domsson
  • 238
  • 1
  • 7

Format string processing similar to date or printf()

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