mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-04-18 02:52:47 +03:00
feat(script): implement FrameScript_Sprintf
This commit is contained in:
parent
382d962900
commit
02e683d699
@ -7,160 +7,6 @@
|
||||
#include <cctype>
|
||||
|
||||
|
||||
// TEMPORARY SOLUTION (based on lstrlib.c from LUA)
|
||||
/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
|
||||
#define MAX_ITEM 512
|
||||
/* valid flags in a format specification */
|
||||
#define FLAGS "-+ #0"
|
||||
/*
|
||||
** maximum size of each format specification (such as '%-099.99d')
|
||||
** (+10 accounts for %99.99x plus margin of error)
|
||||
*/
|
||||
#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
|
||||
|
||||
#define uchar(c) ((unsigned char)(c))
|
||||
|
||||
|
||||
static void addchar(char* b, char ch) {
|
||||
auto len = strlen(b);
|
||||
b[len++] = ch;
|
||||
b[len] = '\0';
|
||||
}
|
||||
|
||||
static void addquoted(lua_State* L, char* b, int arg) {
|
||||
size_t l;
|
||||
const char* s = luaL_checklstring(L, arg, &l);
|
||||
addchar(b, '"');
|
||||
while (l--) {
|
||||
switch (*s) {
|
||||
case '"':
|
||||
case '\\':
|
||||
case '\n': {
|
||||
addchar(b, '\\');
|
||||
addchar(b, *s);
|
||||
break;
|
||||
}
|
||||
case '\r': {
|
||||
strcat(b, "\\r");
|
||||
break;
|
||||
}
|
||||
case '\0': {
|
||||
strcat(b, "\\000");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
addchar(b, *s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
s++;
|
||||
}
|
||||
addchar(b, '"');
|
||||
}
|
||||
|
||||
static const char* scanformat(lua_State* L, const char* strfrmt, char* form) {
|
||||
const char* p = strfrmt;
|
||||
while (*p != '\0' && strchr(FLAGS, *p) != NULL)
|
||||
p++; /* skip flags */
|
||||
if ((size_t)(p - strfrmt) >= sizeof(FLAGS))
|
||||
luaL_error(L, "invalid format (repeated flags)");
|
||||
if (isdigit(uchar(*p)))
|
||||
p++; /* skip width */
|
||||
if (isdigit(uchar(*p)))
|
||||
p++; /* (2 digits at most) */
|
||||
if (*p == '.') {
|
||||
p++;
|
||||
if (isdigit(uchar(*p)))
|
||||
p++; /* skip precision */
|
||||
if (isdigit(uchar(*p)))
|
||||
p++; /* (2 digits at most) */
|
||||
}
|
||||
if (isdigit(uchar(*p)))
|
||||
luaL_error(L, "invalid format (width or precision too long)");
|
||||
*(form++) = '%';
|
||||
strncpy(form, strfrmt, p - strfrmt + 1);
|
||||
form += p - strfrmt + 1;
|
||||
*form = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static void addintlen(char* form) {
|
||||
size_t l = strlen(form);
|
||||
char spec = form[l - 1];
|
||||
strcpy(form + l - 1, LUA_INTFRMLEN);
|
||||
form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
|
||||
form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
|
||||
}
|
||||
|
||||
static int str_format(lua_State* L, char* b) {
|
||||
int arg = 2;
|
||||
size_t sfl;
|
||||
const char* strfrmt = luaL_checklstring(L, arg, &sfl);
|
||||
const char* strfrmt_end = strfrmt + sfl;
|
||||
while (strfrmt < strfrmt_end) {
|
||||
if (*strfrmt != '%')
|
||||
addchar(b, *strfrmt++);
|
||||
else if (*++strfrmt == '%')
|
||||
addchar(b, *strfrmt++); /* %% */
|
||||
else { /* format item */
|
||||
char form[MAX_FORMAT]; /* to store the format (`%...') */
|
||||
char buff[MAX_ITEM]; /* to store the formatted item */
|
||||
arg++;
|
||||
strfrmt = scanformat(L, strfrmt, form);
|
||||
switch (*strfrmt++) {
|
||||
case 'c': {
|
||||
sprintf(buff, form, (int)luaL_checknumber(L, arg));
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
case 'i': {
|
||||
addintlen(form);
|
||||
sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
|
||||
break;
|
||||
}
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X': {
|
||||
addintlen(form);
|
||||
sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
|
||||
break;
|
||||
}
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'G': {
|
||||
sprintf(buff, form, (double)luaL_checknumber(L, arg));
|
||||
break;
|
||||
}
|
||||
case 'q': {
|
||||
addquoted(L, b, arg);
|
||||
continue; /* skip the 'addsize' at the end */
|
||||
}
|
||||
case 's': {
|
||||
size_t l;
|
||||
const char* s = luaL_checklstring(L, arg, &l);
|
||||
if (!strchr(form, '.') && l >= 100) {
|
||||
/* no precision and string is too long to be formatted;
|
||||
keep original string */
|
||||
continue; /* skip the `addsize' at the end */
|
||||
} else {
|
||||
sprintf(buff, form, s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
default: { /* also treat cases `pnLlh' */
|
||||
return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " LUA_QL("format"), *(strfrmt - 1));
|
||||
}
|
||||
}
|
||||
strcat(b, buff);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// END OF TEMPORARY SOLUTION
|
||||
|
||||
int32_t CSimpleFontString_IsObjectType(lua_State* L) {
|
||||
WHOA_UNIMPLEMENTED(0);
|
||||
}
|
||||
@ -301,9 +147,9 @@ int32_t CSimpleFontString_SetFormattedText(lua_State* L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char b[2048] = {};
|
||||
str_format(L, b);
|
||||
string->SetText(b, 0);
|
||||
char text[2048] = {};
|
||||
FrameScript_Sprintf(L, 2, text, sizeof(text));
|
||||
string->SetText(text, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <storm/Array.hpp>
|
||||
#include <storm/String.hpp>
|
||||
#include <tempest/Vector.hpp>
|
||||
#include <cctype>
|
||||
|
||||
const char* g_glueScriptEvents[41];
|
||||
const char* g_scriptEvents[722];
|
||||
@ -867,6 +868,216 @@ void FrameScript_UnregisterScriptEvent(FrameScript_Object* object, FrameScript_E
|
||||
}
|
||||
}
|
||||
|
||||
static void addchar(char* buffer, size_t bufferSize, char ch) {
|
||||
auto length = SStrLen(buffer);
|
||||
if (length + 1 < bufferSize)
|
||||
{
|
||||
buffer[length++] = ch;
|
||||
buffer[length] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static void addstring(char* buffer, size_t bufferSize, const char* source) {
|
||||
uint32_t dsize = 0;
|
||||
uint32_t size = 0;
|
||||
|
||||
dsize = SStrLen(buffer);
|
||||
size = SStrLen(source);
|
||||
|
||||
if (dsize + size >= bufferSize) {
|
||||
size = bufferSize - dsize;
|
||||
// Check for space for trailing zero
|
||||
if (size < 2) {
|
||||
size = 0;
|
||||
} else {
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
if (size > 0)
|
||||
memmove(&buffer[dsize], source, size);
|
||||
|
||||
buffer[dsize + size] = '\0';
|
||||
}
|
||||
|
||||
static void addstring(char* buffer, size_t bufferSize, const char* source, size_t count) {
|
||||
uint32_t dsize = 0;
|
||||
uint32_t size = 0;
|
||||
|
||||
dsize = SStrLen(buffer);
|
||||
size = std::min(SStrLen(source), count);
|
||||
|
||||
if (dsize + size >= bufferSize) {
|
||||
size = bufferSize - dsize;
|
||||
// Check for space for trailing zero
|
||||
if (size < 2) {
|
||||
size = 0;
|
||||
} else {
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
if (size > 0)
|
||||
memmove(&buffer[dsize], source, size);
|
||||
|
||||
buffer[dsize + size] = '\0';
|
||||
}
|
||||
|
||||
static void addquoted(lua_State* L, char* buffer, size_t bufferSize, int arg) {
|
||||
size_t l;
|
||||
const char* s = luaL_checklstring(L, arg, &l);
|
||||
addchar(buffer, bufferSize, '"');
|
||||
while (l--) {
|
||||
switch (*s) {
|
||||
case '"':
|
||||
case '\\':
|
||||
case '\n': {
|
||||
addchar(buffer, bufferSize, '\\');
|
||||
addchar(buffer, bufferSize, *s);
|
||||
break;
|
||||
}
|
||||
case '\r': {
|
||||
addstring(buffer, bufferSize, "\\r");
|
||||
break;
|
||||
}
|
||||
case '\0': {
|
||||
addstring(buffer, bufferSize, "\\000");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
addchar(buffer, bufferSize, *s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
s++;
|
||||
}
|
||||
addchar(buffer, bufferSize, '"');
|
||||
}
|
||||
|
||||
#define FORMAT_FLAGS "-+ #0"
|
||||
|
||||
static const char* scanformat(lua_State* L, const char* strfrmt, char* form) {
|
||||
const char* flags = "-+ #0";
|
||||
const char* p = strfrmt;
|
||||
|
||||
while (*p != '\0' && SStrChrR(FORMAT_FLAGS, *p) != NULL) {
|
||||
p++; /* skip flags */
|
||||
}
|
||||
|
||||
if ((size_t)(p - strfrmt) >= sizeof(FORMAT_FLAGS)) {
|
||||
luaL_error(L, "invalid format (repeated flags)");
|
||||
}
|
||||
|
||||
if (isdigit((unsigned char)(*p))) {
|
||||
p++; /* skip width */
|
||||
}
|
||||
|
||||
if (isdigit((unsigned char)(*p))) {
|
||||
p++; /* (2 digits at most) */
|
||||
}
|
||||
|
||||
if (*p == '.') {
|
||||
p++;
|
||||
if (isdigit((unsigned char)(*p))) {
|
||||
p++; /* skip precision */
|
||||
}
|
||||
if (isdigit((unsigned char)(*p))) {
|
||||
p++; /* (2 digits at most) */
|
||||
}
|
||||
}
|
||||
if (isdigit((unsigned char)(*p))) {
|
||||
luaL_error(L, "invalid format (width or precision too long)");
|
||||
}
|
||||
|
||||
*(form++) = '%';
|
||||
strncpy(form, strfrmt, p - strfrmt + 1);
|
||||
form += p - strfrmt + 1;
|
||||
*form = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static void addintlen(char* form) {
|
||||
size_t l = SStrLen(form);
|
||||
char spec = form[l - 1];
|
||||
strcpy(form + l - 1, LUA_INTFRMLEN);
|
||||
form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
|
||||
form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
|
||||
}
|
||||
|
||||
void FrameScript_Sprintf(lua_State* L, int startIndex, char* buffer, uint32_t bufferSize) {
|
||||
// maximum size of each formatted item (> len(format('%99.99f', -1e308)))
|
||||
const size_t MAX_ITEM = 512;
|
||||
|
||||
// maximum size of each format specification (such as '%-099.99d')
|
||||
// (+10 accounts for %99.99x plus margin of error)
|
||||
const size_t MAX_FORMAT = sizeof(FORMAT_FLAGS) + sizeof(LUA_INTFRMLEN) + 10;
|
||||
|
||||
int arg = startIndex;
|
||||
size_t sfl;
|
||||
const char* strfrmt = luaL_checklstring(L, arg, &sfl);
|
||||
const char* strfrmt_end = strfrmt + sfl;
|
||||
while (strfrmt < strfrmt_end) {
|
||||
if (*strfrmt != '%') {
|
||||
addchar(buffer, bufferSize, *strfrmt++);
|
||||
} else if (*++strfrmt == '%') {
|
||||
addchar(buffer, bufferSize, *strfrmt++); /* %% */
|
||||
} else { /* format item */
|
||||
char form[MAX_FORMAT]; /* to store the format (`%...') */
|
||||
char buff[MAX_ITEM]; /* to store the formatted item */
|
||||
arg++;
|
||||
strfrmt = scanformat(L, strfrmt, form);
|
||||
switch (*strfrmt++) {
|
||||
case 'c': {
|
||||
sprintf(buff, form, (int)luaL_checknumber(L, arg));
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
case 'i': {
|
||||
addintlen(form);
|
||||
sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
|
||||
break;
|
||||
}
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X': {
|
||||
addintlen(form);
|
||||
sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
|
||||
break;
|
||||
}
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'G': {
|
||||
sprintf(buff, form, (double)luaL_checknumber(L, arg));
|
||||
break;
|
||||
}
|
||||
case 'q': {
|
||||
addquoted(L, buffer, bufferSize, arg);
|
||||
continue; /* skip the 'addsize' at the end */
|
||||
}
|
||||
case 's': {
|
||||
size_t l;
|
||||
const char* s = luaL_checklstring(L, arg, &l);
|
||||
if (!strchr(form, '.') && l >= 100) {
|
||||
/* no precision and string is too long to be formatted;
|
||||
keep original string */
|
||||
continue; /* skip the `addsize' at the end */
|
||||
} else {
|
||||
sprintf(buff, form, s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
default: { /* also treat cases `pnLlh' */
|
||||
luaL_error(L, "invalid option " LUA_QL("%%%c") " to " LUA_QL("format"), *(strfrmt - 1));
|
||||
}
|
||||
}
|
||||
addstring(buffer, bufferSize, buff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GlueScriptEventsInitialize() {
|
||||
g_glueScriptEvents[0] = "SET_GLUE_SCREEN";
|
||||
g_glueScriptEvents[1] = "START_GLUE_MUSIC";
|
||||
|
@ -100,6 +100,8 @@ void FrameScript_SignalEvent(uint32_t index, const char* format, ...);
|
||||
|
||||
void FrameScript_UnregisterScriptEvent(FrameScript_Object* object, FrameScript_EventObject* event);
|
||||
|
||||
void FrameScript_Sprintf(lua_State* L, int startIndex, char* buffer, uint32_t bufferSize);
|
||||
|
||||
void GlueScriptEventsInitialize();
|
||||
|
||||
void ScriptEventsInitialize();
|
||||
|
@ -19,8 +19,11 @@ int32_t Script_IsShiftKeyDown(lua_State* L) {
|
||||
}
|
||||
|
||||
int32_t Script_GetBuildInfo(lua_State* L) {
|
||||
lua_pushstring(L, "WHOA");
|
||||
lua_pushstring(L, "Release");
|
||||
auto szVersion = FrameScript_GetText("VERSION", -1, GENDER_NOT_APPLICABLE);
|
||||
auto szVersionType = FrameScript_GetText("RELEASE_BUILD", -1, GENDER_NOT_APPLICABLE);
|
||||
|
||||
lua_pushstring(L, szVersion);
|
||||
lua_pushstring(L, szVersionType);
|
||||
lua_pushstring(L, "3.3.5");
|
||||
lua_pushstring(L, "12340");
|
||||
lua_pushstring(L, "Jun 24 2010");
|
||||
|
Loading…
Reference in New Issue
Block a user