mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-17 22:50:51 +00:00
new internal printf engine for progs, mostly thanks to Deek.
also a few cleanup bits
This commit is contained in:
parent
538d669887
commit
dfe7f263c7
8 changed files with 495 additions and 361 deletions
|
@ -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
|
||||
|
|
|
@ -43,13 +43,11 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -41,6 +41,7 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <QF/dstring.h>
|
||||
#include <QF/progs.h>
|
||||
#include <QF/zone.h>
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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 =
|
||||
|
|
Loading…
Reference in a new issue