fix strlennocol/strdecolorize on unusual strings like "foo^";
authordivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 25 Apr 2007 07:18:16 +0000 (07:18 +0000)
committerdivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 25 Apr 2007 07:18:16 +0000 (07:18 +0000)
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
common.h
prvm_cmds.c

index 50fb662..118e89e 100644 (file)
--- 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)
 {
index b1a7b90..71713c4 100644 (file)
--- 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
index f846a0b..095a313 100644 (file)
@@ -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;
 }