diff --git a/polymer/eduke32/source/lunatic/control.lua b/polymer/eduke32/source/lunatic/control.lua index 3014ee1a0..ddccbdff6 100644 --- a/polymer/eduke32/source/lunatic/control.lua +++ b/polymer/eduke32/source/lunatic/control.lua @@ -486,6 +486,78 @@ function _qstrcat(qdst, qsrc) cstr_dst[i] = 0 end +local buf = ffi.new("char [?]", MAXQUOTELEN) + +function _qsprintf(qdst, qsrc, ...) + local dst = bcheck.quote_idx(qdst) + local src = bcheck.quote_idx(qsrc) + local vals = {...} + + local i, j, vi = 0, 0, 0 + + while (true) do + local ch = src[j] + local didfmt = false + + if (ch==0) then + break + end + + if (ch=='%') then + local nch = src[j+1] + if (nch=='d' or (nch=='l' and src[j+2]=='d')) then + -- number + didfmt = true + + if (vi == #vals) then + break + end + + local numstr = tostring(vals[vi]) + assert(type(numstr)=="string") + vi = vi+1 + + local ncopied = math.min(#numstr, MAXQUOTELEN-1-i) + ffi.copy(buf+i, numstr, ncopied) + + i = i+ncopied + j = j+1+(nch=='d' and 1 or 2) + elseif (nch=='s') then + -- string + didfmt = true + + if (vi == #vals) then + break + end + + local k = -1 + local tmpsrc = bcheck.quote_idx(vals[vi]) + + repeat + k = k+1 + buf[i] = tmpsrc[k] + i = i+1 + until (i < MAXQUOTELEN-1 and tmpsrc[k]~=0) + + j = j+2 + end + end + + if (not didfmt) then + buf[i] = src[j] + i = i+1 + j = j+1 + end + + if (i >= MAXQUOTELEN-1) then + break + end + end + + buf[i] = 0 + strcpy(dst, buf) +end + function _getkeyname(qdst, gfuncnum, which) local cstr_dst = bcheck.quote_idx(qdst) diff --git a/polymer/eduke32/source/lunatic/lunacon.lua b/polymer/eduke32/source/lunatic/lunacon.lua index aed791da8..33b84aea7 100644 --- a/polymer/eduke32/source/lunatic/lunacon.lua +++ b/polymer/eduke32/source/lunatic/lunacon.lua @@ -1351,6 +1351,10 @@ local function GetOrSetPerxvarCmd(Setp, Actorp) end +local function n_s_fmt(n) + return string.rep("%s,", n-1).."%s" +end + -- Various inner command handling functions / string capture strings. local handle = { @@ -1398,6 +1402,11 @@ local handle = v[1] or 0, v[2] or 0, v[3] or 0, v[4] or 0) end, + qsprintf = function(qdst, qsrc, ...) + local codes = {...} + return format("_con._qsprintf(%d,%d,%s)", qdst, qsrc, table.concat(codes, ',')) + end, + move = function(mv, ...) local flags = {...} return format(ACS":set_move(%s,%d)", mv, (flags[1] and bit.bor(...)) or 0) @@ -1428,10 +1437,6 @@ local handle = soundonce = "_con._soundonce(_aci,%1)", } -local function n_s_fmt(n) - return string.rep("%s,", n-1).."%s" -end - local userdef_common_pat = (arraypat + sp1)/{} * lpeg.Cc(0) * lpeg.Ct(singlememberpat) * sp1 -- NOTE about prefixes: most is handled by all_alt_pattern(), however commands @@ -1750,7 +1755,8 @@ local Cinner = { / "%3=_con._findnear(_aci,false,'d2',%1,%2)", -- quotes - qsprintf = sp1 * tok.rvar * sp1 * tok.rvar * (sp1 * tok.rvar)^-32, + qsprintf = sp1 * tok.rvar * sp1 * tok.rvar * (sp1 * tok.rvar)^-32 + / handle.qsprintf, qgetsysstr = cmd(R,R) / handle.NYI, qstrcat = cmd(R,R) diff --git a/polymer/eduke32/source/lunatic/test/sprite_access.con b/polymer/eduke32/source/lunatic/test/sprite_access.con index 4569d9c17..3b7988af4 100644 --- a/polymer/eduke32/source/lunatic/test/sprite_access.con +++ b/polymer/eduke32/source/lunatic/test/sprite_access.con @@ -51,7 +51,12 @@ onevent EVENT_ENTERLEVEL getticks t2 subvarvar t2 t - redefinequote 114 %d x four 0..MAXSPITES-1 iterations took %d ms in total - qsprintf 115 114 n t2 + // qsprintf test + redefinequote 116 0..MAXSPITES-1 + redefinequote 117 in total + + redefinequote 114 %d x four %s iterations took %d ms %s + qsprintf 115 /*<-*/ 114 /*args:*/ n 116 t2 117 + echo 115 endevent