From 49cb03386ffd09a915d04c7b0d05ef6e954917c6 Mon Sep 17 00:00:00 2001 From: divverent Date: Wed, 23 Dec 2009 18:33:12 +0000 Subject: [PATCH] DP_QC_SPRINTF :P git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9654 d7cf8633-e32d-0410-b094-e92efae38249 --- clvm_cmds.c | 3 + mvm_cmds.c | 2 + prvm_cmds.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++++ prvm_cmds.h | 2 + svvm_cmds.c | 4 + 5 files changed, 239 insertions(+) diff --git a/clvm_cmds.c b/clvm_cmds.c index 83559289..67212a32 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -4585,6 +4585,9 @@ NULL, // #622 NULL, // #623 VM_CL_getextresponse, // #624 string getextresponse(void) NULL, // #625 +NULL, // #626 +VM_sprintf, // #627 string sprintf(string format, ...) +NULL, // #628 }; const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t); diff --git a/mvm_cmds.c b/mvm_cmds.c index 6042843f..1691c262 100644 --- a/mvm_cmds.c +++ b/mvm_cmds.c @@ -24,6 +24,7 @@ char *vm_m_extensions = "DP_QC_FINDCHAIN_TOFIELD " "DP_QC_LOG " "DP_QC_RENDER_SCENE " +"DP_QC_SPRINTF " "DP_QC_STRFTIME " "DP_QC_STRINGBUFFERS " "DP_QC_STRINGBUFFERS_CVARLIST " @@ -1406,6 +1407,7 @@ VM_M_addwantedserverlistkey, // #623 void addwantedhostcachekey(string key) VM_CL_getextresponse, // #624 string getextresponse(void) VM_netaddress_resolve, // #625 string netaddress_resolve(string, float) VM_M_getgamedirinfo, // #626 string getgamedirinfo(float n, float prop) +VM_sprintf, // #627 string sprintf(string format, ...) NULL }; diff --git a/prvm_cmds.c b/prvm_cmds.c index e3e1b322..01b6f8f8 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -5666,3 +5666,231 @@ void VM_isfunction(void) else PRVM_G_FLOAT(OFS_RETURN) = true; } + +/* +========= +VM_sprintf + +string sprintf(string format, ...) +========= +*/ + +void VM_sprintf(void) +{ + const char *s, *s0; + char outbuf[MAX_INPUTLINE]; + char *o = outbuf, *end = outbuf + sizeof(outbuf), *err; + int argpos = 1; + int width, precision, thisarg, flags; + char formatbuf[16]; + char *f; + qboolean isfloat; +#define PRINTF_ALTERNATE 1 +#define PRINTF_ZEROPAD 2 +#define PRINTF_LEFT 4 +#define PRINTF_SPACEPOSITIVE 8 +#define PRINTF_SIGNPOSITIVE 16 + + formatbuf[0] = '%'; + + s = PRVM_G_STRING(OFS_PARM0); + +#define GETARG_FLOAT(a) (((a)>=1 && (a)argc) ? (PRVM_G_FLOAT(OFS_PARM0 + 3 * (a))) : 0) +#define GETARG_INT(a) (((a)>=1 && (a)argc) ? (PRVM_G_INT(OFS_PARM0 + 3 * (a))) : 0) +#define GETARG_STRING(a) (((a)>=1 && (a)argc) ? (PRVM_G_STRING(OFS_PARM0 + 3 * (a))) : "") + + for(;;) + { + s0 = s; + switch(*s) + { + case 0: + goto finished; + break; + case '%': + ++s; + // complete directive format: + // %3$*1$.*2$ld + + width = -1; + precision = -1; + thisarg = -1; + flags = 0; + + // is number following? + if(*s >= '0' && *s <= '9') + { + width = strtol(s, &err, 10); + if(!err) + { + VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0); + goto finished; + } + if(*err == '$') + { + thisarg = width; + width = -1; + s = err + 1; + } + else + { + if(*s == '0') + { + flags |= PRINTF_ZEROPAD; + if(width == 0) + width = -1; // it was just a flag + } + s = err; + } + } + + if(width < 0) + { + for(;;) + { + switch(*s) + { + case '#': flags |= PRINTF_ALTERNATE; break; + case '0': flags |= PRINTF_ZEROPAD; break; + case '-': flags |= PRINTF_LEFT; break; + case ' ': flags |= PRINTF_SPACEPOSITIVE; break; + case '+': flags |= PRINTF_SIGNPOSITIVE; break; + default: + goto noflags; + } + ++s; + } +noflags: + if(*s == '*') + { + ++s; + if(*s >= '0' && *s <= '9') + { + width = strtol(s, &err, 10); + if(!err || *err != '$') + { + VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0); + goto finished; + } + s = err + 1; + } + else + width = argpos++; + width = GETARG_FLOAT(width); + } + else if(*s >= '0' && *s <= '9') + { + width = strtol(s, &err, 10); + if(!err) + { + VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0); + goto finished; + } + s = err; + } + if(width < 0) + { + flags |= PRINTF_LEFT; + width = -width; + } + } + + if(*s == '.') + { + ++s; + if(*s == '*') + { + ++s; + if(*s >= '0' && *s <= '9') + { + precision = strtol(s, &err, 10); + if(!err || *err != '$') + { + VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0); + goto finished; + } + s = err + 1; + } + else + precision = argpos++; + precision = GETARG_FLOAT(precision); + } + else if(*s >= '0' && *s <= '9') + { + precision = strtol(s, &err, 10); + if(!err) + { + VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0); + goto finished; + } + s = err; + } + else + { + VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0); + goto finished; + } + } + + isfloat = true; + for(;;) + { + switch(*s) + { + case 'h': isfloat = true; break; + case 'l': isfloat = false; break; + case 'L': isfloat = false; break; + case 'j': break; + case 'z': break; + case 't': break; + default: + goto nolength; + } + ++s; + } +nolength: + + if(thisarg < 0) + thisarg = argpos++; + + if(o < end - 1) + { + f = &formatbuf[1]; + if(flags & PRINTF_ALTERNATE) *f++ = '#'; + if(flags & PRINTF_ZEROPAD) *f++ = '0'; + if(flags & PRINTF_LEFT) *f++ = '-'; + if(flags & PRINTF_SPACEPOSITIVE) *f++ = ' '; + if(flags & PRINTF_SIGNPOSITIVE) *f++ = '+'; + *f++ = '*'; + *f++ = '.'; + *f++ = '*'; + *f++ = *s; + *f++ = 0; + switch(*s) + { + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': case 'c': + o += dpsnprintf(o, end - o, formatbuf, width, precision, (int) (isfloat ? GETARG_FLOAT(thisarg) : GETARG_INT(thisarg))); + break; + case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': + o += dpsnprintf(o, end - o, formatbuf, width, precision, (double) (isfloat ? GETARG_FLOAT(thisarg) : GETARG_INT(thisarg))); + break; + case 's': + o += dpsnprintf(o, end - o, formatbuf, width, precision, GETARG_STRING(thisarg)); + break; + default: + VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0); + goto finished; + } + } + ++s; + break; + default: + if(o < end - 1) + *o++ = *s++; + break; + } + } +finished: + *o = 0; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(outbuf); +} diff --git a/prvm_cmds.h b/prvm_cmds.h index 1a836e2d..0a3eafe5 100644 --- a/prvm_cmds.h +++ b/prvm_cmds.h @@ -448,3 +448,5 @@ void VM_SV_getextresponse (void); void VM_isfunction(void); void VM_callfunction(void); + +void VM_sprintf(void); diff --git a/svvm_cmds.c b/svvm_cmds.c index a7819b02..c923b83f 100644 --- a/svvm_cmds.c +++ b/svvm_cmds.c @@ -100,6 +100,7 @@ char *vm_sv_extensions = "DP_QC_NUM_FOR_EDICT " "DP_QC_RANDOMVEC " "DP_QC_SINCOSSQRTPOW " +"DP_QC_SPRINTF " "DP_QC_STRFTIME " "DP_QC_STRINGBUFFERS " "DP_QC_STRINGBUFFERS_CVARLIST " @@ -3999,6 +4000,9 @@ NULL, // #622 NULL, // #623 VM_SV_getextresponse, // #624 string getextresponse(void) NULL, // #625 +NULL, // #626 +VM_sprintf, // #627 string sprintf(string format, ...) +NULL, // #628 }; const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t); -- 2.39.2