diff options
author | brianluau <brianluau@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2011-12-09 02:46:31 +0000 |
---|---|---|
committer | brianluau <brianluau@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2011-12-09 02:46:31 +0000 |
commit | 7215da0cd6723ebe147757752843c295c5f9ab03 (patch) | |
tree | 8e8c7a333e7fe978138d6dba9f0132f73d68acf1 | |
parent | e3be4992275a0d15f3d1b9f39043d66b8faa10da (diff) | |
download | hercules-7215da0cd6723ebe147757752843c295c5f9ab03.tar.gz hercules-7215da0cd6723ebe147757752843c295c5f9ab03.tar.bz2 hercules-7215da0cd6723ebe147757752843c295c5f9ab03.tar.xz hercules-7215da0cd6723ebe147757752843c295c5f9ab03.zip |
- Added ToastOfDoom's String Commands Package. (tid:53411, topic:204976)
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@15039 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r-- | doc/script_commands.txt | 187 | ||||
-rw-r--r-- | src/map/script.c | 802 |
2 files changed, 989 insertions, 0 deletions
diff --git a/doc/script_commands.txt b/doc/script_commands.txt index f5d9a9cee..a10002f0e 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -6591,6 +6591,193 @@ The first letter is position 0. --------------------------------------- +*charat(<string>,<index>) + + Returns char at specified index. If index is out of range, + returns empty string. + + Example: + + charat("This is a string", 10); //returns "s" + +--------------------------------------- + +*setchar(<string>,<char>,<index>) + + Returns the original string with the char at the specified + index set to the specified char. If index out of range, the + original string will be returned. + Only the 1st char in the <char> parameter will be used. + + Example: + + setchar("Cat", "B", 0); //returns "Bat" + +--------------------------------------- + +*insertchar(<string>,<char>,<index>) + + Returns the original string with the specified char inserted + at the specified index. If index is out of range, the char + will be inserted on the end of the string that it is closest. + Only the 1st char in the <char> parameter will be used. + + Example: + + setchar("laughter", "s", 0); //returns "slaughter" + +--------------------------------------- + +*delchar(<string>,<index>) + + Returns the original string with the char at the specified index + removed. If index is out of range, original string will be returned. + + Example: + + delchar("Diet", 3); //returns "Die" + +--------------------------------------- + +*strtoupper(<string>) +*strtolower(<string>) + + Returns the specified string in it's uppercase/lowercase form. + All non-alpha characters will be preserved + + Example: + + strtoupper("The duck is blue!!"); //returns "THE DUCK IS BLUE!!" + +--------------------------------------- + +*charisupper(<string>,<index>) +*charislower(<string>,<index>) + + Returns 1 if character at specified index of specified string is + uppercase/lowercase. Otherwise, 0. Characters not of the alphabelt + will return 0. + + Example: + + charisupper("eAthena", 1); //returns 1 + +--------------------------------------- + +*substr(<string>,<start_index>,<end_index>) + + Returns the sub-string of the specified string inclusively between + the set indexes. + If indexes are out of range, or the start index is after the end + index, an empty string will be returned. + + Example: + + substr("foobar", 3, 5); //returns "bar" + +--------------------------------------- + +*explode(<dest_array>,<string>,<delimiter>) + + Breaks a string up into substrings based on the specified delimiter. + Substrings will be stored within the specified string array. + Only the 1st char of the delimiter parameter will be used. + If an empty string is passed as a delimiter, the string will be placed + in the array in it's original form. + + Example: + + explode(.@my_array$, "Explode:Test:1965:red:PIE", ":"); + //.@my_array$ contents will be... + //.@my_array$[0]: "Explode" + //.@my_array$[1]: "Test" + //.@my_array$[2]: "1965" + //.@my_array$[3]: "red" + //.@my_array$[4]: "PIE" + + +--------------------------------------- + +*implode(<string_array>{,<glue>}) + + Combines all substrings within the specified string array into a single string. + If the glue parameter is specified, it will be inserted inbetween each substring. + + Example: + setarray .@my_array$[0], "This", "is", "a", "test"; + implode(.@my_array$, " "); //returns "This is a test" + +--------------------------------------- + +*sprintf(<format>[,param[,param[,...]]]) [Mirei] + + C style sprintf. The resulting string is returned same as in PHP. All C format + specifiers are supported except %n. More info: sprintf @ www.cplusplus.com. + The number of params is only limited by eA's script engine. + + See thread: http://www.eathena.ws/board/index.php?showtopic=190410 + + Example: + .@format$ = 'The %s contains %d monkeys'; + dispbottom(sprintf(.@format$, "zoo", 5)); //prints "The zoo contains 5 monkeys" + dispbottom(sprintf(.@format$, "barrel", 82)); //prints "The barrel contains 82 monkeys" + +--------------------------------------- + +*sscanf(<string>,<format>[,param[,param[,...]]]) [Mirei] + + C style sscanf. All C format specifiers are supported. + More info: sscanf @ www.cplusplus.com. The number of params is only limited + by eA's script engine. + + See thread: http://www.eathena.ws/board/index.php?showtopic=191157 + + Example: + sscanf("This is a test: 42 foobar", "This is a test: %d %s", .@num, .@str$); + dispbottom(.@num + " " + .@str$); //prints "42 foobar" + +--------------------------------------- + +*strpos(<haystack>,<needle>{,<offset>}) + + PHP style strpos. Finds a substring (needle) within a string (haystack). + The offset parameter indicates the index of the string to start searching. + Returns index of substring on successful search, else -1. + Comparison is case sensitive. + + Example: + strpos("foobar", "bar", 0); //returns 3 + strpos("foobarfoo", "foo", 0); //returns 0 + strpos("foobarfoo", "foo", 1); //returns 6 + +--------------------------------------- + +*replacestr(<input>, <search>, <replace>{, <usecase>{, <count>}}) + + Replaces all instances of a search string in the input with the specified + replacement string. By default is case sensitive unless <usecase> is set + to 0. If specified it will only replace as many instances as specified + in the count parameter. + + Example: + replacestr("testing tester", "test", "dash"); //returns "dashing dasher" + replacestr("Donkey", "don", "mon", 0); //returns "monkey" + replacestr("test test test test test", "yay", 0, 3); //returns "yay yay yay test test" + +--------------------------------------- + +*countstr(<input>, <search>{, <usecase>}) + + Counts all instances of a search string in the input. By default is case + sensitive unless <usecase> is set to 0. + + Example: + countstr("test test test Test", "test"); //returns 3 + countstr("cake Cake", "Cake", 0); //returns 2 + + +--------------------------------------- + *setfont <font> This command sets the current RO client interface font to one of the diff --git a/src/map/script.c b/src/map/script.c index 755ce8bf9..fb500e40e 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -12579,6 +12579,792 @@ BUILDIN_FUNC(charisalpha) return 0; } +//======================================================= +// charisupper <str>, <index> +//------------------------------------------------------- +BUILDIN_FUNC(charisupper) +{ + const char *str = script_getstr(st,2); + int pos = script_getnum(st,3); + + int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISUPPER( str[pos] ) : 0; + + script_pushint(st,val); + return 0; +} + +//======================================================= +// charislower <str>, <index> +//------------------------------------------------------- +BUILDIN_FUNC(charislower) +{ + const char *str = script_getstr(st,2); + int pos = script_getnum(st,3); + + int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISLOWER( str[pos] ) : 0; + + script_pushint(st,val); + return 0; +} + +//======================================================= +// charat <str>, <index> +//------------------------------------------------------- +BUILDIN_FUNC(charat) +{ + const char *str = script_getstr(st,2); + int pos = script_getnum(st,3); + char *output; + + output = (char*)aMallocA(2*sizeof(char)); + output[0] = '\0'; + + if(str && pos >= 0 && (unsigned int)pos < strlen(str)) + sprintf(output, "%c", str[pos]); + + script_pushstr(st, output); + return 0; +} + +//======================================================= +// setchar <string>, <char>, <index> +//------------------------------------------------------- +BUILDIN_FUNC(setchar) +{ + const char *str = script_getstr(st,2); + const char *c = script_getstr(st,3); + int index = script_getnum(st,4); + char *output; + size_t len = strlen(str); + + output = (char*)aMallocA(len + 1); + memcpy(output, str, len); + output[len] = '\0'; + + if(index >= 0 && index < len) + output[index] = c[0]; + + script_pushstr(st, output); + return 0; +} + +//======================================================= +// insertchar <string>, <char>, <index> +//------------------------------------------------------- +BUILDIN_FUNC(insertchar) +{ + const char *str = script_getstr(st,2); + const char *c = script_getstr(st,3); + int index = script_getnum(st,4); + char *output; + size_t len = strlen(str); + + if(index < 0) + index = 0; + else if(index > len) + index = len; + + output = (char*)aMallocA(len + 2); + + memcpy(output, str, index); + output[index] = c[0]; + memcpy(&output[index+1], &str[index], len - index); + output[len+1] = '\0'; + + script_pushstr(st, output); + return 0; +} + +//======================================================= +// delchar <string>, <index> +//------------------------------------------------------- +BUILDIN_FUNC(delchar) +{ + const char *str = script_getstr(st,2); + int index = script_getnum(st,3); + char *output; + size_t len = strlen(str); + + if(index < 0 || index > len) { + //return original + ++len; + output = (char*)aMallocA(len); + memcpy(output, str, len); + script_pushstr(st, output); + return 0; + } + + output = (char*)aMallocA(len); + + memcpy(output, str, index); + memcpy(&output[index], &str[index+1], len - index); + + script_pushstr(st, output); + return 0; +} + +//======================================================= +// strtoupper <str> +//------------------------------------------------------- +BUILDIN_FUNC(strtoupper) +{ + const char *str = script_getstr(st,2); + char *output; + int i = 0; + + output = (char*)aMallocA(strlen(str) + 1); + + while(str[i] != '\0') + output[i++] = TOUPPER(str[i]); + output[i] = '\0'; + + script_pushstr(st, output); + return 0; +} + +//======================================================= +// strtolower <str> +//------------------------------------------------------- +BUILDIN_FUNC(strtolower) +{ + const char *str = script_getstr(st,2); + char *output; + int i = 0; + + output = (char*)aMallocA(strlen(str) + 1); + + while(str[i] != '\0') + output[i++] = TOLOWER(str[i]); + output[i] = '\0'; + + script_pushstr(st, output); + return 0; +} + +//======================================================= +// substr <str>, <start>, <end> +//------------------------------------------------------- +BUILDIN_FUNC(substr) +{ + const char *str = script_getstr(st,2); + char *output; + int start = script_getnum(st,3); + int end = script_getnum(st,4); + + int len = 0; + + if(start >= 0 && end < strlen(str) && start <= end) { + len = end - start + 1; + output = (char*)aMallocA(len + 1); + memcpy(output, &str[start], len); + } else + output = (char*)aMallocA(1); + + output[len] = '\0'; + + script_pushstr(st, output); + return 0; +} + +//======================================================= +// explode <dest_string_array>, <str>, <delimiter> +// Note: delimiter is limited to 1 char +//------------------------------------------------------- +BUILDIN_FUNC(explode) +{ + struct script_data* data = script_getdata(st, 2); + const char *str = script_getstr(st,3); + const char delimiter = script_getstr(st, 4)[0]; + int32 id; + size_t len = strlen(str); + int i = 0, j = 0, k = 0; + int start; + + + char *temp; + const char* name; + + TBL_PC* sd = NULL; + + temp = (char*)aMallocA(len + 1); + + if( !data_isreference(data) ) + { + ShowError("script:explode: not a variable\n"); + script_reportdata(data); + st->state = END; + return 1;// not a variable + } + + id = reference_getid(data); + start = reference_getindex(data); + name = reference_getname(data); + + if( not_array_variable(*name) ) + { + ShowError("script:explode: illegal scope\n"); + script_reportdata(data); + st->state = END; + return 1;// not supported + } + + if( !is_string_variable(name) ) + { + ShowError("script:explode: not string array\n"); + script_reportdata(data); + st->state = END; + return 1;// data type mismatch + } + + if( not_server_variable(*name) ) + { + sd = script_rid2sd(st); + if( sd == NULL ) + return 0;// no player attached + } + + while(str[i] != '\0') { + if(str[i] == delimiter && start < 127) { //break at delimiter but ignore after reaching last array index + temp[j] = '\0'; + set_reg(st, sd, reference_uid(id, start++), name, (void*)temp, reference_getref(data)); + j = 0; + ++i; + } else { + temp[j++] = str[i++]; + } + } + //set last string + temp[j] = '\0'; + set_reg(st, sd, reference_uid(id, start), name, (void*)temp, reference_getref(data)); + + aFree(temp); + return 0; +} + +//======================================================= +// implode <string_array> +// implode <string_array>, <glue> +//------------------------------------------------------- +BUILDIN_FUNC(implode) +{ + struct script_data* data = script_getdata(st, 2); + const char *glue, *name, *temp; + int32 glue_len = 0, array_size, id; + size_t len = 0; + int i, k = 0; + + TBL_PC* sd = NULL; + + char *output; + + if( !data_isreference(data) ) + { + ShowError("script:implode: not a variable\n"); + script_reportdata(data); + st->state = END; + return 1;// not a variable + } + + id = reference_getid(data); + name = reference_getname(data); + + if( not_array_variable(*name) ) + { + ShowError("script:implode: illegal scope\n"); + script_reportdata(data); + st->state = END; + return 1;// not supported + } + + if( !is_string_variable(name) ) + { + ShowError("script:implode: not string array\n"); + script_reportdata(data); + st->state = END; + return 1;// data type mismatch + } + + if( not_server_variable(*name) ) + { + sd = script_rid2sd(st); + if( sd == NULL ) + return 0;// no player attached + } + + //count chars + array_size = getarraysize(st, id, reference_getindex(data), is_string_variable(name), reference_getref(data)) - 1; + + if(array_size == -1) //empty array check (AmsTaff) + { + ShowWarning("script:implode: array length = 0\n"); + output = (char*)aMallocA(sizeof(char)*5); + sprintf(output,"%s","NULL"); + } else { + for(i = 0; i <= array_size; ++i) { + temp = (char*) get_val2(st, reference_uid(id, i), reference_getref(data)); + len += strlen(temp); + script_removetop(st, -1, 0); + } + + //allocate mem + if( script_hasdata(st,3) ) { + glue = script_getstr(st,3); + glue_len = strlen(glue); + len += glue_len * (array_size); + } + output = (char*)aMallocA(len + 1); + + //build output + for(i = 0; i < array_size; ++i) { + temp = (char*) get_val2(st, reference_uid(id, i), reference_getref(data)); + len = strlen(temp); + memcpy(&output[k], temp, len); + k += len; + if(glue_len != 0) { + memcpy(&output[k], glue, glue_len); + k += glue_len; + } + script_removetop(st, -1, 0); + } + temp = (char*) get_val2(st, reference_uid(id, array_size), reference_getref(data)); + len = strlen(temp); + memcpy(&output[k], temp, len); + k += len; + script_removetop(st, -1, 0); + + output[k] = '\0'; + } + + script_pushstr(st, output); + return 0; +} + +//======================================================= +// sprintf(<format>, ...); +// Implements C sprintf, except format %n. The resulting string is +// returned, instead of being saved in variable by reference. +//------------------------------------------------------- +BUILDIN_FUNC(sprintf) +{ + unsigned int len, argc = 0, arg = 0, buf2_len = 0; + const char* format; + char* p; + char* q; + char* buf = NULL; + char* buf2 = NULL; + struct script_data* data; + StringBuf final_buf; + + // Fetch init data + format = script_getstr(st, 2); + argc = script_lastdata(st)-2; + len = strlen(format); + + // Skip parsing, where no parsing is required. + if(len==0){ + script_pushconststr(st,""); + return 0; + } + + // Pessimistic alloc + CREATE(buf, char, len+1); + + // Need not be parsed, just solve stuff like %%. + if(argc==0){ + sprintf(buf, format); + script_pushstrcopy(st, buf); + aFree(buf); + return 0; + } + + safestrncpy(buf, format, len+1); + + // Issue sprintf for each parameter + StringBuf_Init(&final_buf); + q = buf; + while((p = strchr(q, '%'))!=NULL){ + if(p!=q){ + len = p-q+1; + if(buf2_len<len){ + RECREATE(buf2, char, len); + buf2_len = len; + } + safestrncpy(buf2, q, len); + StringBuf_AppendStr(&final_buf, buf2); + q = p; + } + p = q+1; + if(*p=='%'){ // %% + StringBuf_AppendStr(&final_buf, "%"); + q+=2; + continue; + } + if(*p=='n'){ // %n + ShowWarning("buildin_sprintf: Format %%n not supported! Skipping...\n"); + script_reportsrc(st); + q+=2; + continue; + } + if(arg>=argc){ + ShowError("buildin_sprintf: Not enough arguments passed!\n"); + if(buf) aFree(buf); + if(buf2) aFree(buf2); + StringBuf_Destroy(&final_buf); + script_pushconststr(st,""); + return 1; + } + if((p = strchr(q+1, '%'))==NULL){ + p = strchr(q, 0); // EOS + } + len = p-q+1; + if(buf2_len<len){ + RECREATE(buf2, char, len); + buf2_len = len; + } + safestrncpy(buf2, q, len); + q = p; + + // Note: This assumes the passed value being the correct + // type to the current format specifier. If not, the server + // probably crashes or returns anything else, than expected, + // but it would behave in normal code the same way so it's + // the scripter's responsibility. + data = script_getdata(st, arg+3); + if(data_isstring(data)){ // String + StringBuf_Printf(&final_buf, buf2, script_getstr(st, arg+3)); + }else if(data_isint(data)){ // Number + StringBuf_Printf(&final_buf, buf2, script_getnum(st, arg+3)); + }else if(data_isreference(data)){ // Variable + char* name = reference_getname(data); + if(name[strlen(name)-1]=='$'){ // var Str + StringBuf_Printf(&final_buf, buf2, script_getstr(st, arg+3)); + }else{ // var Int + StringBuf_Printf(&final_buf, buf2, script_getnum(st, arg+3)); + } + }else{ // Unsupported type + ShowError("buildin_sprintf: Unknown argument type!\n"); + if(buf) aFree(buf); + if(buf2) aFree(buf2); + StringBuf_Destroy(&final_buf); + script_pushconststr(st,""); + return 1; + } + arg++; + } + + // Append anything left + if(*q){ + StringBuf_AppendStr(&final_buf, q); + } + + // Passed more, than needed + if(arg<argc){ + ShowWarning("buildin_sprintf: Unused arguments passed.\n"); + script_reportsrc(st); + } + + script_pushstrcopy(st, StringBuf_Value(&final_buf)); + + if(buf) aFree(buf); + if(buf2) aFree(buf2); + StringBuf_Destroy(&final_buf); + + return 0; +} + +//======================================================= +// sscanf(<str>, <format>, ...); +// Implements C sscanf. +//------------------------------------------------------- +BUILDIN_FUNC(sscanf){ + unsigned int argc, arg = 0, len; + struct script_data* data; + struct map_session_data* sd = NULL; + const char* str; + const char* format; + const char* p; + const char* q; + char* buf = NULL; + char* buf_p; + char* ref_str = NULL; + int ref_int; + + // Get data + str = script_getstr(st, 2); + format = script_getstr(st, 3); + argc = script_lastdata(st)-3; + + len = strlen(format); + CREATE(buf, char, len*2+1); + + // Issue sscanf for each parameter + *buf = 0; + q = format; + while(p = strchr(q, '%')){ + if(p!=q){ + strncat(buf, q, (size_t)(p-q)); + q = p; + } + p = q+1; + if(*p=='*' || *p=='%'){ // Skip + strncat(buf, q, 2); + q+=2; + continue; + } + if(arg>=argc){ + ShowError("buildin_sscanf: Not enough arguments passed!\n"); + script_pushint(st, -1); + if(buf) aFree(buf); + if(ref_str) aFree(ref_str); + return 1; + } + if((p = strchr(q+1, '%'))==NULL){ + p = strchr(q, 0); // EOS + } + len = p-q; + strncat(buf, q, len); + q = p; + + // Validate output + data = script_getdata(st, arg+4); + if(!data_isreference(data) || !reference_tovariable(data)){ + ShowError("buildin_sscanf: Target argument is not a variable!\n"); + script_pushint(st, -1); + if(buf) aFree(buf); + if(ref_str) aFree(ref_str); + return 1; + } + buf_p = reference_getname(data); + if(not_server_variable(*buf_p) && (sd = script_rid2sd(st))==NULL){ + script_pushint(st, -1); + if(buf) aFree(buf); + if(ref_str) aFree(ref_str); + return 0; + } + + // Save value if any + if(buf_p[strlen(buf_p)-1]=='$'){ // String + if(ref_str==NULL){ + CREATE(ref_str, char, strlen(str)+1); + } + if(sscanf(str, buf, ref_str)==0){ + break; + } + set_reg(st, sd, add_str(buf_p), buf_p, (void *)(ref_str), reference_getref(data)); + }else{ // Number + if(sscanf(str, buf, &ref_int)==0){ + break; + } + set_reg(st, sd, add_str(buf_p), buf_p, (void *)(ref_int), reference_getref(data)); + } + arg++; + + // Disable used format (%... -> %*...) + buf_p = strchr(buf, 0); + memmove(buf_p-len+2, buf_p-len+1, len); + *(buf_p-len+1) = '*'; + } + + // Passed more, than needed + if(arg<argc){ + ShowWarning("buildin_sscanf: Unused arguments passed.\n"); + script_reportsrc(st); + } + + script_pushint(st, arg); + if(buf) aFree(buf); + if(ref_str) aFree(ref_str); + + return 0; +} + +//======================================================= +// strpos(<haystack>, <needle>) +// strpos(<haystack>, <needle>, <offset>) +// +// Implements PHP style strpos. Adapted from code from +// http://www.daniweb.com/code/snippet313.html, Dave Sinkula +//------------------------------------------------------- +BUILDIN_FUNC(strpos) { + const char *haystack = script_getstr(st,2); + const char *needle = script_getstr(st,3); + int i; + size_t len; + + if( script_hasdata(st,4) ) + i = script_getnum(st,4); + else + i = 0; + + if ( strlen(needle) == 0 ) { + script_pushint(st, -1); + return 0; + } + + len = strlen(haystack); + for ( ; i < len; ++i ) { + if ( haystack[i] == *needle ) { + // matched starting char -- loop through remaining chars + const char *h, *n; + for ( h = &haystack[i], n = needle; *h && *n; ++h, ++n ) { + if ( *h != *n ) { + break; + } + } + if ( !*n ) { // matched all of 'needle' to null termination + script_pushint(st, i); + return 0; + } + } + } + script_pushint(st, -1); + return 0; +} + +//=============================================================== +// replacestr <input>, <search>, <replace>{, <usecase>{, <count>}} +// +// Note: Finds all instances of <search> in <input> and replaces +// with <replace>. If specified will only replace as many +// instances as specified in <count>. By default will be case +// sensitive. +//--------------------------------------------------------------- +BUILDIN_FUNC(replacestr) +{ + const char *input = script_getstr(st, 2); + const char *find = script_getstr(st, 3); + const char *replace = script_getstr(st, 4); + size_t inputlen = strlen(input); + size_t findlen = strlen(find); + struct StringBuf output; + bool usecase = true; + + int count = 0; + int numFinds = 0; + int i = 0, f = 0; + + if(findlen == 0) { + ShowError("script:replacestr: Invalid search length.\n"); + st->state = END; + return 1; + } + + if(script_hasdata(st, 5)) { + if(script_isint(st,5)) + usecase = script_getnum(st, 5) != 0; + else { + ShowError("script:replacestr: Invalid usecase value. Expected int got string\n"); + st->state = END; + return 1; + } + } + + if(script_hasdata(st, 6)) { + if(script_isint(st,6)) + count = script_getnum(st, 6); + else { + ShowError("script:replacestr: Invalid count value. Expected int got string\n"); + st->state = END; + return 1; + } + } + + StringBuf_Init(&output); + + for(; i < inputlen; i++) { + if(count && count == numFinds) { //found enough, stop looking + break; + } + + for(f = 0; f <= findlen; f++) { + if(f == findlen) { //complete match + numFinds++; + StringBuf_AppendStr(&output, replace); + + i += findlen - 1; + break; + } else { + if(usecase) { + if((i + f) > inputlen || input[i + f] != find[f]) { + StringBuf_Printf(&output, "%c", input[i]); + break; + } + } else { + if((i + f) > inputlen || input[i + f] != find[f] && TOUPPER(input[i+f]) != TOUPPER(find[f])) { + StringBuf_Printf(&output, "%c", input[i]); + break; + } + } + } + } + } + + //append excess after enough found + if(i < inputlen) + StringBuf_AppendStr(&output, &(input[i])); + + script_pushstrcopy(st, StringBuf_Value(&output)); + StringBuf_Destroy(&output); + return 0; +} + +//======================================================== +// countstr <input>, <search>{, <usecase>} +// +// Note: Counts the number of times <search> occurs in +// <input>. By default will be case sensitive. +//-------------------------------------------------------- +BUILDIN_FUNC(countstr) +{ + const char *input = script_getstr(st, 2); + const char *find = script_getstr(st, 3); + size_t inputlen = strlen(input); + size_t findlen = strlen(find); + bool usecase = true; + + int numFinds = 0; + int i = 0, f = 0; + + if(findlen == 0) { + ShowError("script:countstr: Invalid search length.\n"); + st->state = END; + return 1; + } + + if(script_hasdata(st, 4)) { + if(script_isint(st,4)) + usecase = script_getnum(st, 4) != 0; + else { + ShowError("script:countstr: Invalid usecase value. Expected int got string\n"); + st->state = END; + return 1; + } + } + + for(; i < inputlen; i++) { + for(f = 0; f <= findlen; f++) { + if(f == findlen) { //complete match + numFinds++; + i += findlen - 1; + break; + } else { + if(usecase) { + if((i + f) > inputlen || input[i + f] != find[f]) { + break; + } + } else { + if((i + f) > inputlen || input[i + f] != find[f] && TOUPPER(input[i+f]) != TOUPPER(find[f])) { + break; + } + } + } + } + } + script_pushint(st, numFinds); + return 0; +} + + /// Changes the display name and/or display class of the npc. /// Returns 0 is successful, 1 if the npc does not exist. /// @@ -15395,6 +16181,22 @@ struct script_function buildin_func[] = { BUILDIN_DEF(unequip,"i"), // unequip command [Spectre] BUILDIN_DEF(getstrlen,"s"), //strlen [Valaris] BUILDIN_DEF(charisalpha,"si"), //isalpha [Valaris] + BUILDIN_DEF(charat,"si"), + BUILDIN_DEF(setchar,"ssi"), + BUILDIN_DEF(insertchar,"ssi"), + BUILDIN_DEF(delchar,"si"), + BUILDIN_DEF(strtoupper,"s"), + BUILDIN_DEF(strtolower,"s"), + BUILDIN_DEF(charisupper, "si"), + BUILDIN_DEF(charislower, "si"), + BUILDIN_DEF(substr,"sii"), + BUILDIN_DEF(explode, "rss"), + BUILDIN_DEF(implode, "r?"), + BUILDIN_DEF(sprintf,"s*"), // [Mirei] + BUILDIN_DEF(sscanf,"ss*"), // [Mirei] + BUILDIN_DEF(strpos,"ss?"), + BUILDIN_DEF(replacestr,"sss??"), + BUILDIN_DEF(countstr,"ss?"), BUILDIN_DEF(setnpcdisplay,"sv??"), BUILDIN_DEF(compare,"ss"), // Lordalfa - To bring strstr to scripting Engine. BUILDIN_DEF(getiteminfo,"ii"), //[Lupus] returns Items Buy / sell Price, etc info |