diff --git a/core/TextParsers.cpp b/core/TextParsers.cpp index d16fee3e..409ef49c 100644 --- a/core/TextParsers.cpp +++ b/core/TextParsers.cpp @@ -25,6 +25,11 @@ TextParsers g_TextParser; static int g_ini_chartable1[255] = {0}; static int g_ws_chartable[255] = {0}; +bool IsWhitespace(const char *stream) +{ + return g_ws_chartable[(unsigned)*stream] == 1; +} + TextParsers::TextParsers() { g_ini_chartable1[(unsigned)'_'] = 1; diff --git a/core/TextParsers.h b/core/TextParsers.h index a4078923..300fa64a 100644 --- a/core/TextParsers.h +++ b/core/TextParsers.h @@ -37,6 +37,8 @@ inline unsigned int _GetUTF8CharBytes(const char *stream) return 1; } +bool IsWhitespace(const char *stream); + /** * @param void * IN: Stream pointer * @param char * IN/OUT: Stream buffer diff --git a/core/smn_string.cpp b/core/smn_string.cpp index e864cb99..9be0c748 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -15,6 +15,7 @@ #include #include "sm_globals.h" #include "sm_stringutil.h" +#include "TextParsers.h" inline const char *_strstr(const char *str, const char *substr) { @@ -219,9 +220,99 @@ static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params) return total; } -REGISTER_NATIVES(basicstrings) +/* :TODO: make this UTF8 safe */ +static cell_t StrBreak(IPluginContext *pContext, const cell_t *params) +{ + const char *input; + char *out; + size_t outMax; + + /* Get parameters */ + pContext->LocalToString(params[1], (char **)&input); + pContext->LocalToString(params[2], &out); + outMax = params[3]; + + const char *inptr = input; + /* Eat up whitespace */ + while (*inptr != '\0' && IsWhitespace(inptr)) + { + inptr++; + } + + if (*inptr == '\0') + { + if (outMax) + { + *out = '\0'; + } + return -1; + } + + const char *start, *end = NULL; + + bool quoted = (*inptr == '"'); + if (quoted) + { + inptr++; + start = inptr; + /* Read input until we reach a quote. */ + while (*inptr != '\0' && *inptr != '"') + { + /* Update the end point, increment the stream. */ + end = inptr++; + } + /* Read one more token if we reached an end quote */ + if (*inptr == '"') + { + inptr++; + } + } else { + start = inptr; + /* Read input until we reach a space */ + while (*inptr != '\0' && !IsWhitespace(inptr)) + { + /* Update the end point, increment the stream. */ + end = inptr++; + } + } + + /* Copy the string we found, if necessary */ + if (end == NULL) + { + if (outMax) + { + *out = '\0'; + } + } else if (outMax) { + char *outptr = out; + outMax--; + for (const char *ptr=start; + (ptr <= end) && ((unsigned)(outptr - out) < (outMax)); + ptr++, outptr++) + { + *outptr = *ptr; + } + *outptr = '\0'; + } + + /* Consume more of the string until we reach non-whitespace */ + while (*inptr != '\0' && IsWhitespace(inptr)) + { + inptr++; + } + + if (*inptr == '\0') + { + return -1; + } + + return inptr - input; +} + +REGISTER_NATIVES(basicStrings) { {"strlen", sm_strlen}, + {"StrBreak", StrBreak}, {"StrContains", sm_contain}, {"StrCompare", sm_strcmp}, {"StrCopy", sm_strcopy}, diff --git a/plugins/include/string.inc b/plugins/include/string.inc index 9dee3579..fbd3b499 100644 --- a/plugins/include/string.inc +++ b/plugins/include/string.inc @@ -23,7 +23,7 @@ * and maximum length should have the null terminator INCLUDED in the length. This means * that this is valid: StrCopy(string, sizeof(string), ...) */ - + /** * Calculates the length of a string. * @@ -159,3 +159,17 @@ native Float:StringToFloat(const String:str[]); * @return Number of cells written to buffer. */ native FloatToString(Float:num, String:str[], maxlength); + +/** + * Finds the first "argument" in a string; either a set of space + * terminated characters, or a fully quoted string. After the + * argument is found, whitespace is read until the next portion + * of the string is reached. If nothing remains, -1 is returned. + * Otherwise, the index to the first character is returned. + * + * @param source Source input string. + * @param arg Stores argument read from string. + * @param argLen Maximum length of argument buffer. + * @return Index to next piece of string, or -1 if none. + */ +native StrBreak(const String:source[], String:arg[], argLen); \ No newline at end of file