Added "string_format" script function

Some code refactoring.
This commit is contained in:
NovaRain
2019-12-01 12:09:58 +08:00
parent 84076a2586
commit 2a2849537c
11 changed files with 105 additions and 51 deletions
+7 -7
View File
@@ -707,29 +707,29 @@ CreditsAtBottom=0
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;To change the path and filename of the critical table file, uncomment the next line
;OverrideCriticalFile=CriticalOverrides.ini
;OverrideCriticalFile=sfall\CriticalOverrides.ini
;To change the relationship between SPECIAL stats and derived stats, uncomment the next line
;See the Stats.ini in the modders pack for an example file
;DerivedStats=Stats.ini
;DerivedStats=sfall\Stats.ini
;Allows you to edit the skill tables
;Point the next line to an ini file containing the replacement skill data
;SkillsFile=Skills.ini
;SkillsFile=sfall\Skills.ini
;To add additional perks to the game, uncomment the next line and set it to point to a file containing perk information
;PerksFile=Perks.ini
;PerksFile=sfall\Perks.ini
;To add additional books to the game, uncomment the next line and point to a file containing book information
;See the Books.ini in the modders pack for an example file
;BooksFile=Books.ini
;BooksFile=sfall\Books.ini
;Allows you to change some parameters for drugs and their addictions
;See the Drugs.ini in the modders pack for an example file
;DrugsFile=Drugs.ini
;DrugsFile=sfall\Drugs.ini
;Point to an ini file containing elevator data
;ElevatorsFile=Elevators.ini
;ElevatorsFile=sfall\Elevators.ini
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Scripts]
+1
View File
@@ -320,6 +320,7 @@
#define spatial_radius(obj) sfall_func1("spatial_radius", obj)
#define string_compare(str1, str2) sfall_func2("string_compare", str1, str2)
#define string_compare_locale(str1, str2, codePage) sfall_func3("string_compare", str1, str2, codePage)
#define string_format(format, a1, a2) sfall_func3("string_format", format, a1, a2)
#define tile_refresh_display sfall_func0("tile_refresh_display")
#define unjam_lock(obj) sfall_func1("unjam_lock", obj)
#define unset_unique_id(obj) sfall_func2("set_unique_id", obj, -1)
+5 -1
View File
@@ -262,7 +262,7 @@ Some utility/math functions are available:
- you can use this to search for a substring in a string like this: strlen(get_array(string_split(haystack, needle), 0))
> string substr(string, start, length)
- cuts a substring from a string starting at "start" up to "length" characters. The first character position starts with 0 (zero).
- cuts a substring from a string starting at "start" up to "length" characters. The first character position is 0 (zero).
- If start is negative - it indicates starting position from the end of the string (for example substr("test", -2, 2) will return last 2 charactes: "st").
- If length is negative - it means so many characters will be omitted from the end of string (example: substr("test", 0, -2) will return string without last 2 characters: "te").
- If length is zero - it will return a string from the starting position to the end of the string **New behavior** for sfall 4.2.2/3.8.22
@@ -682,6 +682,10 @@ optional argument:
- codePage: code page number to properly compare national characters in the range 128-255 of the ASCII code table
available encodings: 1250-1252, 866
> string sfall_func3("string_format", string format, any val1, any val2, ...)
- formats given value using standard syntax of C printf function (google "printf" for format details). However it is limited to formatting up to 4 values
- formatting is only supported for %s and %d. The format string is limited to 1024 characters
------------------------
------ MORE INFO -------
------------------------
+5 -6
View File
@@ -310,19 +310,18 @@ hide:
}
}
static char* artDbgMsg = "\nError: file not found: %s\n";
static char* artDbgMsg = "\nERROR: File not found: %s\n";
static void __declspec(naked) art_data_size_hook() {
__asm {
test edi, edi;
jz artNotExist;
retn;
artNotExist:
mov eax, [esp + 0x124 - 0x1C + 4]; // filename
push eax;
mov edx, [esp + 0x124 - 0x1C + 4]; // filename
push edx;
push artDbgMsg;
call fo::funcoffs::debug_printf_;
mov eax, [esp + 0x124 - 0x1C + 12]; // filename
push eax;
push edx; // filename
push artDbgMsg;
lea eax, [esp + 0x124 - 0x124 + 20]; // buf
push eax;
@@ -368,7 +367,7 @@ static void DebugModePatch() {
if (iniGetInt("Debugging", "HideObjIsNullMsg", 0, ::sfall::ddrawIni)) {
MakeJump(0x453FD2, dbg_error_hack);
}
// prints a debug message about missing art file for critters to debug.log and the message window
// prints a debug message about missing art file for critters to both debug.log and the message window
HookCall(0x419B65, art_data_size_hook);
dlogr(" Done", DL_INIT);
+1 -1
View File
@@ -523,7 +523,7 @@ end:
static void __declspec(naked) DialogHook() {
__asm {
test inLoop, DIALOG; // check bit flag
test inLoop, DIALOG; // check byte flag
jz changeMode;
jmp fo::funcoffs::gdProcess_;
changeMode:
+2
View File
@@ -51,6 +51,8 @@ static DWORD _stdcall HandleMapUpdateForScripts(const DWORD procId);
static int idle;
char ScriptExtender::gTextBuffer[5120]; // used as global temp text buffer for script functions
std::string ScriptExtender::iniConfigFolder;
struct GlobalScript {
+5
View File
@@ -40,6 +40,11 @@ public:
static std::string iniConfigFolder;
static char gTextBuffer[5120];
// returns the size of the global text buffer
inline static const long TextBufferSize() { return sizeof(gTextBuffer); }
static long GetScriptReturnValue();
static long GetResetScriptReturnValue();
@@ -132,6 +132,7 @@ static const SfallMetarule metarules[] = {
{"show_window", sf_show_window, 0, 1, -1, {ARG_STRING}},
{"spatial_radius", sf_spatial_radius, 1, 1, 0, {ARG_OBJECT}},
{"string_compare", sf_string_compare, 2, 3, 0, {ARG_STRING, ARG_STRING, ARG_INT}},
{"string_format", sf_string_format, 2, 5, 0, {ARG_STRING, ARG_ANY, ARG_ANY, ARG_ANY, ARG_ANY}},
{"tile_refresh_display", sf_tile_refresh_display, 0, 0},
{"unjam_lock", sf_unjam_lock, 1, 1, -1, {ARG_OBJECT}},
{"unwield_slot", sf_unwield_slot, 2, 2, -1, {ARG_OBJECT, ARG_INT}},
+10 -13
View File
@@ -42,7 +42,7 @@ namespace sfall
namespace script
{
const char* stringTooLong = "%s() - the string length exceeds maximum of 64 characters.";
const char* stringTooLong = "%s() - the string exceeds maximum length of 64 characters.";
void sf_set_dm_model(OpcodeContext& ctx) {
auto model = ctx.arg(0).strValue();
@@ -453,7 +453,6 @@ specialIni:
return 1;
}
static char IniStrBuffer[256];
static DWORD GetIniSetting(const char* str, bool isString) {
const char* key;
char section[33], file[128];
@@ -462,9 +461,9 @@ static DWORD GetIniSetting(const char* str, bool isString) {
return -1;
}
if (isString) {
IniStrBuffer[0] = 0;
iniGetString(section, key, "", IniStrBuffer, 256, file);
return (DWORD)&IniStrBuffer[0];
ScriptExtender::gTextBuffer[0] = 0;
iniGetString(section, key, "", ScriptExtender::gTextBuffer, 256, file);
return (DWORD)&ScriptExtender::gTextBuffer[0];
} else {
return iniGetInt(section, key, -1, file);
}
@@ -1037,8 +1036,8 @@ void sf_set_ini_setting(OpcodeContext& ctx) {
const char* saveValue;
if (argVal.isInt()) {
_itoa_s(argVal.rawValue(), IniStrBuffer, 10);
saveValue = IniStrBuffer;
_itoa_s(argVal.rawValue(), ScriptExtender::gTextBuffer, 10);
saveValue = ScriptExtender::gTextBuffer;
} else {
saveValue = argVal.strValue();
}
@@ -1075,12 +1074,10 @@ static std::string GetIniFilePath(const ScriptValue& arg) {
return fileName;
}
char getIniSectionBuf[5120];
void sf_get_ini_sections(OpcodeContext& ctx) {
GetPrivateProfileSectionNamesA(getIniSectionBuf, 5120, GetIniFilePath(ctx.arg(0)).data());
GetPrivateProfileSectionNamesA(ScriptExtender::gTextBuffer, ScriptExtender::TextBufferSize(), GetIniFilePath(ctx.arg(0)).data());
std::vector<char*> sections;
char* section = getIniSectionBuf;
char* section = ScriptExtender::gTextBuffer;
while (*section != 0) {
sections.push_back(section); // position
section += std::strlen(section) + 1;
@@ -1099,10 +1096,10 @@ void sf_get_ini_sections(OpcodeContext& ctx) {
void sf_get_ini_section(OpcodeContext& ctx) {
auto section = ctx.arg(1).strValue();
GetPrivateProfileSectionA(section, getIniSectionBuf, 5120, GetIniFilePath(ctx.arg(0)).data());
GetPrivateProfileSectionA(section, ScriptExtender::gTextBuffer, ScriptExtender::TextBufferSize(), GetIniFilePath(ctx.arg(0)).data());
int arrayId = TempArray(-1, 0); // associative
auto& arr = arrays[arrayId];
char *key = getIniSectionBuf, *val = nullptr;
char *key = ScriptExtender::gTextBuffer, *val = nullptr;
while (*key != 0) {
char* val = std::strpbrk(key, "=");
if (val != nullptr) {
+66 -23
View File
@@ -190,8 +190,6 @@ void sf_string_split(OpcodeContext& ctx) {
ctx.setReturn(StringSplit(ctx.arg(0).strValue(), ctx.arg(1).strValue()));
}
static char* tempTextBuf = nullptr;
char* Substring(const char* str, int startPos, int length) {
int len = strlen(str);
@@ -201,11 +199,8 @@ char* Substring(const char* str, int startPos, int length) {
}
if (length < 0) {
length += len - startPos; // cutoff at end
if (length == 0) {
return "";
} else if (length < 0) {
length = -length; // length can't be negative
}
if (length == 0) return "";
abs(length); // length can't be negative
}
// check position
if (startPos >= len) return ""; // start position is out of string length, return empty string
@@ -213,11 +208,12 @@ char* Substring(const char* str, int startPos, int length) {
length = len - startPos; // set the correct length, the length of characters goes beyond the end of the string
}
if (tempTextBuf) delete[] tempTextBuf;
tempTextBuf = new char[length + 1];
memcpy(tempTextBuf, &str[startPos], length);
tempTextBuf[length] = '\0';
return tempTextBuf;
const int bufMax = ScriptExtender::TextBufferSize() - 1;
if (length > bufMax) length = bufMax;
memcpy(ScriptExtender::gTextBuffer, &str[startPos], length);
ScriptExtender::gTextBuffer[length] = '\0';
return ScriptExtender::gTextBuffer;
}
void sf_substr(OpcodeContext& ctx) {
@@ -241,8 +237,7 @@ static char* _stdcall sprintf_lite(const char* format, ScriptValue value) {
int fmtlen = strlen(format);
int buflen = fmtlen + 1;
for (int i = 0; i < fmtlen; i++) {
if (format[i] == '%')
buflen++; // will possibly be escaped, need space for that
if (format[i] == '%') buflen++; // will possibly be escaped, need space for that
}
// parse format to make it safe
char* newfmt = new char[buflen];
@@ -290,7 +285,8 @@ static char* _stdcall sprintf_lite(const char* format, ScriptValue value) {
newfmt[j++] = c;
}
newfmt[j] = '\0';
// calculate required memory
// calculate required length
if (hasDigits) {
buflen = 254;
} else if (specifier == 'c') {
@@ -300,18 +296,18 @@ static char* _stdcall sprintf_lite(const char* format, ScriptValue value) {
} else {
buflen = j + 30; // numbers
}
if (tempTextBuf) {
delete[] tempTextBuf;
}
tempTextBuf = new char[buflen + 1];
const long bufMaxLen = ScriptExtender::TextBufferSize() - 1;
if (buflen > bufMaxLen - 1) buflen = bufMaxLen - 1;
ScriptExtender::gTextBuffer[bufMaxLen] = '\0';
if (value.isFloat()) {
_snprintf(tempTextBuf, buflen, newfmt, value.floatValue());
_snprintf(ScriptExtender::gTextBuffer, buflen, newfmt, value.floatValue());
} else {
_snprintf(tempTextBuf, buflen, newfmt, value.rawValue());
_snprintf(ScriptExtender::gTextBuffer, buflen, newfmt, value.rawValue());
}
tempTextBuf[buflen] = '\0'; // just in case
delete[] newfmt;
return tempTextBuf;
return ScriptExtender::gTextBuffer;
}
void sf_sprintf(OpcodeContext& ctx) {
@@ -320,6 +316,53 @@ void sf_sprintf(OpcodeContext& ctx) {
);
}
void sf_string_format(OpcodeContext& ctx) {
const char* format = ctx.arg(0).strValue();
int fmtLen = strlen(format);
if (fmtLen == 0) {
ctx.setReturn(format);
return;
}
if (fmtLen > 1024) {
ctx.printOpcodeError("%s() - the format string exceeds maximum length of 1024 characters.", ctx.getMetaruleName());
ctx.setReturn("Error");
} else {
char* newFmt = new char[fmtLen + 1];
newFmt[fmtLen] = '\0';
// parse format to make it safe
int i = 0;
do {
char c = format[i];
if (c == '%') {
char cf = format[i + 1];
if (cf != 's' && cf != 'd' && cf != '%') c = ' '; // unsupported format
}
newFmt[i] = c;
} while (++i < fmtLen);
const long bufMaxLen = ScriptExtender::TextBufferSize() - 1;
switch (ctx.numArgs()) {
case 2 :
_snprintf(ScriptExtender::gTextBuffer, bufMaxLen, newFmt, ctx.arg(1).rawValue());
break;
case 3 :
_snprintf(ScriptExtender::gTextBuffer, bufMaxLen, newFmt, ctx.arg(1).rawValue(), ctx.arg(2).rawValue());
break;
case 4 :
_snprintf(ScriptExtender::gTextBuffer, bufMaxLen, newFmt, ctx.arg(1).rawValue(), ctx.arg(2).rawValue(), ctx.arg(3).rawValue());
break;
case 5 :
_snprintf(ScriptExtender::gTextBuffer, bufMaxLen, newFmt, ctx.arg(1).rawValue(), ctx.arg(2).rawValue(), ctx.arg(3).rawValue(), ctx.arg(4).rawValue());
}
ScriptExtender::gTextBuffer[bufMaxLen] = '\0'; // just in case
delete[] newFmt;
ctx.setReturn(ScriptExtender::gTextBuffer);
}
}
void sf_power(OpcodeContext& ctx) {
const ScriptValue &base = ctx.arg(0),
&power = ctx.arg(1);
+2
View File
@@ -53,6 +53,8 @@ void sf_string_compare(OpcodeContext&);
void sf_sprintf(OpcodeContext&);
void sf_string_format(OpcodeContext&);
void sf_ord(OpcodeContext&);
void sf_typeof(OpcodeContext&);