X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=common.c;h=e0154eec0f759a7c6974aa883e64667c0f05fb6a;hb=e93385631fb31028b8879b4e77b21d5ad95969c8;hp=872a70f23425af5790ace3819f130d05c9f95661;hpb=42f72a6c46f7c459016799ec832debd4c7646503;p=xonotic%2Fdarkplaces.git diff --git a/common.c b/common.c index 872a70f2..e0154eec 100644 --- a/common.c +++ b/common.c @@ -665,12 +665,12 @@ void SZ_HexDumpToConsole(const sizebuf_t *buf) /* ============== -COM_ParseToken +COM_ParseToken_Simple Parse a token out of a string ============== */ -int COM_ParseToken(const char **datapointer, int returnnewline) +int COM_ParseToken_Simple(const char **datapointer, int returnnewline) { int len; int c; @@ -718,94 +718,159 @@ skipwhite: data++; while (*data && (data[0] != '*' || data[1] != '/')) data++; - data += 2; + if (*data) + data++; + if (*data) + data++; goto skipwhite; } else if (*data == '\"') { // quoted string - for (data++;*data != '\"';data++) + for (data++;*data && *data != '\"';data++) { - if (!*data || len >= (int)sizeof(com_token) - 1) - { - com_token[0] = 0; - *datapointer = NULL; - return false; - } c = *data; if (*data == '\\') { - if (data[1] == '"') - { - data++; - c = *data; - } - else if (data[1] == '\'') - { - data++; - c = *data; - } - else if (data[1] == 'n') - { - data++; + data++; + c = *data; + if (c == 'n') c = '\n'; - } - else if (data[1] == '\\') - data++; + else if (c == 't') + c = '\t'; } - com_token[len++] = c; + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = c; } com_token[len] = 0; - *datapointer = data+1; + if (*data == '\"') + data++; + *datapointer = data; + return true; + } + else if (*data == '\r') + { + // translate Mac line ending to UNIX + com_token[len++] = '\n';data++; + com_token[len] = 0; + *datapointer = data; + return true; + } + else if (*data == '\n') + { + // single character + com_token[len++] = *data++; + com_token[len] = 0; + *datapointer = data; + return true; + } + else + { + // regular word + for (;*data > ' ';data++) + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = *data; + com_token[len] = 0; + *datapointer = data; return true; } - else if (*data == '\'') +} + +/* +============== +COM_ParseToken_QuakeC + +Parse a token out of a string +============== +*/ +int COM_ParseToken_QuakeC(const char **datapointer, int returnnewline) +{ + int len; + int c; + const char *data = *datapointer; + + len = 0; + com_token[0] = 0; + + if (!data) + { + *datapointer = NULL; + return false; + } + +// skip whitespace +skipwhite: + // line endings: + // UNIX: \n + // Mac: \r + // Windows: \r\n + for (;*data <= ' ' && ((*data != '\n' && *data != '\r') || !returnnewline);data++) + { + if (*data == 0) + { + // end of file + *datapointer = NULL; + return false; + } + } + + // handle Windows line ending + if (data[0] == '\r' && data[1] == '\n') + data++; + + if (data[0] == '/' && data[1] == '/') + { + // comment + while (*data && *data != '\n' && *data != '\r') + data++; + goto skipwhite; + } + else if (data[0] == '/' && data[1] == '*') + { + // comment + data++; + while (*data && (data[0] != '*' || data[1] != '/')) + data++; + if (*data) + data++; + if (*data) + data++; + goto skipwhite; + } + else if (*data == '\"' || *data == '\'') { // quoted string - for (data++;*data != '\'';data++) + char quote = *data; + for (data++;*data && *data != quote;data++) { - if (!*data || len >= (int)sizeof(com_token) - 1) - { - com_token[0] = 0; - *datapointer = NULL; - return false; - } c = *data; if (*data == '\\') { - if (data[1] == '"') - { - data++; - c = *data; - } - else if (data[1] == '\'') - { - data++; - c = *data; - } - else if (data[1] == 'n') - { - data++; + data++; + c = *data; + if (c == 'n') c = '\n'; - } - else if (data[1] == '\\') - data++; + else if (c == 't') + c = '\t'; } - com_token[len++] = c; + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = c; } com_token[len] = 0; - *datapointer = data+1; + if (*data == quote) + data++; + *datapointer = data; return true; } else if (*data == '\r') { // translate Mac line ending to UNIX - com_token[len++] = '\n'; + com_token[len++] = '\n';data++; com_token[len] = 0; *datapointer = data; return true; } - else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';') + else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';') { // single character com_token[len++] = *data++; @@ -816,38 +881,124 @@ skipwhite: else { // regular word - for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';' && *data != '\'' && *data != '"';data++) + for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++) + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = *data; + com_token[len] = 0; + *datapointer = data; + return true; + } +} + +/* +============== +COM_ParseToken_VM_Tokenize + +Parse a token out of a string +============== +*/ +int COM_ParseToken_VM_Tokenize(const char **datapointer, int returnnewline) +{ + int len; + int c; + const char *data = *datapointer; + + len = 0; + com_token[0] = 0; + + if (!data) + { + *datapointer = NULL; + return false; + } + +// skip whitespace +skipwhite: + // line endings: + // UNIX: \n + // Mac: \r + // Windows: \r\n + for (;*data <= ' ' && ((*data != '\n' && *data != '\r') || !returnnewline);data++) + { + if (*data == 0) + { + // end of file + *datapointer = NULL; + return false; + } + } + + // handle Windows line ending + if (data[0] == '\r' && data[1] == '\n') + data++; + + if (data[0] == '/' && data[1] == '/') + { + // comment + while (*data && *data != '\n' && *data != '\r') + data++; + goto skipwhite; + } + else if (data[0] == '/' && data[1] == '*') + { + // comment + data++; + while (*data && (data[0] != '*' || data[1] != '/')) + data++; + if (*data) + data++; + if (*data) + data++; + goto skipwhite; + } + else if (*data == '\"' || *data == '\'') + { + char quote = *data; + // quoted string + for (data++;*data && *data != quote;data++) { - if (len >= (int)sizeof(com_token) - 1) - { - com_token[0] = 0; - *datapointer = NULL; - return false; - } c = *data; if (*data == '\\') { - if (data[1] == '"') - { - data++; - c = *data; - } - else if (data[1] == '\'') - { - data++; - c = *data; - } - else if (data[1] == 'n') - { - data++; + data++; + c = *data; + if (c == 'n') c = '\n'; - } - else if (data[1] == '\\') - data++; + else if (c == 't') + c = '\t'; } - com_token[len++] = c; + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = c; } com_token[len] = 0; + if (*data == quote) + data++; + *datapointer = data; + return true; + } + else if (*data == '\r') + { + // translate Mac line ending to UNIX + com_token[len++] = '\n';data++; + com_token[len] = 0; + *datapointer = data; + return true; + } + else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';') + { + // single character + com_token[len++] = *data++; + com_token[len] = 0; + *datapointer = data; + return true; + } + else + { + // regular word + for (;*data > ' ' && *data != ',' && *data != ';' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++) + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = *data; + com_token[len] = 0; *datapointer = data; return true; } @@ -855,15 +1006,14 @@ skipwhite: /* ============== -COM_ParseTokenConsole +COM_ParseToken_Console Parse a token out of a string, behaving like the qwcl console ============== */ -int COM_ParseTokenConsole(const char **datapointer) +int COM_ParseToken_Console(const char **datapointer) { int len; - int c; const char *data = *datapointer; len = 0; @@ -897,32 +1047,25 @@ skipwhite: else if (*data == '\"') { // quoted string - for (data++;*data != '\"';data++) + for (data++;*data && *data != '\"';data++) { - if (!*data || len >= (int)sizeof(com_token) - 1) - { - com_token[0] = 0; - *datapointer = NULL; - return false; - } - com_token[len++] = *data; + // allow escaped " and \ case + if (*data == '\\' && (data[1] == '\"' || data[1] == '\\')) + data++; + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = *data; } com_token[len] = 0; - *datapointer = data+1; + if (*data == '\"') + data++; + *datapointer = data; } else { // regular word for (;*data > ' ';data++) - { - if (len >= (int)sizeof(com_token) - 1) - { - com_token[0] = 0; - *datapointer = NULL; - return false; - } - com_token[len++] = *data; - } + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = *data; com_token[len] = 0; *datapointer = data; } @@ -1283,6 +1426,135 @@ int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *t return argc; } +/* +============ +COM_StringLengthNoColors + +calculates the visible width of a color coded string. + +*valid is filled with TRUE if the string is a valid colored string (that is, if +it does not end with an unfinished color code). If it gets filled with FALSE, a +fix would be adding a STRING_COLOR_TAG at the end of the string. + +valid can be set to NULL if the caller doesn't care. + +For size_s, specify the maximum number of characters from s to use, or 0 to use +all characters until the zero terminator. +============ +*/ +size_t +COM_StringLengthNoColors(const char *s, size_t size_s, qboolean *valid) +{ + const char *end = size_s ? (s + size_s) : NULL; + size_t len = 0; + for(;;) + { + switch((s == end) ? 0 : *s) + { + case 0: + if(valid) + *valid = TRUE; + return len; + case STRING_COLOR_TAG: + ++s; + switch((s == end) ? 0 : *s) + { + case 0: // ends with unfinished color code! + ++len; + if(valid) + *valid = FALSE; + return len; + case STRING_COLOR_TAG: // escaped ^ + ++len; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': // color code + break; + default: // not a color code + ++len; // STRING_COLOR_TAG + ++len; // the character + break; + } + break; + default: + ++len; + break; + } + ++s; + } + // never get here +} + +/* +============ +COM_StringDecolorize + +removes color codes from a string. + +If escape_carets is true, the resulting string will be safe for printing. If +escape_carets is false, the function will just strip color codes (for logging +for example). + +If the output buffer size did not suffice for converting, the function returns +FALSE. Generally, if escape_carets is false, the output buffer needs +strlen(str)+1 bytes, and if escape_carets is true, it can need strlen(str)+2 +bytes. In any case, the function makes sure that the resulting string is +zero terminated. + +For size_in, specify the maximum number of characters from in to use, or 0 to use +all characters until the zero terminator. +============ +*/ +qboolean +COM_StringDecolorize(const char *in, size_t size_in, char *out, size_t size_out, qboolean escape_carets) +{ +#define APPEND(ch) do { if(--size_out) { *out++ = (ch); } else { *out++ = 0; return FALSE; } } while(0) + const char *end = size_in ? (in + size_in) : NULL; + if(size_out < 1) + return FALSE; + for(;;) + { + switch((in == end) ? 0 : *in) + { + case 0: + *out++ = 0; + return TRUE; + case STRING_COLOR_TAG: + ++in; + switch((in == end) ? 0 : *in) + { + case 0: // ends with unfinished color code! + APPEND(STRING_COLOR_TAG); + // finish the code by appending another caret when escaping + if(escape_carets) + APPEND(STRING_COLOR_TAG); + *out++ = 0; + return TRUE; + case STRING_COLOR_TAG: // escaped ^ + APPEND(STRING_COLOR_TAG); + // append a ^ twice when escaping + if(escape_carets) + APPEND(STRING_COLOR_TAG); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': // color code + break; + default: // not a color code + APPEND(STRING_COLOR_TAG); + APPEND(*in); + break; + } + break; + default: + APPEND(*in); + break; + } + ++in; + } + // never get here +#undef APPEND +} + // written by Elric, thanks Elric! char *SearchInfostring(const char *infostring, const char *key) {