From e12d5b6c194a92ddd0a71cc8d854559130eb44a4 Mon Sep 17 00:00:00 2001 From: divverent Date: Wed, 25 Apr 2007 07:18:16 +0000 Subject: [PATCH] fix strlennocol/strdecolorize on unusual strings like "foo^"; now strlennocol returns the visible width (like before) and strdecolorize returns a string that can be safely printed and that looks like the original, just without the colors. Moved decolorizing and counting to common.c. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@7189 d7cf8633-e32d-0410-b094-e92efae38249 --- common.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++ common.h | 3 ++ prvm_cmds.c | 86 ++----------------------------------- 3 files changed, 127 insertions(+), 83 deletions(-) diff --git a/common.c b/common.c index 50fb662e..118e89e7 100644 --- a/common.c +++ b/common.c @@ -1282,6 +1282,127 @@ 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. +============ +*/ +size_t +COM_StringLengthNoColors(const char *s, qboolean *valid) +{ + size_t len = 0; + for(;;) + { + switch(*s) + { + case 0: + if(valid) + *valid = TRUE; + return len; + case STRING_COLOR_TAG: + ++s; + switch(*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. +============ +*/ +qboolean +COM_StringDecolorize(const char *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) + if(size_out < 1) + return FALSE; + for(;;) + { + switch(*in) + { + case 0: + *out++ = 0; + return TRUE; + case STRING_COLOR_TAG: + ++in; + switch(*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) { diff --git a/common.h b/common.h index b1a7b90b..71713c40 100644 --- a/common.h +++ b/common.h @@ -287,6 +287,9 @@ int COM_StringBeginsWith(const char *s, const char *match); int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix); +size_t COM_StringLengthNoColors(const char *s, qboolean *valid); +qboolean COM_StringDecolorize(const char *in, char *out, size_t size_out, qboolean escape_carets); + typedef struct stringlist_s { // maxstrings changes as needed, causing reallocation of strings[] array diff --git a/prvm_cmds.c b/prvm_cmds.c index f846a0be..095a313a 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -1754,53 +1754,12 @@ void VM_strdecolorize(void) { char szNewString[VM_STRINGTEMP_LENGTH]; const char *szString; - size_t nCnt; - int nPos; - int nFillPos; - int bFinished; - nPos = 0; - nFillPos = 0; - nCnt = 0; - bFinished = 0; // Prepare Strings VM_SAFEPARMCOUNT(1,VM_strdecolorize); szString = PRVM_G_STRING(OFS_PARM0); - while(!bFinished) - { // Traverse through String - if( szString[nPos] == '\n' || szString[nPos] == '\r' || szString[nPos] <= 0) - { // String End Found - szNewString[nFillPos++] = szString[nPos]; - bFinished = 1; - } - else - if( szString[nPos] == STRING_COLOR_TAG) - { // Color Code Located - if( szString[nPos + 1] == STRING_COLOR_TAG) - { // Valid Characters to Include - szNewString[nFillPos++] = szString[nPos]; - nPos = nPos + 1; - szNewString[nFillPos++] = szString[nPos]; - } - else - if( szString[nPos + 1] >= '0' && szString[nPos + 1] <= '9' ) - { // Color Code Found; Increment Position - nPos = nPos + 1; - } - else - { // Unknown Color Code; Include - szNewString[nFillPos++] = szString[nPos]; - nPos = nPos + 1; - } - } - else - // Include Character - szNewString[nFillPos++] = szString[nPos]; - - // Increment Position - nPos = nPos + 1; - } + COM_StringDecolorize(szString, szNewString, sizeof(szNewString), TRUE); PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(szNewString); } @@ -1818,53 +1777,14 @@ float strlennocol(string s) void VM_strlennocol(void) { const char *szString; - size_t nCnt; - int nPos; - int bFinished; - nPos = 0; - nCnt = 0; - bFinished = 0; + int nCnt; VM_SAFEPARMCOUNT(1,VM_strlennocol); szString = PRVM_G_STRING(OFS_PARM0); - while(!bFinished) - { // Count Characters - // SV_BroadcastPrintf("Position '%d'; Character '%c'; Length '%d'\n", nPos, szString[nPos], nCnt); + nCnt = COM_StringLengthNoColors(szString, NULL); - if( szString[nPos] == '\n' || szString[nPos] == '\r' || szString[nPos] <= 0) - { // String End Found - // SV_BroadcastPrintf("Found End of String at '%d'\n", nPos); - bFinished = 1; - } - else - if( szString[nPos] == STRING_COLOR_TAG) - { // Color Code Located - if( szString[nPos + 1] == STRING_COLOR_TAG) - { // Increment Length; Skip Color Code - nCnt = nCnt + 1; - nPos = nPos + 1; - } - else - if( szString[nPos + 1] >= '0' && szString[nPos + 1] <= '9' ) - { // Color Code Found; Increment Position - // SV_BroadcastPrintf("Found Color Codes at '%d'\n", nPos); - nPos = nPos + 1; - } - else - { // Unknown Color Code; Increment Length! - nPos = nPos + 1; - nCnt = nCnt + 1; - } - } - else - // Increment String Length - nCnt = nCnt + 1; - - // Increment Position - nPos = nPos + 1; - } PRVM_G_FLOAT(OFS_RETURN) = nCnt; } -- 2.39.2