/*
 * == VFormat ==
 *
 * VVVVVV's format strings. See the function declarations below (vformat_*).
 *  - vformat_cb       Calls a user-supplied callback function for each part of
 *                      the resulting string.
 *  - vformat_buf      Fills a user-supplied buffer with the result.
 *  - vformat_alloc    Allocates a buffer with the result (caller must VVV_free).
 *
 * All include the following parameters:
 *  - format_string     The string which needs placeholders to be filled in
 *  - args_index        A string describing the varargs
 *  - ...               The varargs (like printf-family functions)
 *
 * Variants ending in _valist are equivalent, but take a va_list instead of a variable
 * number of arguments. These use va_copy (they have to) and thus leave the given
 * va_list untouched.
 *
 * The FORMAT STRING can include placeholders, which look like {name} or {name|flags}.
 * The name can be user-defined, as long as it appears in the ARGS INDEX.
 * Flags are separated by |, invalid flags are ignored.
 *
 * The valid flags are:
 *  - wordy         [ints only] use number words (Twenty) instead of digits (20)
 *  - digits=n      [ints only] force minimum n digits, like n=5 --> 00031
 *  - spaces        [only if using digits=n] use leading spaces instead of 0s
 *  - upper         uppercase the first character with loc::toupper_ch
 *
 * For example, {aa|digits=3|spaces} fills in the argument with the name "aa".
 * Space is reserved for 3 digits, and unused columns are padded with spaces.
 * This is equivalent to %3d in printf-family functions.
 *
 * Literal { and } characters can be included in the text by doubling them,
 * like {{ and }}. Including curly braces of any kind inside placeholder tags,
 * (as part of the name or flags), is unsupported. Included string arguments
 * aren't subject to further parsing, so including curly braces in string
 * arguments poses no problems.
 *
 * The ARGS INDEX defines the names and types of the arguments you pass.
 * In the args index string, arguments are separated by commas, and each argument is
 * in the format name:type. Whitespace around the : and , separators is ignored.
 *
 * The valid types are:
 *  - int   Signed integer
 *  - str   const char*
 *  - but   Controller button icon: vformat_button(actionset, action)
 *
 * Special case: if an argument name is a single underscore (_), it matches
 * any name not found earlier in the list. This should normally not be needed.
 *
 * Full example:
 *
 *  char buffer[100];
 *  vformat_buf(buffer, sizeof(buffer),
 *      "{crewmate} got {number} out of {total} trinkets in {m}:{s|digits=2}.{ms|digits=3}",
 *      "number:int, total:int, crewmate:str, m:int, s:int, ms:int",
 *      2, 20, "Vermilion", 2, 3, 1
 *  );
 *
 * => "Vermilion got 2 out of 20 trinkets in 2:03.001"
 *
 * ERROR CONDITIONS: These functions should not cause any crashes or UB unless you
 * mislead them on the programming side of things. For example, if your args index doesn't
 * align with the varargs you actually pass, or you pass the wrong buffer size into
 * vformat_buf. That means it should be safe to use user-generated content as a format
 * string. If the format string refers to an argument name that is not found in the index,
 * that placeholder will be filled in as [name?] (where `name` is filled in with the name).
 * If you pass a NULL string argument, it will be rendered as [null].
 */


#ifndef VFORMAT_H
#define VFORMAT_H

#include <stdarg.h>
#include <stddef.h>

#include "ActionSets.h"

#ifdef __cplusplus
extern "C"
{
#endif

typedef void (*format_callback)(void* userdata, const char* string, size_t bytes);


int vformat_button(ActionSet actionset, int action);


void vformat_cb_valist(
    format_callback callback,
    void* userdata,
    const char* format_string,
    const char* args_index,
    va_list args
);

void vformat_cb(
    format_callback callback,
    void* userdata,
    const char* format_string,
    const char* args_index,
    ...
);

size_t vformat_buf_valist(
    char* buffer,
    size_t buffer_len,
    const char* format_string,
    const char* args_index,
    va_list args
);

size_t vformat_buf(
    char* buffer,
    size_t buffer_len,
    const char* format_string,
    const char* args_index,
    ...
);

char* vformat_alloc_valist(
    const char* format_string,
    const char* args_index,
    va_list args
);

char* vformat_alloc(
    const char* format_string,
    const char* args_index,
    ...
);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* VFORMAT_H */
