Lunatic translator: fix quote commands, taking care of corner cases. Add test.

git-svn-id: https://svn.eduke32.com/eduke32@3511 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2013-02-21 18:53:49 +00:00
parent 9f843fb445
commit db2c24b7ef
3 changed files with 122 additions and 21 deletions

View file

@ -9,11 +9,13 @@ local math = require("math")
local geom = require("geom")
local con_lang = require("con_lang")
local byte = require("string").byte
local setmetatable = setmetatable
local assert = assert
local error = error
local print = print
local tostring = tostring
local type = type
local unpack = unpack
@ -455,12 +457,13 @@ local function strlen(cstr)
assert(false)
end
-- NOTE: dst==src is OK (effectively a no-op)
local function strcpy(dst, src)
local i=-1
repeat
i = i+1
dst[i] = src[i]
until (src[i]~=0)
until (src[i]==0)
end
function _qstrlen(qnum)
@ -473,16 +476,42 @@ function _qstrcpy(qdst, qsrc)
strcpy(cstr_dst, cstr_src)
end
-- NOTE: qdst==qsrc is OK (duplicates the quote)
function _qstrcat(qdst, qsrc)
local cstr_dst = bcheck.quote_idx(qdst)
local cstr_src = bcheck.quote_idx(qsrc)
local i, j = strlen(cstr_dst), 0
while (i < MAXQUOTELEN-1) do
cstr_dst[i] = cstr_src[j]
if (cstr_src[0]==0) then
return
end
if (cstr_dst[0]==0) then
return strcpy(cstr_dst, cstr_src)
end
-- From here on: destination and source quote (potentially aliased) are
-- nonempty.
local slen_dst = strlen(cstr_dst)
assert(slen_dst <= MAXQUOTELEN-1)
if (slen_dst == MAXQUOTELEN-1) then
return
end
local i = slen_dst
local j = 0
repeat
-- NOTE: don't copy the first char yet, so that the qdst==qsrc case
-- works correctly.
i = i+1
j = j+1
end
cstr_dst[i] = cstr_src[j]
until (i >= MAXQUOTELEN-1 or cstr_src[j]==0)
-- Now copy the first char!
cstr_dst[slen_dst] = cstr_src[0]
cstr_dst[i] = 0
end
@ -493,7 +522,7 @@ function _qsprintf(qdst, qsrc, ...)
local src = bcheck.quote_idx(qsrc)
local vals = {...}
local i, j, vi = 0, 0, 0
local i, j, vi = 0, 0, 1
while (true) do
local ch = src[j]
@ -503,13 +532,13 @@ function _qsprintf(qdst, qsrc, ...)
break
end
if (ch=='%') then
if (ch==byte'%') then
local nch = src[j+1]
if (nch=='d' or (nch=='l' and src[j+2]=='d')) then
if (nch==byte'd' or (nch==byte'l' and src[j+2]==byte'd')) then
-- number
didfmt = true
if (vi == #vals) then
if (vi > #vals) then
break
end
@ -521,23 +550,24 @@ function _qsprintf(qdst, qsrc, ...)
ffi.copy(buf+i, numstr, ncopied)
i = i+ncopied
j = j+1+(nch=='d' and 1 or 2)
elseif (nch=='s') then
j = j+1+(nch==byte'd' and 1 or 2)
elseif (nch==byte's') then
-- string
didfmt = true
if (vi == #vals) then
if (vi > #vals) then
break
end
local k = -1
local tmpsrc = bcheck.quote_idx(vals[vi])
vi = vi+1
i = i-1
repeat
i = i+1
k = k+1
buf[i] = tmpsrc[k]
i = i+1
until (i < MAXQUOTELEN-1 and tmpsrc[k]~=0)
until (i >= MAXQUOTELEN-1 or tmpsrc[k]==0)
j = j+2
end

View file

@ -747,11 +747,13 @@ function Cmd.definequote(qnum, quotestr)
quotestr = stripws(quotestr)
if (ffi) then
if (#quotestr >= conl.MAXQUOTELEN) then
warnprintf("quote %d truncated to %d characters.", conl.MAXQUOTELEN-1)
end
if (#quotestr >= conl.MAXQUOTELEN) then
-- NOTE: Actually, C_DefineQuote takes care of this! That is,
-- standalone, the string isn't truncated.
warnprintf("quote %d truncated to %d characters.", qnum, conl.MAXQUOTELEN-1)
end
if (ffi) then
ffiC.C_DefineQuote(qnum, quotestr)
end
@ -2720,8 +2722,11 @@ else
for _, fname in ipairs(filenames) do
local ok, msg = pcall(do_include_file, "", fname)
if (not ok) then
print_on_failure(msg)
if (not ok or g_numerrors > 0) then
if (not ok) then
-- Unexpected error in the Lua code (i.e. a bug here).
print_on_failure(msg)
end
return nil
end
end

View file

@ -0,0 +1,66 @@
// Don't try in C-CON!
gamevar slen 0 0
gamevar n -12345678 0 // a number having length 9 in the decimal representation
// overlong string at definition (should warn)
definequote 400 123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789=123456789-
onevent EVENT_ENTERLEVEL
redefinequote 114 QWE
redefinequote 115 012345678|
// qstrcat X Y, where X==Y: duplicates the quote
qstrcat 115 115
userquote 115 // "012345678|012345678|"
// simple qstrcpy test
qstrcpy 116 115
userquote 116 // "012345678|012345678|"
redefinequote 117 %s -- %d -- %s -- %d slen=%d
// test:
// - same destination quote as the format quote
// - multiple conversions
qstrlen slen 115 // -> 10
qsprintf 117 /*<-*/ 117 /*args:*/ 116 9999 114 5555 slen
userquote 117 // "012345678|012345678| -- 9999 -- QWE -- 5555 slen=10"
redefinequote 117 %s -- %d -- %s -- %d slen=%d
// test:
// - same destination quote as on of the source quotes under %s conversion
qsprintf 116 /*<-*/ 117 /*args:*/ 116 9999 116 5555 slen
userquote 116 // "012345678|012345678| -- 9999 -- 012345678|012345678| -- 5555 slen=10"
// aliased qstrcpy test (a no-op)
qstrcpy 115 115
userquote 115 // still "012345678|012345678|"
qstrcat 115 115 // len 40
qstrcat 115 115 // len 80
qstrcat 115 115
// result now: 12 x "012345678|" concantenated with "0123456" (= total length 127 = MAXQUOTELEN-1)
qstrcat 115 115 // this one is redundant, but must not overflow the quote buffer
userquote 115
redefinequote 117 X%s
qsprintf 117 /*<-*/ 117 /*args:*/ 115
userquote 117 // result: "X" .. 12 x "012345678|" .. "012345" (= total length 127 = MAXQUOTELEN-1)
// 32 %d (or %ld) conversion
redefinequote 117 %ld|%d|%ld|%d|%ld|%ld|%d|%ld|%d|%ld/%ld|%d|%ld|%d|%ld|%ld|%d|%ld|%d|%ld/%ld|%d|%ld|%d|%ld|%ld|%d|%ld|%d|%ld/%d/%d
// string shorter than MAXQUOTELEN-1:
qsprintf 116 /*<-*/ 117 /*args:*/ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// result: "0|1|2|3|4|5|6|7|8|9/0|1|2|3|4|5|6|7|8|9/0|1|2|3|4|5|6|7|8|9/0/1"
userquote 116
// string longer than MAXQUOTELEN-1:
qsprintf 116 /*<-*/ 117 /*args:*/ n n n n n n n n n n /**/ n n n n n n n n n n /**/ n n
userquote 116
// result: 10 x "-12345678" .. "/-12345678|-12345678|-123456" (= total length 127 = MAXQUOTELEN-1)
// overlong string at redefinition
redefinequote 117 123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789=123456789-
userquote 117 // should end in "=1234567" (= total length 127 = MAXQUOTELEN-1)
userquote 400 // same thing
endevent