C API: Parse value(s) from string

The SDK provides playdate->system->formatString() for processing values into text:

int playdate->system->formatString(
  char **ret,
  const char *format,
  ...
)

Documentation request: Inside Playdate with C does not describe the significance of the format argument or the return type. I assume these match what sprintf() does (the return value is either the length of the resulting string not including the null terminator, or negative on error), but this really should be detailed in Inside Playdate with C.

Unlike sprintf(), formatString() allocates a new string buffer and provides a pointer to it. This buffer needs to be deleted by the program via playdate->system->realloc().

SDK request: I'd like to propose a companion function:

int playdate->system->parseString(
  const char *src,
  const char *format,
  ...
)

Unsurprisngly, this would work like sscanf(), where the variadic arguments are all pointers to receive the parsed contents. Unlike sscanf(), I would have the return value work as follows: the number of parsed values if successful, or negative on error.

Intuitively, converting text to other types shouldn't be necessary since, well, why are you representing your assets as text? But some things to consider:

  • If the program accepts text input from the user via the on-screen keyboard, there may be situations where the data is literally unavailable in any other format.
  • Some widespread and/or standard asset formats do use text, such as XML or 3D models/OBJ, as this user points out.
  • Lua has built-in support for this via tonumber(), so this would help provide parity for the C environment.
  • Users won't have to dance around that nosys.specs thing that keeps cropping up for this specific use case (example, example).
2 Likes

Here's my edit for formatString(). Does this make sense?

Creates a formatted string and returns it via the outstring argument. The arguments and return value match libc's asprintf(): the format string is standard printf() style, the string returned in outstring should be freed by the caller when it's no longer in use, and the return value is the length of the formatted string.

And yes, a scanf() function would be really useful! I'll add that now, though no promises on when it'll make it into an SDK release.

Thanks for the feedback, and sorry for the slow response!

oh, one question: Can you clarify why you'd change the scanf() return value?

Unlike sscanf() , I would have the return value work as follows: the number of parsed values if successful, or negative on error.

If you had four items to match and it matched the first three then failed on the last, would it return -1 instead of 3? That seems less useful to me, not being able to see where the failure occurred.. :thinking:

I like it. Since the function is stated to work analogously to asprintf(), which many people will already be familiar with, it's a simple matter of referencing documentation on that instead of bloating the Playdate documentation with all the various things it can do. Wouldn't hurt to have the HTML actually link to asprintf() and printf() for convenience.


scanf() has some nuances that don't really fit into the way I interpret the Playdate setup:

Upon successful completion, these functions return the number of successfully matched and assigned input items; this number can be 0 in the event of an early matching failure. If the input ends before the first matching failure or conversion, EOF is returned. If a read error occurs the error indicator for the stream is set, EOF is returned, and errno is set to indicate the error.

I may be mistaken, but I've been operating under the impression that EOF (from stdio.h) and errno (from errno.h) are not conventionally part of Playdate development. Rather, Playdate itself provides an API for utility functions like this, and any error conditions that might arise are within that scope instead of a broader C library context.

Essentially, errno provides a sort of second return value, which isn't a mechanic C normally supports. The Playdate function wouldn't necessarily need to return -1, however: it could have a magnitude of one greater than the number of successfully parsed values.

int result = playdate->system->parseString( ... );
int successful_values = result < 0 ? -result - 1 : result;

Normally, I'd say add an optional output argument (as a pointer) for situations like this, but since this specific function accepts a variadic argument list, doing it that way may not be a great idea...

EDIT: I suppose it's worth noting that since the number of expected parsed values is known as given by the actual argument list, it should be acceptable for the function to always return a nonnegative result that simply describes how many values succeeded. That is, if you're expecting 3 values, you can check for errors by testing if the result is less than 3.

You're right, I should have clarified that I'll add an sscanf() function, not scanf(), since we don't have stdin. I don't think I've used scanf() since my intro programming class a (very) long time ago. :smiley: