X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=common.c;h=e0154eec0f759a7c6974aa883e64667c0f05fb6a;hb=e93385631fb31028b8879b4e77b21d5ad95969c8;hp=a510c060d86215b5fec166db6e056b28d275d7ac;hpb=d0d4509a66a143530db1f89ac0a1b079c4693e8e;p=xonotic%2Fdarkplaces.git diff --git a/common.c b/common.c index a510c060..e0154eec 100644 --- a/common.c +++ b/common.c @@ -27,17 +27,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" -cvar_t registered = {0, "registered","0", "indicates if this is running registered quake (whether gfx/qpop.lmp was found)"}; +cvar_t registered = {0, "registered","0", "indicates if this is running registered quake (whether gfx/pop.lmp was found)"}; cvar_t cmdline = {0, "cmdline","0", "contains commandline the engine was launched with"}; -extern qboolean fs_modified; // set true if using non-id files - char com_token[MAX_INPUTLINE]; int com_argc; const char **com_argv; -char com_cmdline[MAX_INPUTLINE]; - gamemode_t gamemode; const char *gamename; const char *gamedirname1; @@ -303,15 +299,15 @@ void MSG_WriteFloat (sizebuf_t *sb, float f) void MSG_WriteString (sizebuf_t *sb, const char *s) { - if (!s) - SZ_Write (sb, (unsigned char *)"", 1); + if (!s || !*s) + MSG_WriteChar (sb, 0); else SZ_Write (sb, (unsigned char *)s, (int)strlen(s)+1); } void MSG_WriteUnterminatedString (sizebuf_t *sb, const char *s) { - if (s) + if (s && *s) SZ_Write (sb, (unsigned char *)s, (int)strlen(s)); } @@ -633,7 +629,13 @@ void Com_HexDumpToConsole(const unsigned char *data, int size) { if (j < n) { - if (d[j] >= ' ' && d[j] <= 127) + // color change prefix character has to be treated specially + if (d[j] == STRING_COLOR_TAG) + { + *cur++ = STRING_COLOR_TAG; + *cur++ = STRING_COLOR_TAG; + } + else if (d[j] >= ' ') *cur++ = d[j]; else *cur++ = '.'; @@ -663,14 +665,15 @@ 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; const char *data = *datapointer; len = 0; @@ -715,56 +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 == '\\' && data[1] == '"' ) - data++; - if (!*data || len >= (int)sizeof(com_token) - 1) + c = *data; + if (*data == '\\') { - com_token[0] = 0; - *datapointer = NULL; - return false; + data++; + c = *data; + if (c == 'n') + c = '\n'; + else if (c == 't') + c = '\t'; } - com_token[len++] = *data; + 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 == '\'') + 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; + } +} + +/* +============== +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 == '\\' && data[1] == '\'' ) - data++; - if (!*data || len >= (int)sizeof(com_token) - 1) + c = *data; + if (*data == '\\') { - com_token[0] = 0; - *datapointer = NULL; - return false; + data++; + c = *data; + if (c == 'n') + c = '\n'; + else if (c == 't') + c = '\t'; } - com_token[len++] = *data; + 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++; @@ -775,17 +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) { - if (len >= (int)sizeof(com_token) - 1) + // 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++) + { + c = *data; + if (*data == '\\') { - com_token[0] = 0; - *datapointer = NULL; - return false; + data++; + c = *data; + if (c == 'n') + c = '\n'; + else if (c == 't') + c = '\t'; } - com_token[len++] = *data; + 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; } @@ -793,12 +1006,12 @@ 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; const char *data = *datapointer; @@ -834,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; } @@ -891,69 +1097,6 @@ int COM_CheckParm (const char *parm) return 0; } -/* -================ -COM_CheckRegistered - -Looks for the pop.txt file and verifies it. -Sets the "registered" cvar. -Immediately exits out if an alternate game was attempted to be started without -being registered. -================ -*/ -void COM_CheckRegistered (void) -{ - Cvar_Set ("cmdline", com_cmdline); - - if (gamemode == GAME_NORMAL && !FS_FileExists("gfx/pop.lmp")) - { - if (fs_modified) - Con_Print("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n"); - else - Con_Print("Playing shareware version.\n"); - return; - } - - Cvar_Set ("registered", "1"); - Con_Print("Playing registered version.\n"); -} - - -/* -================ -COM_InitArgv -================ -*/ -void COM_InitArgv (void) -{ - int i, j, n; - // reconstitute the command line for the cmdline externally visible cvar - n = 0; - for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++) - { - i = 0; - if (strstr(com_argv[j], " ")) - { - // arg contains whitespace, store quotes around it - com_cmdline[n++] = '\"'; - while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i]) - com_cmdline[n++] = com_argv[j][i++]; - com_cmdline[n++] = '\"'; - } - else - { - while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i]) - com_cmdline[n++] = com_argv[j][i++]; - } - if (n < ((int)sizeof(com_cmdline) - 1)) - com_cmdline[n++] = ' '; - else - break; - } - com_cmdline[n] = 0; -} - - //=========================================================================== // Game mods @@ -1029,6 +1172,12 @@ static const gamemode_info_t gamemode_info [] = // GAME_DEFEATINDETAIL2 // COMMANDLINEOPTION: Game: -did2 runs the game Defeat In Detail 2 { "did2", "-did2", "Defeat In Detail 2", "data", NULL, "did2_", "did2" }, +// GAME_DARSANA +// COMMANDLINEOPTION: Game: -darsana runs the game Darsana +{ "darsana", "-darsana", "Darsana", "ddata", NULL, "darsana", "darsana" }, +// GAME_CONTAGIONTHEORY +// COMMANDLINEOPTION: Game: -contagiontheory runs the game Contagion Theory +{ "contagiontheory", "-contagiontheory", "Contagion Theory", "ctdata", NULL, "ct", "contagiontheory" }, }; void COM_InitGameType (void) @@ -1071,8 +1220,37 @@ COM_Init */ void COM_Init_Commands (void) { + int i, j, n; + char com_cmdline[MAX_INPUTLINE]; + Cvar_RegisterVariable (®istered); Cvar_RegisterVariable (&cmdline); + + // reconstitute the command line for the cmdline externally visible cvar + n = 0; + for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++) + { + i = 0; + if (strstr(com_argv[j], " ")) + { + // arg contains whitespace, store quotes around it + com_cmdline[n++] = '\"'; + while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i]) + com_cmdline[n++] = com_argv[j][i++]; + com_cmdline[n++] = '\"'; + } + else + { + while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i]) + com_cmdline[n++] = com_argv[j][i++]; + } + if (n < ((int)sizeof(com_cmdline) - 1)) + com_cmdline[n++] = ' '; + else + break; + } + com_cmdline[n] = 0; + Cvar_Set ("cmdline", com_cmdline); } /* @@ -1248,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) { @@ -1395,7 +1702,7 @@ void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, con for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++); for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++); } - if (bufferlength <= 1 + strlen(key) + 1 + strlen(value) + strlen(buffer + pos2)) + if (bufferlength <= pos + 1 + strlen(key) + 1 + strlen(value) + strlen(buffer + pos2)) { Con_Printf("InfoString_SetValue: no room for \"%s\" \"%s\" in infostring\n", key, value); return; @@ -1410,7 +1717,7 @@ void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, con else { // just remove the key from the text - strcpy(buffer + pos, buffer + pos2); + strlcpy(buffer + pos, buffer + pos2, bufferlength - pos); } }