mirror of
				https://github.com/thunderbrewhq/thunderbrew
				synced 2025-10-31 00:06:05 +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
	 VDm
						VDm