mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-17 01:11:45 +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);
|
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.
|
/** Formatted printing similar to C's vsprintf, but using QC types.
|
||||||
The format string is a string of characters (other than \c \%) to be
|
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
|
printed that includes optional format specifiers, one for each arg to be
|
||||||
|
|
|
@ -90,6 +90,8 @@ typedef struct prstr_resources_s {
|
||||||
int num_strings;
|
int num_strings;
|
||||||
fmt_item_t *free_fmt_items;
|
fmt_item_t *free_fmt_items;
|
||||||
dstring_t *print_str;
|
dstring_t *print_str;
|
||||||
|
prstr_at_handler_t at_handler;
|
||||||
|
void *at_handler_data;
|
||||||
} prstr_resources_t;
|
} prstr_resources_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -866,6 +868,8 @@ typedef struct fmt_state_s {
|
||||||
fmt_item_t *fmt_items;
|
fmt_item_t *fmt_items;
|
||||||
fmt_item_t **fi;
|
fmt_item_t **fi;
|
||||||
int fmt_count;
|
int fmt_count;
|
||||||
|
prstr_at_handler_t at_handler;
|
||||||
|
void *at_handler_data;
|
||||||
} fmt_state_t;
|
} fmt_state_t;
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -1052,6 +1056,25 @@ fmt_state_conversion (fmt_state_t *state)
|
||||||
switch ((conv = *state->c++)) {
|
switch ((conv = *state->c++)) {
|
||||||
case '@':
|
case '@':
|
||||||
// object
|
// 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++;
|
state->fmt_count++;
|
||||||
fmt_append_item (state);
|
fmt_append_item (state);
|
||||||
break;
|
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
|
VISIBLE void
|
||||||
PR_Sprintf (progs_t *pr, dstring_t *result, const char *name,
|
PR_Sprintf (progs_t *pr, dstring_t *result, const char *name,
|
||||||
const char *format, int count, pr_type_t **args)
|
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.fi = new_fmt_item (res);
|
||||||
state.c = format;
|
state.c = format;
|
||||||
state.state = fmt_state_format;
|
state.state = fmt_state_format;
|
||||||
|
state.at_handler = res->at_handler;
|
||||||
|
state.at_handler_data = res->at_handler_data;
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
name = "PR_Sprintf";
|
name = "PR_Sprintf";
|
||||||
|
|
Loading…
Reference in a new issue