mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 22:31:05 +00:00
[gamecode] Add optional support for %@ strings
If no handler has been registered, then the corresponding parameter is printed as a pointer but with surrounding brackets (eg, [0xfc48]). This will allow the ruamoko runtime to implement object printing.
This commit is contained in:
parent
1f9553d13e
commit
6db44afedc
2 changed files with 60 additions and 0 deletions
|
@ -1628,6 +1628,32 @@ void PR_FreeString (progs_t *pr, pr_string_t str);
|
|||
*/
|
||||
void PR_FreeTempStrings (progs_t *pr);
|
||||
|
||||
/** Callback for handling %@ in PR_Sprintf format strings.
|
||||
|
||||
\param pr pointer to ::progs_t VM struct
|
||||
\param at_param Parameter to be converted to a string. Usually a progs
|
||||
pointer value. It is the callee's responsibility to
|
||||
interpret the value as a pointer.
|
||||
\param data User data pointer as passed to PR_Sprintf_SetAtHandler
|
||||
\return String to be printed in place of %@
|
||||
*/
|
||||
typedef const char *(*prstr_at_handler_t) (progs_t *pr, pr_ptr_t at_param,
|
||||
void *data);
|
||||
|
||||
/** Set the at_handler callback and its user data pointer.
|
||||
|
||||
The at_handler callback defaults to null resulting in [ptr] in the output
|
||||
string. Setting the callback allows the at_handler to interpret the value
|
||||
(nominally pr_ptr_t, but always a 32-bit value) as it chooses.
|
||||
|
||||
\param pr pointer to ::progs_t VM struct
|
||||
\param at_handler Function pointer for callback to interpret the parameter
|
||||
corresponding to the %@ format specifier.
|
||||
\param data User data pointer, passed to \a at_handler.
|
||||
*/
|
||||
void PR_Sprintf_SetAtHandler (progs_t *pr, prstr_at_handler_t at_handler,
|
||||
void *data);
|
||||
|
||||
/** Formatted printing similar to C's vsprintf, but using QC types.
|
||||
The format string is a string of characters (other than \c \%) to be
|
||||
printed that includes optional format specifiers, one for each arg to be
|
||||
|
|
|
@ -90,6 +90,8 @@ typedef struct prstr_resources_s {
|
|||
int num_strings;
|
||||
fmt_item_t *free_fmt_items;
|
||||
dstring_t *print_str;
|
||||
prstr_at_handler_t at_handler;
|
||||
void *at_handler_data;
|
||||
} prstr_resources_t;
|
||||
|
||||
typedef enum {
|
||||
|
@ -866,6 +868,8 @@ typedef struct fmt_state_s {
|
|||
fmt_item_t *fmt_items;
|
||||
fmt_item_t **fi;
|
||||
int fmt_count;
|
||||
prstr_at_handler_t at_handler;
|
||||
void *at_handler_data;
|
||||
} fmt_state_t;
|
||||
|
||||
static inline void
|
||||
|
@ -1052,6 +1056,25 @@ fmt_state_conversion (fmt_state_t *state)
|
|||
switch ((conv = *state->c++)) {
|
||||
case '@':
|
||||
// object
|
||||
pr_ptr_t at_param = P_UINT (pr, state->fmt_count);
|
||||
if (state->at_handler) {
|
||||
const char *at_str = state->at_handler (pr, at_param,
|
||||
state->at_handler_data);
|
||||
(*state->fi)->type = 's';
|
||||
(*state->fi)->data.string_var = at_str;
|
||||
} else {
|
||||
(*state->fi)->type = 's';
|
||||
(*state->fi)->data.string_var = "[";
|
||||
fmt_append_item (state);
|
||||
|
||||
(*state->fi)->flags |= FMT_ALTFORM;
|
||||
(*state->fi)->type = 'x';
|
||||
(*state->fi)->data.uint_var = at_param;
|
||||
fmt_append_item (state);
|
||||
|
||||
(*state->fi)->type = 's';
|
||||
(*state->fi)->data.string_var = "]";
|
||||
}
|
||||
state->fmt_count++;
|
||||
fmt_append_item (state);
|
||||
break;
|
||||
|
@ -1200,6 +1223,15 @@ fmt_state_format (fmt_state_t *state)
|
|||
}
|
||||
///@}
|
||||
|
||||
VISIBLE void
|
||||
PR_Sprintf_SetAtHandler (progs_t *pr, prstr_at_handler_t at_handler,
|
||||
void *data)
|
||||
{
|
||||
prstr_resources_t *res = pr->pr_string_resources;
|
||||
res->at_handler = at_handler;
|
||||
res->at_handler_data = data;
|
||||
}
|
||||
|
||||
VISIBLE void
|
||||
PR_Sprintf (progs_t *pr, dstring_t *result, const char *name,
|
||||
const char *format, int count, pr_type_t **args)
|
||||
|
@ -1214,6 +1246,8 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name,
|
|||
*state.fi = new_fmt_item (res);
|
||||
state.c = format;
|
||||
state.state = fmt_state_format;
|
||||
state.at_handler = res->at_handler;
|
||||
state.at_handler_data = res->at_handler_data;
|
||||
|
||||
if (!name)
|
||||
name = "PR_Sprintf";
|
||||
|
|
Loading…
Reference in a new issue