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)
{
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
{
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);
}
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;
}