From dfe7f263c764e3e474646cb979bc4e27c537ecb6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 4 Jan 2004 07:42:43 +0000 Subject: [PATCH] new internal printf engine for progs, mostly thanks to Deek. also a few cleanup bits --- include/QF/progs.h | 8 +- libs/gamecode/builtins/pr_cmds.c | 426 +++++++---------------------- libs/gamecode/engine/pr_builtins.c | 4 +- libs/gamecode/engine/pr_strings.c | 372 ++++++++++++++++++++++++- libs/util/dstring.c | 2 +- qw/source/sv_init.c | 3 +- tools/qwaq/builtins.c | 40 +-- tools/qwaq/main.qc | 1 + 8 files changed, 495 insertions(+), 361 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index a02dcd150..1aef70a18 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -127,6 +127,7 @@ qboolean PR_EdictValid (progs_t *pr, int e); #define G_EDICT(p,o) ((edict_t *)(PR_edicts (p) + G_INT (p, o))) #define G_EDICTNUM(p,o) NUM_FOR_EDICT(p, G_EDICT (p, o)) #define G_GSTRING(p,o) PR_GetString (p, G_STRING (p, o)) +#define G_DSTRING(p,o) PR_GetDString (p, G_STRING (p, o)) #define G_GPOINTER(p,o) PR_GetPointer (p, o) #define G_STRUCT(p,t,o) (*(t *)G_GPOINTER (p, o)) @@ -143,6 +144,7 @@ qboolean PR_EdictValid (progs_t *pr, int e); #define P_EDICT(p,n) ((edict_t *)(PR_edicts (p) + P_INT (p, n))) #define P_EDICTNUM(p,n) NUM_FOR_EDICT (p, P_EDICT (p, n)) #define P_GSTRING(p,n) PR_GetString (p, P_STRING (p, n)) +#define P_DSTRING(p,n) PR_GetDString (p, P_STRING (p, n)) #define P_GPOINTER(p,n) PR_GetPointer (p, P_POINTER (p, n)) #define P_STRUCT(p,t,n) (*(t *)P_GPOINTER (p, n)) @@ -172,12 +174,13 @@ qboolean PR_EdictValid (progs_t *pr, int e); #define E_POINTER(p,o) E_var (p, o, pointer) #define E_GSTRING(p,e,o) (PR_GetString (p, E_STRING (e, o))) +#define E_DSTRING(p,e,o) (PR_GetDString (p, E_STRING (e, o))) typedef void (*builtin_proc) (progs_t *pr); typedef struct { const char *name; builtin_proc proc; - int first_statement; + int binum; } builtin_t; ddef_t *PR_FindGlobal (progs_t *pr, const char *name); @@ -224,9 +227,12 @@ const char *PR_GetString(progs_t *pr, int num); struct dstring_s *PR_GetDString(progs_t *pr, int num); int PR_SetString(progs_t *pr, const char *s); int PR_SetTempString(progs_t *pr, const char *s); +void PR_MakeTempString(progs_t *pr, int str); int PR_NewString (progs_t *pr); void PR_FreeString (progs_t *pr, int str); void PR_FreeTempStrings (progs_t *pr); +void PR_Sprintf (progs_t *pr, struct dstring_s *result, const char *name, + const char *format, int count, pr_type_t **args); // // PR Resources stuff diff --git a/libs/gamecode/builtins/pr_cmds.c b/libs/gamecode/builtins/pr_cmds.c index 9ec525a2a..38513d1ea 100644 --- a/libs/gamecode/builtins/pr_cmds.c +++ b/libs/gamecode/builtins/pr_cmds.c @@ -43,13 +43,11 @@ static __attribute__ ((unused)) const char rcsid[] = #include -#include "QF/clip_hull.h" -#include "QF/cmd.h" #include "QF/cvar.h" +#include "QF/dstring.h" #include "QF/mathlib.h" #include "QF/progs.h" #include "QF/sys.h" -#include "QF/va.h" #include "QF/zone.h" #include "compat.h" @@ -58,9 +56,6 @@ const char *pr_gametype = ""; /* BUILT-IN FUNCTIONS */ -// FIXME: Hunk_TempAlloc, Sys_Printf, Cvar_*, PR_SetString, PR_RunError, ED_PrintEdicts, PF_traceon, PF_traceoff, ED_PrintNum, PR_FindBuiltin isn't threadsafe/reentrant - - char * PF_VarString (progs_t *pr, int first) { @@ -77,9 +72,7 @@ PF_VarString (progs_t *pr, int first) } /* - PF_normalize - - vector normalize(vector) + vector (vector v) normalize */ static void PF_normalize (progs_t *pr) @@ -107,9 +100,7 @@ PF_normalize (progs_t *pr) } /* - PF_vlen - - scalar vlen(vector) + float (vector v) vlen */ static void PF_vlen (progs_t *pr) @@ -127,9 +118,7 @@ PF_vlen (progs_t *pr) } /* - PF_vectoyaw - - float vectoyaw(vector) + float (vector v) vectoyaw */ static void PF_vectoyaw (progs_t *pr) @@ -151,9 +140,7 @@ PF_vectoyaw (progs_t *pr) } /* - PF_vectoangles - - vector vectoangles(vector) + vector (vector v) vectoangles */ static void PF_vectoangles (progs_t *pr) @@ -186,11 +173,9 @@ PF_vectoangles (progs_t *pr) } /* - PF_Random + float () random Returns a number from 0<= num < 1 - - random() */ static void PF_random (progs_t *pr) @@ -203,23 +188,17 @@ PF_random (progs_t *pr) } /* - PF_break - - break() + void () break */ static void PF_break (progs_t *pr) { Sys_Printf ("break statement\n"); - //*(int *) -4 = 0; // dump to debugger PR_DumpState (pr); -// PR_RunError (pr, "break statement"); } /* - PF_cvar - - float cvar (string) + float (string s) cvar */ static void PF_cvar (progs_t *pr) @@ -232,9 +211,7 @@ PF_cvar (progs_t *pr) } /* - PF_cvar_set - - float cvar (string) + void (string var, string val) cvar_set */ static void PF_cvar_set (progs_t *pr) @@ -255,6 +232,9 @@ PF_cvar_set (progs_t *pr) Cvar_Set (var, val); } +/* + float (float f) fabs +*/ static void PF_fabs (progs_t *pr) { @@ -264,12 +244,14 @@ PF_fabs (progs_t *pr) R_FLOAT (pr) = fabs (v); } -// entity (entity start, .string field, string match) find = #5; +/* + entity (entity start, .(...) fld, ... match) find +*/ static void PF_Find (progs_t *pr) { - const char *s = 0, *t; // ev_string - int i; // ev_vector + const char *s = 0, *t; // ev_string + int i; // ev_vector int e, f; etype_t type; ddef_t *field_def; @@ -326,36 +308,54 @@ PF_Find (progs_t *pr) RETURN_EDICT (pr, *pr->edicts); } +/* + void () coredump +*/ static void PF_coredump (progs_t *pr) { ED_PrintEdicts (pr, ""); } +/* + void () traceon +*/ static void PF_traceon (progs_t *pr) { pr->pr_trace = true; } +/* + void () traceoff +*/ static void PF_traceoff (progs_t *pr) { pr->pr_trace = false; } +/* + void (entity e) eprint +*/ static void PF_eprint (progs_t *pr) { ED_PrintNum (pr, P_EDICTNUM (pr, 0)); } +/* + void (string s) dprint +*/ static void PF_dprint (progs_t *pr) { Sys_Printf ("%s", PF_VarString (pr, 0)); } +/* + float (float v) rint +*/ static void PF_rint (progs_t *pr) { @@ -368,12 +368,18 @@ PF_rint (progs_t *pr) R_FLOAT (pr) = (int) (f - 0.5); } +/* + float (float v) floor +*/ static void PF_floor (progs_t *pr) { R_FLOAT (pr) = floor (P_FLOAT (pr, 0)); } +/* + float (float v) ceil +*/ static void PF_ceil (progs_t *pr) { @@ -381,9 +387,7 @@ PF_ceil (progs_t *pr) } /* - PF_nextent - - entity nextent(entity) + entity (entity e) nextent */ static void PF_nextent (progs_t *pr) @@ -414,8 +418,6 @@ PF_nextent (progs_t *pr) #endif /* - PF_ftoi - integer (float f) ftoi */ static void @@ -425,8 +427,6 @@ PF_ftoi (progs_t *pr) } /* - PF_ftos - string (float f) ftos */ static void @@ -451,8 +451,6 @@ PF_ftos (progs_t *pr) } /* - PF_itof - float (integer i) itof */ static void @@ -462,8 +460,6 @@ PF_itof (progs_t *pr) } /* - PF_itos - string (integer i) itos */ static void @@ -477,8 +473,6 @@ PF_itos (progs_t *pr) } /* - PF_stof - float (string s) stof */ static void @@ -488,8 +482,6 @@ PF_stof (progs_t *pr) } /* - PF_stoi - integer (string s) stoi */ static void @@ -499,8 +491,6 @@ PF_stoi (progs_t *pr) } /* - PF_stov - vector (string s) stov */ static void @@ -514,8 +504,6 @@ PF_stov (progs_t *pr) } /* - PF_vtos - string (vector v) vtos */ static void @@ -532,9 +520,7 @@ PF_vtos (progs_t *pr) } /* - PF_strlen - - float(string s) strlen + float (string s) strlen */ static void PF_strlen (progs_t *pr) @@ -546,9 +532,7 @@ PF_strlen (progs_t *pr) } /* - PF_charcount - - float(string char, string s) charcount + float (string char, string s) charcount */ static void PF_charcount (progs_t *pr) @@ -580,282 +564,78 @@ PF_charcount (progs_t *pr) #endif #define MAX_ARG 7 - +/* + string (...) sprintf +*/ static void PF_sprintf (progs_t *pr) { - const char *format; - const char *c; // current - char *out = 0; - char new_format[INT_WIDTH * 2 + 9]; // "%0-+ #." and conversion - int fmt_alternate, fmt_leadzero, fmt_leftjust, fmt_minwidth; - int fmt_precision, fmt_signed, fmt_space, fmt_type, looping; - int ret; - size_t new_format_i; - int curarg = 1, out_max = 32, out_size = 0; + const char *fmt = P_GSTRING (pr, 0); + int count = pr->pr_argc - 1; + pr_type_t **args = pr->pr_params + 1; + dstring_t *dstr; + int str; - format = P_GSTRING (pr, 0); - c = format; - - out = malloc (out_max); - if (!out) - goto mallocerror; - - while (*c) { - if (*c == '%' && c[1] != '%' && c[1] != 's') { - c++; - if (curarg > MAX_ARG) - goto maxargs; - - // flags - looping = 1; - fmt_leadzero = 0; - fmt_leftjust = 0; - fmt_signed = 0; - fmt_space = 0; - fmt_alternate = 0; - while (looping) { - switch (*c) { - case '0': fmt_leadzero = 1; break; - case '-': fmt_leftjust = 1; break; - case '+': fmt_signed = 1; break; - case ' ': fmt_space = 1; break; - case '#': fmt_alternate = 1; break; - case '\0': goto endofstring; - default: looping = 0; continue; - } - c++; - } - - // minimum field width - fmt_minwidth = 0; - if (*c >= '1' && *c <= '9') - while (*c >= '0' && *c <= '9') { - fmt_minwidth *= 10; - fmt_minwidth += *c - '0'; - c++; - } - else if (*c == '*') { - fmt_minwidth = P_INT (pr, 0 + curarg); - curarg++; - } - - // precision - fmt_precision = -1; - if (*c == '.') { - c++; - if (*c >= '0' && *c <= '9') { - fmt_precision = 0; - while (*c >= '0' && *c <= '9') { - fmt_precision *= 10; - fmt_precision += *c - '0'; - c++; - } - } else if (*c == '*') { - fmt_precision = P_INT (pr, 0 + curarg); - curarg++; - } - } - if (!*c) - goto endofstring; - // length? Nope, not in QC - fmt_type = *c++; - - // some preperation - if (fmt_precision < 0) - switch (fmt_type) { - case 'i': fmt_precision = 0; break; - case 'f': fmt_precision = 6; break; - case 'v': fmt_precision = 1; break; - } - - // built the format string - new_format_i = 0; - new_format[new_format_i++] = '%'; - if (fmt_leadzero) new_format[new_format_i++] = '0'; - if (fmt_leftjust) new_format[new_format_i++] = '-'; - if (fmt_signed) new_format[new_format_i++] = '+'; - if (fmt_space) new_format[new_format_i++] = ' '; - if (fmt_alternate) new_format[new_format_i++] = '#'; - if (fmt_minwidth) - if ((new_format_i += snprintf (new_format + new_format_i, - sizeof (new_format) - - new_format_i, - "%d", fmt_minwidth)) - >= sizeof (new_format)) - PR_Error (pr, "PF_sprintf: new_format overflowed?!"); - if (fmt_type != 'i') { - new_format[new_format_i++] = '.'; - if ((new_format_i += snprintf (new_format + new_format_i, - sizeof (new_format) - - new_format_i, - "%d", fmt_precision)) - >= sizeof (new_format)) - PR_Error (pr, "PF_sprintf: new_format overflowed?!"); - } - switch (fmt_type) { - case 'i': new_format[new_format_i++] = 'd'; break; - case 'f': - case 'v': new_format[new_format_i++] = 'f'; break; - default: PR_Error (pr, "PF_sprintf: unknown type '%c'!", *c); - } - new_format[new_format_i++] = '\0'; - - switch (fmt_type) { - case 'i': - while ((ret = snprintf (&out[out_size], out_max - out_size, - new_format, - P_INT (pr, 0 + curarg))) - >= out_max - out_size) { - char *o; - out_max *= 2; - o = realloc (out, out_max); - if (!o) - goto mallocerror; - out = o; - } - out_size += ret; - curarg++; - break; - case 'f': - while ((ret = snprintf (&out[out_size], out_max - out_size, - new_format, - P_FLOAT (pr, 0 + curarg))) - >= out_max - out_size) { - char *o; - out_max *= 2; - o = realloc (out, out_max); - if (!o) - goto mallocerror; - out = o; - } - out_size += ret; - curarg++; - break; - case 'v': { - int i; - for (i = 0; i <= 2; i++) { - if (curarg > MAX_ARG) - goto maxargs; - while ((ret = snprintf (&out[out_size], - out_max - out_size, new_format, - P_VECTOR (pr, 0 + curarg)[i])) - >= out_max - out_size) { - char *o; - out_max *= 2; - o = realloc (out, out_max); - if (!o) - goto mallocerror; - out = o; - } - out_size += ret; - i++; - } - curarg++; - break; - } - } - } else if (*c == '%' && *(c + 1) == 's') { - const char *s; - if (curarg > MAX_ARG) - goto maxargs; - s = P_GSTRING (pr, 0 + curarg); - while ((ret = snprintf (&out[out_size], out_max - out_size, "%s", - s)) - >= out_max - out_size) { - char *o; - out_max *= 2; - o = realloc (out, out_max); - if (!o) - goto mallocerror; - out = o; - } - out_size += ret; - curarg++; - c += 2; - } else { - if (*c == '%') - c++; - - if (out_size == out_max) { - char *o; - out_max *= 2; - o = realloc (out, out_max); - if (!o) - goto mallocerror; - out = o; - } - out[out_size] = *c; - out_size++; - c++; - } - } - if (out_size == out_max) { - char *o; - out_max *= 2; - o = realloc (out, out_max); - if (!o) - goto mallocerror; - out = o; - } - out[out_size] = '\0'; - RETURN_STRING (pr, out); - free (out); - return; - - mallocerror: -// if (errno == ENOMEM) - // hopefully we can free up some mem so it can be used during shutdown -// free (out); - PR_Error (pr, "PF_sprintf: memory allocation error!\n"); - - endofstring: - PR_Error (pr, "PF_sprintf: unexpected end of string!\n"); - - maxargs: - PR_Error (pr, "PF_sprintf: argument limit exceeded\n"); + str = PR_NewString (pr); + dstr = PR_GetDString (pr, str); + PR_Sprintf (pr, dstr, "bi_printf", fmt, count, args); + PR_MakeTempString (pr, str); + R_STRING (pr) = str; } +/* + string () gametype +*/ static void PR_gametype (progs_t *pr) { RETURN_STRING (pr, pr_gametype); } +static builtin_t builtins[] = { + {"break", PF_break, 6}, + {"random", PF_random, 7}, + {"normalize", PF_normalize, 9}, + {"vlen", PF_vlen, 12}, + {"vectoyaw", PF_vectoyaw, 13}, + {"find", PF_Find, 18}, + {"dprint", PF_dprint, 25}, + {"ftos", PF_ftos, 26}, + {"vtos", PF_vtos, 27}, + {"coredump", PF_coredump, 28}, + {"traceon", PF_traceon, 29}, + {"traceoff", PF_traceoff, 30}, + {"eprint", PF_eprint, 31}, + {"rint", PF_rint, 36}, + {"floor", PF_floor, 37}, + {"ceil", PF_ceil, 38}, + {"fabs", PF_fabs, 43}, + {"cvar", PF_cvar, 45}, + {"nextent", PF_nextent, 47}, + {"vectoangles", PF_vectoangles, 51}, + {"cvar_set", PF_cvar_set, 72}, + {"stof", PF_stof, 81}, + + + {"strlen", PF_strlen, 100}, + {"charcount", PF_charcount, 101}, + {"sprintf", PF_sprintf, 109}, + {"ftoi", PF_ftoi, 110}, + {"itof", PF_itof, 111}, + {"itos", PF_itos, 112}, + {"stoi", PF_stoi, 113}, + {"stov", PF_stov, 114}, + {"gametype", PR_gametype, 115}, +}; + void PR_Cmds_Init (progs_t *pr) { - PR_AddBuiltin (pr, "break", PF_break, 6); // void () break - PR_AddBuiltin (pr, "random", PF_random, 7); // float () random - PR_AddBuiltin (pr, "normalize", PF_normalize, 9); // vector (vector v) normalize - PR_AddBuiltin (pr, "vlen", PF_vlen, 12); // float (vector v) vlen - PR_AddBuiltin (pr, "vectoyaw", PF_vectoyaw, 13); // float (vector v) vectoyaw - PR_AddBuiltin (pr, "find", PF_Find, 18); // entity (entity start, .(...) fld, ... match) find - PR_AddBuiltin (pr, "dprint", PF_dprint, 25); // void (string s) dprint - PR_AddBuiltin (pr, "ftos", PF_ftos, 26); // string (float f) ftos - PR_AddBuiltin (pr, "vtos", PF_vtos, 27); // string (vector v) vtos - PR_AddBuiltin (pr, "coredump", PF_coredump, 28); // void () coredump - PR_AddBuiltin (pr, "traceon", PF_traceon, 29); // void () traceon - PR_AddBuiltin (pr, "traceoff", PF_traceoff, 30); // void () traceoff - PR_AddBuiltin (pr, "eprint", PF_eprint, 31); // void (entity e) eprint - PR_AddBuiltin (pr, "rint", PF_rint, 36); // float (float v) rint - PR_AddBuiltin (pr, "floor", PF_floor, 37); // float (float v) floor - PR_AddBuiltin (pr, "ceil", PF_ceil, 38); // float (float v) ceil - PR_AddBuiltin (pr, "fabs", PF_fabs, 43); // float (float f) fabs - PR_AddBuiltin (pr, "cvar", PF_cvar, 45); // float (string s) cvar - PR_AddBuiltin (pr, "nextent", PF_nextent, 47); // entity (entity e) nextent - PR_AddBuiltin (pr, "vectoangles", PF_vectoangles, 51); // vector (vector v) vectoangles - PR_AddBuiltin (pr, "cvar_set", PF_cvar_set, 72); // void (string var, string val) cvar_set - PR_AddBuiltin (pr, "stof", PF_stof, 81); // float (string s) stof - - - PR_AddBuiltin (pr, "strlen", PF_strlen, 100); // float (string s) strlen - PR_AddBuiltin (pr, "charcount", PF_charcount, 101); // float (string goal, string s) charcount - PR_AddBuiltin (pr, "sprintf", PF_sprintf, 109); // string (...) sprintf - PR_AddBuiltin (pr, "ftoi", PF_ftoi, 110); // integer (float f) ftoi - PR_AddBuiltin (pr, "itof", PF_itof, 111); // float (integer i) itof - PR_AddBuiltin (pr, "itos", PF_itos, 112); // string (integer i) itos - PR_AddBuiltin (pr, "stoi", PF_stoi, 113); // integer (string s) stoi - PR_AddBuiltin (pr, "stov", PF_stov, 114); // vector (string s) stov - PR_AddBuiltin (pr, "gametype", PR_gametype, 115); // string () gametype + int i; + builtin_t *bi; + + for (i = 0; i < sizeof (builtins) / sizeof (builtins[0]); i++) { + bi = builtins + i; + PR_AddBuiltin (pr, bi->name, bi->proc, bi->binum); + } }; diff --git a/libs/gamecode/engine/pr_builtins.c b/libs/gamecode/engine/pr_builtins.c index e7722ee81..2810cbf79 100644 --- a/libs/gamecode/engine/pr_builtins.c +++ b/libs/gamecode/engine/pr_builtins.c @@ -98,7 +98,7 @@ PR_AddBuiltin (progs_t *pr, const char *name, builtin_proc builtin, int num) pr->builtins[i] = malloc (sizeof (builtin_t)); pr->builtins[i]->proc = builtin; pr->builtins[i]->name = name; - pr->builtins[i]->first_statement = i; + pr->builtins[i]->binum = i; Hash_Add (pr->builtin_hash, pr->builtins[i]); } @@ -127,7 +127,7 @@ PR_RelocateBuiltins (progs_t *pr) pr->progs_name, bi_name); return 0; } - func->first_statement = -bi->first_statement; + func->first_statement = -bi->binum; } return 1; } diff --git a/libs/gamecode/engine/pr_strings.c b/libs/gamecode/engine/pr_strings.c index 3843d4544..8767a0141 100644 --- a/libs/gamecode/engine/pr_strings.c +++ b/libs/gamecode/engine/pr_strings.c @@ -38,6 +38,7 @@ static __attribute__ ((unused)) const char rcsid[] = # include #endif +#include #include #include @@ -150,7 +151,7 @@ strref_free (void *_sr, void *_pr) int PR_LoadStrings (progs_t *pr) { - char *end = pr->pr_strings + pr->pr_stringsize; + char *end = pr->pr_strings + pr->progs->numstrings; char *str = pr->pr_strings; int count = 0; @@ -289,6 +290,25 @@ PR_SetTempString (progs_t *pr, const char *s) return string_index (pr, sr); } +void +PR_MakeTempString (progs_t *pr, int str) +{ + strref_t *sr = get_strref (pr, str); + + if (!sr) + PR_RunError (pr, "invalid string %d", str); + if (sr->dstring) { + if (sr->dstring->str) + sr->string = sr->dstring->str; + PR_Zone_Free (pr, sr->dstring); + } + if (!sr->string) + sr->string = pr_strdup (pr, ""); + sr->count = 0; + sr->next = pr->pr_xtstr; + pr->pr_xtstr = sr; +} + int PR_NewString (progs_t *pr) { @@ -325,3 +345,353 @@ PR_FreeTempStrings (progs_t *pr) } pr->pr_xtstr = 0; } + +// format adjustments +#define FMT_ALTFORM (1<<0) +#define FMT_LJUSTIFY (1<<1) +#define FMT_ZEROPAD (1<<2) +#define FMT_ADDSIGN (1<<3) +#define FMT_ADDBLANK (1<<4) +#define FMT_HEX (1<<5) + +typedef struct fmt_item_s { + byte type; + unsigned flags; + int minFieldWidth; + int precision; + union { + const char *string_var; + int integer_var; + unsigned uinteger_var; + float float_var; + } data; + struct fmt_item_s *next; +} fmt_item_t; + +#define PRINT(t) \ + switch ((doWidth << 1) | doPrecision) { \ + case 3: \ + dasprintf (result, tmp->str, current->minFieldWidth, \ + current->precision, current->data.t##_var); \ + break; \ + case 2: \ + dasprintf (result, tmp->str, current->minFieldWidth, \ + current->precision, current->data.t##_var); \ + break; \ + case 1: \ + dasprintf (result, tmp->str, current->precision, \ + current->data.t##_var); \ + break; \ + case 0: \ + dasprintf (result, tmp->str, current->data.t##_var); \ + break; \ + } + +/* + This function takes as input a linked list of fmt_item_t representing + EVERYTHING to be printed. This includes text that is not affected by + formatting. A string without any formatting would wind up with only one + list item. +*/ +static void +I_DoPrint (dstring_t *result, fmt_item_t *formatting) +{ + fmt_item_t *current = formatting; + dstring_t *tmp = dstring_new (); + + while (current) { + qboolean doPrecision, doWidth; + + doPrecision = -1 != current->precision; + doWidth = 0 != current->minFieldWidth; + + dsprintf (tmp, "%%%s%s%s%s%s%s%s", + (current->flags & FMT_ALTFORM) ? "#" : "", // hash + (current->flags & FMT_ZEROPAD) ? "0" : "", // zero padding + (current->flags & FMT_LJUSTIFY) ? "-" : "", // left justify + (current->flags & FMT_ADDBLANK) ? " " : "", // add space for +ve + (current->flags & FMT_ADDSIGN) ? "+" : "", // add sign always + doWidth ? "*" : "", + doPrecision ? ".*" : ""); + + switch (current->type) { + case 's': + dstring_appendstr (tmp, "s"); + PRINT (string); + break; + case 'i': + dstring_appendstr (tmp, "ld"); + PRINT (integer); + break; + case 'u': + if (current->flags & FMT_HEX) + dstring_appendstr (tmp, "lx"); + else + dstring_appendstr (tmp, "lu"); + PRINT (uinteger); + break; + case 'f': + dstring_appendstr (tmp, "f"); + PRINT (float); + break; + case 'g': + dstring_appendstr (tmp, "g"); + PRINT (float); + break; + default: + break; + } + current = current->next; + } + dstring_delete (tmp); +} + +static fmt_item_t *free_fmt_items; + +static fmt_item_t * +new_fmt_item (void) +{ + int i; + fmt_item_t *fi; + + if (!free_fmt_items) { + free_fmt_items = malloc (16 * sizeof (fmt_item_t)); + for (i = 0; i < 15; i++) + free_fmt_items[i].next = free_fmt_items + i + 1; + free_fmt_items[i].next = 0; + } + + fi = free_fmt_items; + free_fmt_items = fi->next; + memset (fi, 0, sizeof (*fi)); + fi->precision = -1; + return fi; +} + +static void +free_fmt_item (fmt_item_t *fi) +{ + fi->next = free_fmt_items; + free_fmt_items = fi; +} + +#undef P_var +#define P_var(p,n,t) (args[n]->t##_var) +void +PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, + const char *format, int count, pr_type_t **args) +{ + const char *c, *l; + const char *msg = ""; + fmt_item_t *fmt_items = 0; + fmt_item_t **fi = &fmt_items; + int fmt_count = 0; + + if (!name) + name = "PF_InternalSprintf"; + + *fi = new_fmt_item (); + c = l = format; + while (*c) { // count "%"s, checking our input along the way + if (*c++ == '%') { + if (c != l + 1) { + // have some unformatted text to print + (*fi)->precision = c - l - 1; + (*fi)->type = 's'; + (*fi)->data.string_var = l; + + (*fi)->next = new_fmt_item (); + fi = &(*fi)->next; + } + if (*c == '%') { + (*fi)->type = 's'; + (*fi)->data.string_var = "%"; + + (*fi)->next = new_fmt_item (); + fi = &(*fi)->next; + } else { + do { + switch (*c) { + // format options + case '\0': + msg = "Unexpected end of format string"; + goto error; + case '0': + (*fi)->flags |= FMT_ZEROPAD; + c++; + continue; + case '#': + (*fi)->flags |= FMT_ALTFORM; + c++; + continue; + case ' ': + (*fi)->flags |= FMT_ADDBLANK; + c++; + continue; + case '-': + (*fi)->flags |= FMT_LJUSTIFY; + c++; + continue; + case '+': + (*fi)->flags |= FMT_ADDSIGN; + c++; + continue; + case '.': + (*fi)->precision = 0; + c++; + while (isdigit (*c)) { + (*fi)->precision *= 10; + (*fi)->precision += *c++ - '0'; + } + continue; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + while (isdigit (*c)) { + (*fi)->minFieldWidth *= 10; + (*fi)->minFieldWidth += *c++ - '0'; + } + continue; + // format types + case '@': + // object + fmt_count++; + (*fi)->next = new_fmt_item (); + fi = &(*fi)->next; + break; + case 'e': + // entity + (*fi)->type = 'i'; + (*fi)->data.integer_var = + P_EDICTNUM (pr, fmt_count); + + fmt_count++; + (*fi)->next = new_fmt_item (); + fi = &(*fi)->next; + break; + case 'i': + // integer + (*fi)->type = *c; + (*fi)->data.integer_var = P_INT (pr, fmt_count); + + fmt_count++; + (*fi)->next = new_fmt_item (); + fi = &(*fi)->next; + break; + case 'f': + // float + case 'g': + // float, no trailing zeroes, trim "." if nothing + // after + (*fi)->type = *c; + (*fi)->data.float_var = P_FLOAT (pr, fmt_count); + + fmt_count++; + (*fi)->next = new_fmt_item (); + fi = &(*fi)->next; + break; + case 'p': + // pointer + (*fi)->flags |= FMT_ALTFORM; + (*fi)->type = 'x'; + (*fi)->data.uinteger_var = P_UINT (pr, fmt_count); + + fmt_count++; + (*fi)->next = new_fmt_item (); + fi = &(*fi)->next; + break; + case 's': + // string + (*fi)->type = *c; + (*fi)->data.string_var = P_GSTRING (pr, fmt_count); + + fmt_count++; + (*fi)->next = new_fmt_item (); + fi = &(*fi)->next; + break; + case 'v': + // vector + { + int i; + int flags = (*fi)->flags; + int precision = (*fi)->precision; + unsigned minWidth = (*fi)->minFieldWidth; + + (*fi)->flags = 0; + (*fi)->precision = -1; + (*fi)->minFieldWidth = 0; + + for (i = 0; i < 3; i++) { + if (i == 0) { + (*fi)->type = 's'; + (*fi)->data.string_var = "'"; + } else { + (*fi)->type = 's'; + (*fi)->data.string_var = " "; + } + (*fi)->next = new_fmt_item (); + fi = &(*fi)->next; + + (*fi)->flags = flags; + (*fi)->precision = precision; + (*fi)->minFieldWidth = minWidth; + (*fi)->type = 'g'; + (*fi)->data.float_var = + P_VECTOR (pr, fmt_count)[i]; + + (*fi)->next = new_fmt_item (); + fi = &(*fi)->next; + } + } + + (*fi)->type = 's'; + (*fi)->data.string_var = "'"; + + fmt_count++; + (*fi)->next = new_fmt_item (); + fi = &(*fi)->next; + break; + case 'x': + // integer, hex notation + (*fi)->type = *c; + (*fi)->data.uinteger_var = P_UINT (pr, fmt_count); + + fmt_count++; + (*fi)->next = new_fmt_item (); + fi = &(*fi)->next; + break; + } + break; + } while (1); + } + l = ++c; + } + } + if (c != l) { + // have some unformatted text to print + (*fi)->precision = c - l; + (*fi)->type = 's'; + (*fi)->data.string_var = l; + + (*fi)->next = new_fmt_item (); + fi = &(*fi)->next; + } + + if (0 && fmt_count != count) { + printf ("%d %d", fmt_count, count); + if (fmt_count > count) + msg = "Not enough arguments for format string."; + else + msg = "Too many arguments for format string."; + goto error; + } + + I_DoPrint (result, fmt_items); + while (fmt_items) { + fmt_item_t *t = fmt_items->next; + free_fmt_item (fmt_items); + fmt_items = t; + } + return; +error: + PR_RunError (pr, "%s: %s", name, msg); +} diff --git a/libs/util/dstring.c b/libs/util/dstring.c index c3c3a6ae2..d42430ad1 100644 --- a/libs/util/dstring.c +++ b/libs/util/dstring.c @@ -297,7 +297,7 @@ _dvsprintf (dstring_t *dstr, int offs, const char *fmt, va_list args) dstring_clearstr (dstr); // Make it a string // Some vsnprintf implementations return -1 on truncation while ((size = vsnprintf (dstr->str + offs, dstr->truesize - offs, fmt, args)) == -1) { - dstr->size = dstr->truesize + 1024; + dstr->size = (dstr->truesize & 1023) + 1024; dstring_adjust (dstr); #ifdef VA_LIST_IS_ARRAY VA_COPY (args, tmp_args); diff --git a/qw/source/sv_init.c b/qw/source/sv_init.c index 5d5039b24..ce5f751fe 100644 --- a/qw/source/sv_init.c +++ b/qw/source/sv_init.c @@ -134,7 +134,8 @@ SV_CreateBaseline (void) } else { ((entity_state_t*)svent->data)->colormap = 0; ((entity_state_t*)svent->data)->modelindex = - SV_ModelIndex (PR_GetString (&sv_pr_state, SVstring (svent, model))); + SV_ModelIndex (PR_GetString (&sv_pr_state, + SVstring (svent, model))); } // LordHavoc: setup baseline to include new effects ((entity_state_t*)svent->data)->alpha = 255; diff --git a/tools/qwaq/builtins.c b/tools/qwaq/builtins.c index 7231fc9e4..c29f8c0f6 100644 --- a/tools/qwaq/builtins.c +++ b/tools/qwaq/builtins.c @@ -41,6 +41,7 @@ static __attribute__ ((unused)) const char rcsid[] = #include #include +#include #include #include @@ -138,39 +139,14 @@ static void bi_printf (progs_t *pr) { const char *fmt = P_GSTRING (pr, 0); - char c; - int count = 0; - float *v; + int count = pr->pr_argc - 1; + pr_type_t **args = pr->pr_params + 1; + dstring_t *dstr = dstring_new (); - while ((c = *fmt++)) { - if (c == '%' && count < 7) { - switch (c = *fmt++) { - case 'i': - fprintf (stdout, "%i", - P_INT (pr, 1 + count++ * pr->pr_param_size)); - break; - case 'f': - fprintf (stdout, "%f", - P_FLOAT (pr, 1 + count++ * pr->pr_param_size)); - break; - case 's': - fputs (P_GSTRING (pr, 1 + count++ * pr->pr_param_size), - stdout); - break; - case 'v': - v = P_VECTOR (pr, 1 + count++ * pr->pr_param_size); - fprintf (stdout, "'%f %f %f'", v[0], v[1], v[2]); - break; - default: - fputc ('%', stdout); - fputc (c, stdout); - count = 7; - break; - } - } else { - fputc (c, stdout); - } - } + PR_Sprintf (pr, dstr, "bi_printf", fmt, count, args); + if (dstr->str) + fputs (dstr->str, stdout); + dstring_delete (dstr); } void diff --git a/tools/qwaq/main.qc b/tools/qwaq/main.qc index 74b199b7b..39635c20e 100644 --- a/tools/qwaq/main.qc +++ b/tools/qwaq/main.qc @@ -6,6 +6,7 @@ void () test_str = c = "strings "; d = "\n"; print (a + b + c + d); + printf ("%i \"%.5s\" %3.4f %v\n", 14, "hi there", 3.1415926, '4 1 3'); }; integer (integer argc, string []argv) main =