-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-*/\r
-\r
-// q_parse.c -- support for parsing text files\r
-\r
-#include "q_shared.h"\r
-\r
-/*\r
-============================================================================\r
-\r
-PARSING\r
-\r
-============================================================================\r
-*/\r
-\r
-// multiple character punctuation tokens\r
-static const char *punctuation[] = {\r
- "+=", "-=", "*=", "/=", "&=", "|=", "++", "--",\r
- "&&", "||", "<=", ">=", "==", "!=",\r
- NULL\r
-};\r
-\r
-typedef struct {\r
- char token[MAX_TOKEN_CHARS];\r
- int lines;\r
- qboolean ungetToken;\r
- char parseFile[MAX_QPATH];\r
-} parseInfo_t;\r
-\r
-#define MAX_PARSE_INFO 16\r
-static parseInfo_t parseInfo[MAX_PARSE_INFO];\r
-static int parseInfoNum;\r
-static parseInfo_t *pi = &parseInfo[0];\r
-\r
-/*\r
-===================\r
-Com_BeginParseSession\r
-===================\r
-*/\r
-void Com_BeginParseSession( const char *filename ) {\r
- if ( parseInfoNum == MAX_PARSE_INFO - 1 ) {\r
- Com_Error( ERR_FATAL, "Com_BeginParseSession: session overflow" );\r
- }\r
- parseInfoNum++;\r
- pi = &parseInfo[parseInfoNum];\r
-\r
- pi->lines = 1;\r
- Q_strncpyz( pi->parseFile, filename, sizeof( pi->parseFile ) );\r
-}\r
-\r
-/*\r
-===================\r
-Com_EndParseSession\r
-===================\r
-*/\r
-void Com_EndParseSession( void ) {\r
- if ( parseInfoNum == 0 ) {\r
- Com_Error( ERR_FATAL, "Com_EndParseSession: session underflow" );\r
- }\r
- parseInfoNum--;\r
- pi = &parseInfo[parseInfoNum];\r
-}\r
-\r
-/*\r
-===================\r
-Com_GetCurrentParseLine\r
-===================\r
-*/\r
-int Com_GetCurrentParseLine( void ) {\r
- return pi->lines;\r
-}\r
-\r
-/*\r
-===================\r
-Com_ScriptError\r
-\r
-Prints the script name and line number in the message\r
-===================\r
-*/\r
-void Com_ScriptError( const char *msg, ... ) {\r
- va_list argptr;\r
- char string[32000];\r
-\r
- va_start( argptr, msg );\r
- vsprintf( string, msg,argptr );\r
- va_end( argptr );\r
-\r
- Com_Error( ERR_DROP, "File %s, line %i: %s", pi->parseFile, pi->lines, string );\r
-}\r
-\r
-void Com_ScriptWarning( const char *msg, ... ) {\r
- va_list argptr;\r
- char string[32000];\r
-\r
- va_start( argptr, msg );\r
- vsprintf( string, msg,argptr );\r
- va_end( argptr );\r
-\r
- Com_Printf( "File %s, line %i: %s", pi->parseFile, pi->lines, string );\r
-}\r
-\r
-\r
-/*\r
-===================\r
-Com_UngetToken\r
-\r
-Calling this will make the next Com_Parse return\r
-the current token instead of advancing the pointer\r
-===================\r
-*/\r
-void Com_UngetToken( void ) {\r
- if ( pi->ungetToken ) {\r
- Com_ScriptError( "UngetToken called twice" );\r
- }\r
- pi->ungetToken = qtrue;\r
-}\r
-\r
-\r
-static const char *SkipWhitespace( const char (*data), qboolean *hasNewLines ) {\r
- int c;\r
-\r
- while( (c = *data) <= ' ') {\r
- if( !c ) {\r
- return NULL;\r
- }\r
- if( c == '\n' ) {\r
- pi->lines++;\r
- *hasNewLines = qtrue;\r
- }\r
- data++;\r
- }\r
-\r
- return data;\r
-}\r
-\r
-/*\r
-==============\r
-Com_ParseExt\r
-\r
-Parse a token out of a string\r
-Will never return NULL, just empty strings.\r
-An empty string will only be returned at end of file.\r
-\r
-If "allowLineBreaks" is qtrue then an empty\r
-string will be returned if the next token is\r
-a newline.\r
-==============\r
-*/\r
-static char *Com_ParseExt( const char *(*data_p), qboolean allowLineBreaks ) {\r
- int c = 0, len;\r
- qboolean hasNewLines = qfalse;\r
- const char *data;\r
- const char **punc;\r
-\r
- if ( !data_p ) {\r
- Com_Error( ERR_FATAL, "Com_ParseExt: NULL data_p" );\r
- }\r
-\r
- data = *data_p;\r
- len = 0;\r
- pi->token[0] = 0;\r
-\r
- // make sure incoming data is valid\r
- if ( !data ) {\r
- *data_p = NULL;\r
- return pi->token;\r
- }\r
-\r
- // skip any leading whitespace\r
- while ( 1 ) {\r
- // skip whitespace\r
- data = SkipWhitespace( data, &hasNewLines );\r
- if ( !data ) {\r
- *data_p = NULL;\r
- return pi->token;\r
- }\r
- if ( hasNewLines && !allowLineBreaks ) {\r
- *data_p = data;\r
- return pi->token;\r
- }\r
-\r
- c = *data;\r
-\r
- // skip double slash comments\r
- if ( c == '/' && data[1] == '/' ) {\r
- while (*data && *data != '\n') {\r
- data++;\r
- }\r
- continue;\r
- }\r
-\r
- // skip /* */ comments\r
- if ( c=='/' && data[1] == '*' ) {\r
- while ( *data && ( *data != '*' || data[1] != '/' ) ) {\r
- if( *data == '\n' ) {\r
- pi->lines++;\r
- }\r
- data++;\r
- }\r
- if ( *data ) {\r
- data += 2;\r
- }\r
- continue;\r
- }\r
-\r
- // a real token to parse\r
- break;\r
- }\r
-\r
- // handle quoted strings\r
- if ( c == '\"' ) {\r
- data++;\r
- while( 1 ) {\r
- c = *data++;\r
- if ( ( c=='\\' ) && ( *data == '\"' ) ) {\r
- // allow quoted strings to use \" to indicate the " character\r
- data++;\r
- } else if ( c=='\"' || !c ) {\r
- pi->token[len] = 0;\r
- *data_p = ( char * ) data;\r
- return pi->token;\r
- } else if( *data == '\n' ) {\r
- pi->lines++;\r
- }\r
- if ( len < MAX_TOKEN_CHARS - 1 ) {\r
- pi->token[len] = c;\r
- len++;\r
- }\r
- }\r
- }\r
-\r
- // check for a number\r
- // is this parsing of negative numbers going to cause expression problems\r
- if ( ( c >= '0' && c <= '9' ) || ( c == '-' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) || \r
- ( c == '.' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) ) {\r
- do {\r
-\r
- if (len < MAX_TOKEN_CHARS - 1) {\r
- pi->token[len] = c;\r
- len++;\r
- }\r
- data++;\r
-\r
- c = *data;\r
- } while ( ( c >= '0' && c <= '9' ) || c == '.' );\r
-\r
- // parse the exponent\r
- if ( c == 'e' || c == 'E' ) {\r
- if (len < MAX_TOKEN_CHARS - 1) {\r
- pi->token[len] = c;\r
- len++;\r
- }\r
- data++;\r
- c = *data;\r
-\r
- if ( c == '-' || c == '+' ) {\r
- if (len < MAX_TOKEN_CHARS - 1) {\r
- pi->token[len] = c;\r
- len++;\r
- }\r
- data++;\r
- c = *data;\r
- }\r
-\r
- do {\r
- if (len < MAX_TOKEN_CHARS - 1) {\r
- pi->token[len] = c;\r
- len++;\r
- }\r
- data++;\r
-\r
- c = *data;\r
- } while ( c >= '0' && c <= '9' );\r
- }\r
-\r
- if (len == MAX_TOKEN_CHARS) {\r
- len = 0;\r
- }\r
- pi->token[len] = 0;\r
-\r
- *data_p = ( char * ) data;\r
- return pi->token;\r
- }\r
-\r
- // check for a regular word\r
- // we still allow forward and back slashes in name tokens for pathnames\r
- // and also colons for drive letters\r
- if ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' || c == '/' || c == '\\' ) {\r
- do {\r
- if (len < MAX_TOKEN_CHARS - 1) {\r
- pi->token[len] = c;\r
- len++;\r
- }\r
- data++;\r
-\r
- c = *data;\r
- } while ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' \r
- || ( c >= '0' && c <= '9' ) || c == '/' || c == '\\' || c == ':' || c == '.' );\r
-\r
- if (len == MAX_TOKEN_CHARS) {\r
- len = 0;\r
- }\r
- pi->token[len] = 0;\r
-\r
- *data_p = ( char * ) data;\r
- return pi->token;\r
- }\r
-\r
- // check for multi-character punctuation token\r
- for ( punc = punctuation ; *punc ; punc++ ) {\r
- int l;\r
- int j;\r
-\r
- l = strlen( *punc );\r
- for ( j = 0 ; j < l ; j++ ) {\r
- if ( data[j] != (*punc)[j] ) {\r
- break;\r
- }\r
- }\r
- if ( j == l ) {\r
- // a valid multi-character punctuation\r
- memcpy( pi->token, *punc, l );\r
- pi->token[l] = 0;\r
- data += l;\r
- *data_p = (char *)data;\r
- return pi->token;\r
- }\r
- }\r
-\r
- // single character punctuation\r
- pi->token[0] = *data;\r
- pi->token[1] = 0;\r
- data++;\r
- *data_p = (char *)data;\r
-\r
- return pi->token;\r
-}\r
-\r
-/*\r
-===================\r
-Com_Parse\r
-===================\r
-*/\r
-const char *Com_Parse( const char *(*data_p) ) {\r
- if ( pi->ungetToken ) {\r
- pi->ungetToken = qfalse;\r
- return pi->token;\r
- }\r
- return Com_ParseExt( data_p, qtrue );\r
-}\r
-\r
-/*\r
-===================\r
-Com_ParseOnLine\r
-===================\r
-*/\r
-const char *Com_ParseOnLine( const char *(*data_p) ) {\r
- if ( pi->ungetToken ) {\r
- pi->ungetToken = qfalse;\r
- return pi->token;\r
- }\r
- return Com_ParseExt( data_p, qfalse );\r
-}\r
-\r
-\r
-\r
-/*\r
-==================\r
-Com_MatchToken\r
-==================\r
-*/\r
-void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning ) {\r
- const char *token;\r
-\r
- token = Com_Parse( buf_p );\r
- if ( strcmp( token, match ) ) {\r
- if (warning) {\r
- Com_ScriptWarning( "MatchToken: %s != %s", token, match );\r
- } else {\r
- Com_ScriptError( "MatchToken: %s != %s", token, match );\r
- }\r
- }\r
-}\r
-\r
-\r
-/*\r
-=================\r
-Com_SkipBracedSection\r
-\r
-The next token should be an open brace.\r
-Skips until a matching close brace is found.\r
-Internal brace depths are properly skipped.\r
-=================\r
-*/\r
-void Com_SkipBracedSection( const char *(*program) ) {\r
- const char *token;\r
- int depth;\r
-\r
- depth = 0;\r
- do {\r
- token = Com_Parse( program );\r
- if( token[1] == 0 ) {\r
- if( token[0] == '{' ) {\r
- depth++;\r
- }\r
- else if( token[0] == '}' ) {\r
- depth--;\r
- }\r
- }\r
- } while( depth && *program );\r
-}\r
-\r
-/*\r
-=================\r
-Com_SkipRestOfLine\r
-=================\r
-*/\r
-void Com_SkipRestOfLine ( const char *(*data) ) {\r
- const char *p;\r
- int c;\r
-\r
- p = *data;\r
- while ( (c = *p++) != 0 ) {\r
- if ( c == '\n' ) {\r
- pi->lines++;\r
- break;\r
- }\r
- }\r
-\r
- *data = p;\r
-}\r
-\r
-/*\r
-====================\r
-Com_ParseRestOfLine\r
-====================\r
-*/\r
-const char *Com_ParseRestOfLine( const char *(*data_p) ) {\r
- static char line[MAX_TOKEN_CHARS];\r
- const char *token;\r
-\r
- line[0] = 0;\r
- while( 1 ) {\r
- token = Com_ParseOnLine( data_p );\r
- if ( !token[0] ) {\r
- break;\r
- }\r
- if ( line[0] ) {\r
- Q_strcat( line, sizeof(line), " " );\r
- }\r
- Q_strcat( line, sizeof(line), token );\r
- }\r
-\r
- return line;\r
-}\r
-\r
-\r
-float Com_ParseFloat( const char *(*buf_p) ) {\r
- const char *token;\r
-\r
- token = Com_Parse( buf_p );\r
- if ( !token[0] ) {\r
- return 0;\r
- }\r
- return atof( token );\r
-}\r
-\r
-int Com_ParseInt( const char *(*buf_p) ) {\r
- const char *token;\r
-\r
- token = Com_Parse( buf_p );\r
- if ( !token[0] ) {\r
- return 0;\r
- }\r
- return (int)atof( token );\r
-}\r
-\r
-\r
-\r
-void Com_Parse1DMatrix( const char *(*buf_p), int x, float *m ) {\r
- const char *token;\r
- int i;\r
-\r
- Com_MatchToken( buf_p, "(" );\r
-\r
- for (i = 0 ; i < x ; i++) {\r
- token = Com_Parse(buf_p);\r
- m[i] = atof(token);\r
- }\r
-\r
- Com_MatchToken( buf_p, ")" );\r
-}\r
-\r
-void Com_Parse2DMatrix( const char *(*buf_p), int y, int x, float *m ) {\r
- int i;\r
-\r
- Com_MatchToken( buf_p, "(" );\r
-\r
- for (i = 0 ; i < y ; i++) {\r
- Com_Parse1DMatrix (buf_p, x, m + i * x);\r
- }\r
-\r
- Com_MatchToken( buf_p, ")" );\r
-}\r
-\r
-void Com_Parse3DMatrix( const char *(*buf_p), int z, int y, int x, float *m ) {\r
- int i;\r
-\r
- Com_MatchToken( buf_p, "(" );\r
-\r
- for (i = 0 ; i < z ; i++) {\r
- Com_Parse2DMatrix (buf_p, y, x, m + i * x*y);\r
- }\r
-\r
- Com_MatchToken( buf_p, ")" );\r
-}\r
-\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+// q_parse.c -- support for parsing text files
+
+#include "q_shared.h"
+
+/*
+============================================================================
+
+PARSING
+
+============================================================================
+*/
+
+// multiple character punctuation tokens
+static const char *punctuation[] = {
+ "+=", "-=", "*=", "/=", "&=", "|=", "++", "--",
+ "&&", "||", "<=", ">=", "==", "!=",
+ NULL
+};
+
+typedef struct {
+ char token[MAX_TOKEN_CHARS];
+ int lines;
+ qboolean ungetToken;
+ char parseFile[MAX_QPATH];
+} parseInfo_t;
+
+#define MAX_PARSE_INFO 16
+static parseInfo_t parseInfo[MAX_PARSE_INFO];
+static int parseInfoNum;
+static parseInfo_t *pi = &parseInfo[0];
+
+/*
+===================
+Com_BeginParseSession
+===================
+*/
+void Com_BeginParseSession( const char *filename ) {
+ if ( parseInfoNum == MAX_PARSE_INFO - 1 ) {
+ Com_Error( ERR_FATAL, "Com_BeginParseSession: session overflow" );
+ }
+ parseInfoNum++;
+ pi = &parseInfo[parseInfoNum];
+
+ pi->lines = 1;
+ Q_strncpyz( pi->parseFile, filename, sizeof( pi->parseFile ) );
+}
+
+/*
+===================
+Com_EndParseSession
+===================
+*/
+void Com_EndParseSession( void ) {
+ if ( parseInfoNum == 0 ) {
+ Com_Error( ERR_FATAL, "Com_EndParseSession: session underflow" );
+ }
+ parseInfoNum--;
+ pi = &parseInfo[parseInfoNum];
+}
+
+/*
+===================
+Com_GetCurrentParseLine
+===================
+*/
+int Com_GetCurrentParseLine( void ) {
+ return pi->lines;
+}
+
+/*
+===================
+Com_ScriptError
+
+Prints the script name and line number in the message
+===================
+*/
+void Com_ScriptError( const char *msg, ... ) {
+ va_list argptr;
+ char string[32000];
+
+ va_start( argptr, msg );
+ vsprintf( string, msg,argptr );
+ va_end( argptr );
+
+ Com_Error( ERR_DROP, "File %s, line %i: %s", pi->parseFile, pi->lines, string );
+}
+
+void Com_ScriptWarning( const char *msg, ... ) {
+ va_list argptr;
+ char string[32000];
+
+ va_start( argptr, msg );
+ vsprintf( string, msg,argptr );
+ va_end( argptr );
+
+ Com_Printf( "File %s, line %i: %s", pi->parseFile, pi->lines, string );
+}
+
+
+/*
+===================
+Com_UngetToken
+
+Calling this will make the next Com_Parse return
+the current token instead of advancing the pointer
+===================
+*/
+void Com_UngetToken( void ) {
+ if ( pi->ungetToken ) {
+ Com_ScriptError( "UngetToken called twice" );
+ }
+ pi->ungetToken = qtrue;
+}
+
+
+static const char *SkipWhitespace( const char (*data), qboolean *hasNewLines ) {
+ int c;
+
+ while( (c = *data) <= ' ') {
+ if( !c ) {
+ return NULL;
+ }
+ if( c == '\n' ) {
+ pi->lines++;
+ *hasNewLines = qtrue;
+ }
+ data++;
+ }
+
+ return data;
+}
+
+/*
+==============
+Com_ParseExt
+
+Parse a token out of a string
+Will never return NULL, just empty strings.
+An empty string will only be returned at end of file.
+
+If "allowLineBreaks" is qtrue then an empty
+string will be returned if the next token is
+a newline.
+==============
+*/
+static char *Com_ParseExt( const char *(*data_p), qboolean allowLineBreaks ) {
+ int c = 0, len;
+ qboolean hasNewLines = qfalse;
+ const char *data;
+ const char **punc;
+
+ if ( !data_p ) {
+ Com_Error( ERR_FATAL, "Com_ParseExt: NULL data_p" );
+ }
+
+ data = *data_p;
+ len = 0;
+ pi->token[0] = 0;
+
+ // make sure incoming data is valid
+ if ( !data ) {
+ *data_p = NULL;
+ return pi->token;
+ }
+
+ // skip any leading whitespace
+ while ( 1 ) {
+ // skip whitespace
+ data = SkipWhitespace( data, &hasNewLines );
+ if ( !data ) {
+ *data_p = NULL;
+ return pi->token;
+ }
+ if ( hasNewLines && !allowLineBreaks ) {
+ *data_p = data;
+ return pi->token;
+ }
+
+ c = *data;
+
+ // skip double slash comments
+ if ( c == '/' && data[1] == '/' ) {
+ while (*data && *data != '\n') {
+ data++;
+ }
+ continue;
+ }
+
+ // skip /* */ comments
+ if ( c=='/' && data[1] == '*' ) {
+ while ( *data && ( *data != '*' || data[1] != '/' ) ) {
+ if( *data == '\n' ) {
+ pi->lines++;
+ }
+ data++;
+ }
+ if ( *data ) {
+ data += 2;
+ }
+ continue;
+ }
+
+ // a real token to parse
+ break;
+ }
+
+ // handle quoted strings
+ if ( c == '\"' ) {
+ data++;
+ while( 1 ) {
+ c = *data++;
+ if ( ( c=='\\' ) && ( *data == '\"' ) ) {
+ // allow quoted strings to use \" to indicate the " character
+ data++;
+ } else if ( c=='\"' || !c ) {
+ pi->token[len] = 0;
+ *data_p = ( char * ) data;
+ return pi->token;
+ } else if( *data == '\n' ) {
+ pi->lines++;
+ }
+ if ( len < MAX_TOKEN_CHARS - 1 ) {
+ pi->token[len] = c;
+ len++;
+ }
+ }
+ }
+
+ // check for a number
+ // is this parsing of negative numbers going to cause expression problems
+ if ( ( c >= '0' && c <= '9' ) || ( c == '-' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) ||
+ ( c == '.' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) ) {
+ do {
+
+ if (len < MAX_TOKEN_CHARS - 1) {
+ pi->token[len] = c;
+ len++;
+ }
+ data++;
+
+ c = *data;
+ } while ( ( c >= '0' && c <= '9' ) || c == '.' );
+
+ // parse the exponent
+ if ( c == 'e' || c == 'E' ) {
+ if (len < MAX_TOKEN_CHARS - 1) {
+ pi->token[len] = c;
+ len++;
+ }
+ data++;
+ c = *data;
+
+ if ( c == '-' || c == '+' ) {
+ if (len < MAX_TOKEN_CHARS - 1) {
+ pi->token[len] = c;
+ len++;
+ }
+ data++;
+ c = *data;
+ }
+
+ do {
+ if (len < MAX_TOKEN_CHARS - 1) {
+ pi->token[len] = c;
+ len++;
+ }
+ data++;
+
+ c = *data;
+ } while ( c >= '0' && c <= '9' );
+ }
+
+ if (len == MAX_TOKEN_CHARS) {
+ len = 0;
+ }
+ pi->token[len] = 0;
+
+ *data_p = ( char * ) data;
+ return pi->token;
+ }
+
+ // check for a regular word
+ // we still allow forward and back slashes in name tokens for pathnames
+ // and also colons for drive letters
+ if ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' || c == '/' || c == '\\' ) {
+ do {
+ if (len < MAX_TOKEN_CHARS - 1) {
+ pi->token[len] = c;
+ len++;
+ }
+ data++;
+
+ c = *data;
+ } while ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_'
+ || ( c >= '0' && c <= '9' ) || c == '/' || c == '\\' || c == ':' || c == '.' );
+
+ if (len == MAX_TOKEN_CHARS) {
+ len = 0;
+ }
+ pi->token[len] = 0;
+
+ *data_p = ( char * ) data;
+ return pi->token;
+ }
+
+ // check for multi-character punctuation token
+ for ( punc = punctuation ; *punc ; punc++ ) {
+ int l;
+ int j;
+
+ l = strlen( *punc );
+ for ( j = 0 ; j < l ; j++ ) {
+ if ( data[j] != (*punc)[j] ) {
+ break;
+ }
+ }
+ if ( j == l ) {
+ // a valid multi-character punctuation
+ memcpy( pi->token, *punc, l );
+ pi->token[l] = 0;
+ data += l;
+ *data_p = (char *)data;
+ return pi->token;
+ }
+ }
+
+ // single character punctuation
+ pi->token[0] = *data;
+ pi->token[1] = 0;
+ data++;
+ *data_p = (char *)data;
+
+ return pi->token;
+}
+
+/*
+===================
+Com_Parse
+===================
+*/
+const char *Com_Parse( const char *(*data_p) ) {
+ if ( pi->ungetToken ) {
+ pi->ungetToken = qfalse;
+ return pi->token;
+ }
+ return Com_ParseExt( data_p, qtrue );
+}
+
+/*
+===================
+Com_ParseOnLine
+===================
+*/
+const char *Com_ParseOnLine( const char *(*data_p) ) {
+ if ( pi->ungetToken ) {
+ pi->ungetToken = qfalse;
+ return pi->token;
+ }
+ return Com_ParseExt( data_p, qfalse );
+}
+
+
+
+/*
+==================
+Com_MatchToken
+==================
+*/
+void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning ) {
+ const char *token;
+
+ token = Com_Parse( buf_p );
+ if ( strcmp( token, match ) ) {
+ if (warning) {
+ Com_ScriptWarning( "MatchToken: %s != %s", token, match );
+ } else {
+ Com_ScriptError( "MatchToken: %s != %s", token, match );
+ }
+ }
+}
+
+
+/*
+=================
+Com_SkipBracedSection
+
+The next token should be an open brace.
+Skips until a matching close brace is found.
+Internal brace depths are properly skipped.
+=================
+*/
+void Com_SkipBracedSection( const char *(*program) ) {
+ const char *token;
+ int depth;
+
+ depth = 0;
+ do {
+ token = Com_Parse( program );
+ if( token[1] == 0 ) {
+ if( token[0] == '{' ) {
+ depth++;
+ }
+ else if( token[0] == '}' ) {
+ depth--;
+ }
+ }
+ } while( depth && *program );
+}
+
+/*
+=================
+Com_SkipRestOfLine
+=================
+*/
+void Com_SkipRestOfLine ( const char *(*data) ) {
+ const char *p;
+ int c;
+
+ p = *data;
+ while ( (c = *p++) != 0 ) {
+ if ( c == '\n' ) {
+ pi->lines++;
+ break;
+ }
+ }
+
+ *data = p;
+}
+
+/*
+====================
+Com_ParseRestOfLine
+====================
+*/
+const char *Com_ParseRestOfLine( const char *(*data_p) ) {
+ static char line[MAX_TOKEN_CHARS];
+ const char *token;
+
+ line[0] = 0;
+ while( 1 ) {
+ token = Com_ParseOnLine( data_p );
+ if ( !token[0] ) {
+ break;
+ }
+ if ( line[0] ) {
+ Q_strcat( line, sizeof(line), " " );
+ }
+ Q_strcat( line, sizeof(line), token );
+ }
+
+ return line;
+}
+
+
+float Com_ParseFloat( const char *(*buf_p) ) {
+ const char *token;
+
+ token = Com_Parse( buf_p );
+ if ( !token[0] ) {
+ return 0;
+ }
+ return atof( token );
+}
+
+int Com_ParseInt( const char *(*buf_p) ) {
+ const char *token;
+
+ token = Com_Parse( buf_p );
+ if ( !token[0] ) {
+ return 0;
+ }
+ return (int)atof( token );
+}
+
+
+
+void Com_Parse1DMatrix( const char *(*buf_p), int x, float *m ) {
+ const char *token;
+ int i;
+
+ Com_MatchToken( buf_p, "(" );
+
+ for (i = 0 ; i < x ; i++) {
+ token = Com_Parse(buf_p);
+ m[i] = atof(token);
+ }
+
+ Com_MatchToken( buf_p, ")" );
+}
+
+void Com_Parse2DMatrix( const char *(*buf_p), int y, int x, float *m ) {
+ int i;
+
+ Com_MatchToken( buf_p, "(" );
+
+ for (i = 0 ; i < y ; i++) {
+ Com_Parse1DMatrix (buf_p, x, m + i * x);
+ }
+
+ Com_MatchToken( buf_p, ")" );
+}
+
+void Com_Parse3DMatrix( const char *(*buf_p), int z, int y, int x, float *m ) {
+ int i;
+
+ Com_MatchToken( buf_p, "(" );
+
+ for (i = 0 ; i < z ; i++) {
+ Com_Parse2DMatrix (buf_p, y, x, m + i * x*y);
+ }
+
+ Com_MatchToken( buf_p, ")" );
+}
+