]> git.xonotic.org Git - xonotic/netradiant.git/blobdiff - libs/splines/q_parse.cpp
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / libs / splines / q_parse.cpp
diff --git a/libs/splines/q_parse.cpp b/libs/splines/q_parse.cpp
new file mode 100644 (file)
index 0000000..7709d2b
--- /dev/null
@@ -0,0 +1,535 @@
+/*\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