Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

q_parse.cpp

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // q_parse.c -- support for parsing text files
00023 
00024 #include "q_shared.hpp"
00025 
00026 /*
00027 ============================================================================
00028 
00029 PARSING
00030 
00031 ============================================================================
00032 */
00033 
00034 // multiple character punctuation tokens
00035 static const char *punctuation[] = {
00036     "+=", "-=",  "*=",  "/=", "&=", "|=", "++", "--",
00037         "&&", "||",  "<=",  ">=", "==", "!=",
00038     NULL
00039 };
00040 
00041 typedef struct {
00042     char    token[MAX_TOKEN_CHARS];
00043     int     lines;
00044     qboolean    ungetToken;
00045     char    parseFile[MAX_QPATH];
00046 } parseInfo_t;
00047 
00048 #define MAX_PARSE_INFO  16
00049 static parseInfo_t  parseInfo[MAX_PARSE_INFO];
00050 static int          parseInfoNum;
00051 static parseInfo_t  *pi = &parseInfo[0];
00052 
00053 /*
00054 ===================
00055 Com_BeginParseSession
00056 ===================
00057 */
00058 void Com_BeginParseSession( const char *filename ) {
00059     if ( parseInfoNum == MAX_PARSE_INFO - 1 ) {
00060         Com_Error( ERR_FATAL, "Com_BeginParseSession: session overflow" );
00061     }
00062     parseInfoNum++;
00063     pi = &parseInfo[parseInfoNum];
00064 
00065     pi->lines = 1;
00066     Q_strncpyz( pi->parseFile, filename, sizeof( pi->parseFile ) );
00067 }
00068 
00069 /*
00070 ===================
00071 Com_EndParseSession
00072 ===================
00073 */
00074 void Com_EndParseSession( void ) {
00075     if ( parseInfoNum == 0 ) {
00076         Com_Error( ERR_FATAL, "Com_EndParseSession: session underflow" );
00077     }
00078     parseInfoNum--;
00079     pi = &parseInfo[parseInfoNum];
00080 }
00081 
00082 /*
00083 ===================
00084 Com_GetCurrentParseLine
00085 ===================
00086 */
00087 int Com_GetCurrentParseLine( void ) {
00088     return pi->lines;
00089 }
00090 
00091 /*
00092 ===================
00093 Com_ScriptError
00094 
00095 Prints the script name and line number in the message
00096 ===================
00097 */
00098 void Com_ScriptError( const char *msg, ... ) {
00099     va_list     argptr;
00100     char        string[32000];
00101 
00102     va_start( argptr, msg );
00103     vsprintf( string, msg,argptr );
00104     va_end( argptr );
00105 
00106     Com_Error( ERR_DROP, "File %s, line %i: %s", pi->parseFile, pi->lines, string );
00107 }
00108 
00109 void Com_ScriptWarning( const char *msg, ... ) {
00110     va_list     argptr;
00111     char        string[32000];
00112 
00113     va_start( argptr, msg );
00114     vsprintf( string, msg,argptr );
00115     va_end( argptr );
00116 
00117     Com_Printf( "File %s, line %i: %s", pi->parseFile, pi->lines, string );
00118 }
00119 
00120 
00121 /*
00122 ===================
00123 Com_UngetToken
00124 
00125 Calling this will make the next Com_Parse return
00126 the current token instead of advancing the pointer
00127 ===================
00128 */
00129 void Com_UngetToken( void ) {
00130     if ( pi->ungetToken ) {
00131         Com_ScriptError( "UngetToken called twice" );
00132     }
00133     pi->ungetToken = qtrue;
00134 }
00135 
00136 
00137 static const char *SkipWhitespace( const char (*data), qboolean *hasNewLines ) {
00138     int c;
00139 
00140     while( (c = *data) <= ' ') {
00141         if( !c ) {
00142             return NULL;
00143         }
00144         if( c == '\n' ) {
00145             pi->lines++;
00146             *hasNewLines = qtrue;
00147         }
00148         data++;
00149     }
00150 
00151     return data;
00152 }
00153 
00154 /*
00155 ==============
00156 Com_ParseExt
00157 
00158 Parse a token out of a string
00159 Will never return NULL, just empty strings.
00160 An empty string will only be returned at end of file.
00161 
00162 If "allowLineBreaks" is qtrue then an empty
00163 string will be returned if the next token is
00164 a newline.
00165 ==============
00166 */
00167 static char *Com_ParseExt( const char *(*data_p), qboolean allowLineBreaks ) {
00168     int c = 0, len;
00169     qboolean hasNewLines = qfalse;
00170     const char *data;
00171     const char **punc;
00172 
00173     if ( !data_p ) {
00174         Com_Error( ERR_FATAL, "Com_ParseExt: NULL data_p" );
00175     }
00176 
00177     data = *data_p;
00178     len = 0;
00179     pi->token[0] = 0;
00180 
00181     // make sure incoming data is valid
00182     if ( !data ) {
00183         *data_p = NULL;
00184         return pi->token;
00185     }
00186 
00187     // skip any leading whitespace
00188     while ( 1 ) {
00189         // skip whitespace
00190         data = SkipWhitespace( data, &hasNewLines );
00191         if ( !data ) {
00192             *data_p = NULL;
00193             return pi->token;
00194         }
00195         if ( hasNewLines && !allowLineBreaks ) {
00196             *data_p = data;
00197             return pi->token;
00198         }
00199 
00200         c = *data;
00201 
00202         // skip double slash comments
00203         if ( c == '/' && data[1] == '/' ) {
00204             while (*data && *data != '\n') {
00205                 data++;
00206             }
00207             continue;
00208         }
00209 
00210         // skip /* */ comments
00211         if ( c=='/' && data[1] == '*' ) {
00212             while ( *data && ( *data != '*' || data[1] != '/' ) ) {
00213                 if( *data == '\n' ) {
00214                     pi->lines++;
00215                 }
00216                 data++;
00217             }
00218             if ( *data ) {
00219                 data += 2;
00220             }
00221             continue;
00222         }
00223 
00224         // a real token to parse
00225         break;
00226     }
00227 
00228     // handle quoted strings
00229     if ( c == '\"' ) {
00230         data++;
00231         while( 1 ) {
00232             c = *data++;
00233             if ( ( c=='\\' ) && ( *data == '\"' ) ) {
00234                 // allow quoted strings to use \" to indicate the " character
00235                 data++;
00236             } else if ( c=='\"' || !c ) {
00237                 pi->token[len] = 0;
00238                 *data_p = ( char * ) data;
00239                 return pi->token;
00240             } else if( *data == '\n' ) {
00241                 pi->lines++;
00242             }
00243             if ( len < MAX_TOKEN_CHARS - 1 ) {
00244                 pi->token[len] = c;
00245                 len++;
00246             }
00247         }
00248     }
00249 
00250     // check for a number
00251     // is this parsing of negative numbers going to cause expression problems
00252     if ( ( c >= '0' && c <= '9' ) || ( c == '-' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) || 
00253         ( c == '.' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) ) {
00254         do  {
00255 
00256             if (len < MAX_TOKEN_CHARS - 1) {
00257                 pi->token[len] = c;
00258                 len++;
00259             }
00260             data++;
00261 
00262             c = *data;
00263         } while ( ( c >= '0' && c <= '9' ) || c == '.' );
00264 
00265         // parse the exponent
00266         if ( c == 'e' || c == 'E' ) {
00267             if (len < MAX_TOKEN_CHARS - 1) {
00268                 pi->token[len] = c;
00269                 len++;
00270             }
00271             data++;
00272             c = *data;
00273 
00274             if ( c == '-' || c == '+' ) {
00275                 if (len < MAX_TOKEN_CHARS - 1) {
00276                     pi->token[len] = c;
00277                     len++;
00278                 }
00279                 data++;
00280                 c = *data;
00281             }
00282 
00283             do  {
00284                 if (len < MAX_TOKEN_CHARS - 1) {
00285                     pi->token[len] = c;
00286                     len++;
00287                 }
00288                 data++;
00289 
00290                 c = *data;
00291             } while ( c >= '0' && c <= '9' );
00292         }
00293 
00294         if (len == MAX_TOKEN_CHARS) {
00295             len = 0;
00296         }
00297         pi->token[len] = 0;
00298 
00299         *data_p = ( char * ) data;
00300         return pi->token;
00301     }
00302 
00303     // check for a regular word
00304     // we still allow forward and back slashes in name tokens for pathnames
00305     // and also colons for drive letters
00306     if ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' || c == '/' || c == '\\' ) {
00307         do  {
00308             if (len < MAX_TOKEN_CHARS - 1) {
00309                 pi->token[len] = c;
00310                 len++;
00311             }
00312             data++;
00313 
00314             c = *data;
00315         } while ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' 
00316             || ( c >= '0' && c <= '9' ) || c == '/' || c == '\\' || c == ':' || c == '.' );
00317 
00318         if (len == MAX_TOKEN_CHARS) {
00319             len = 0;
00320         }
00321         pi->token[len] = 0;
00322 
00323         *data_p = ( char * ) data;
00324         return pi->token;
00325     }
00326 
00327     // check for multi-character punctuation token
00328     for ( punc = punctuation ; *punc ; punc++ ) {
00329         int     l;
00330         int     j;
00331 
00332         l = strlen( *punc );
00333         for ( j = 0 ; j < l ; j++ ) {
00334             if ( data[j] != (*punc)[j] ) {
00335                 break;
00336             }
00337         }
00338         if ( j == l ) {
00339             // a valid multi-character punctuation
00340             memcpy( pi->token, *punc, l );
00341             pi->token[l] = 0;
00342             data += l;
00343             *data_p = (char *)data;
00344             return pi->token;
00345         }
00346     }
00347 
00348     // single character punctuation
00349     pi->token[0] = *data;
00350     pi->token[1] = 0;
00351     data++;
00352     *data_p = (char *)data;
00353 
00354     return pi->token;
00355 }
00356 
00357 /*
00358 ===================
00359 Com_Parse
00360 ===================
00361 */
00362 const char *Com_Parse( const char *(*data_p) ) {
00363     if ( pi->ungetToken ) {
00364         pi->ungetToken = qfalse;
00365         return pi->token;
00366     }
00367     return Com_ParseExt( data_p, qtrue );
00368 }
00369 
00370 /*
00371 ===================
00372 Com_ParseOnLine
00373 ===================
00374 */
00375 const char *Com_ParseOnLine( const char *(*data_p) ) {
00376     if ( pi->ungetToken ) {
00377         pi->ungetToken = qfalse;
00378         return pi->token;
00379     }
00380     return Com_ParseExt( data_p, qfalse );
00381 }
00382 
00383 
00384 
00385 /*
00386 ==================
00387 Com_MatchToken
00388 ==================
00389 */
00390 void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning ) {
00391     const char  *token;
00392 
00393     token = Com_Parse( buf_p );
00394     if ( strcmp( token, match ) ) {
00395         if (warning) {
00396             Com_ScriptWarning( "MatchToken: %s != %s", token, match );
00397         } else {
00398             Com_ScriptError( "MatchToken: %s != %s", token, match );
00399         }
00400     }
00401 }
00402 
00403 
00404 /*
00405 =================
00406 Com_SkipBracedSection
00407 
00408 The next token should be an open brace.
00409 Skips until a matching close brace is found.
00410 Internal brace depths are properly skipped.
00411 =================
00412 */
00413 void Com_SkipBracedSection( const char *(*program) ) {
00414     const char          *token;
00415     int             depth;
00416 
00417     depth = 0;
00418     do {
00419         token = Com_Parse( program );
00420         if( token[1] == 0 ) {
00421             if( token[0] == '{' ) {
00422                 depth++;
00423             }
00424             else if( token[0] == '}' ) {
00425                 depth--;
00426             }
00427         }
00428     } while( depth && *program );
00429 }
00430 
00431 /*
00432 =================
00433 Com_SkipRestOfLine
00434 =================
00435 */
00436 void Com_SkipRestOfLine ( const char *(*data) ) {
00437     const char  *p;
00438     int     c;
00439 
00440     p = *data;
00441     while ( (c = *p++) != 0 ) {
00442         if ( c == '\n' ) {
00443             pi->lines++;
00444             break;
00445         }
00446     }
00447 
00448     *data = p;
00449 }
00450 
00451 /*
00452 ====================
00453 Com_ParseRestOfLine
00454 ====================
00455 */
00456 const char *Com_ParseRestOfLine( const char *(*data_p) ) {
00457     static char line[MAX_TOKEN_CHARS];
00458     const char *token;
00459 
00460     line[0] = 0;
00461     while( 1 ) {
00462         token = Com_ParseOnLine( data_p );
00463         if ( !token[0] ) {
00464             break;
00465         }
00466         if ( line[0] ) {
00467             Q_strcat( line, sizeof(line), " " );
00468         }
00469         Q_strcat( line, sizeof(line), token );
00470     }
00471 
00472     return line;
00473 }
00474 
00475 
00476 float Com_ParseFloat( const char *(*buf_p) ) {
00477     const char      *token;
00478 
00479     token = Com_Parse( buf_p );
00480     if ( !token[0] ) {
00481         return 0;
00482     }
00483     return atof( token );
00484 }
00485 
00486 int Com_ParseInt( const char *(*buf_p) ) {
00487     const char      *token;
00488 
00489     token = Com_Parse( buf_p );
00490     if ( !token[0] ) {
00491         return 0;
00492     }
00493     return atoi( token );
00494 }
00495 
00496 
00497 
00498 void Com_Parse1DMatrix( const char *(*buf_p), int x, float *m ) {
00499     const char  *token;
00500     int     i;
00501 
00502     Com_MatchToken( buf_p, "(" );
00503 
00504     for (i = 0 ; i < x ; i++) {
00505         token = Com_Parse(buf_p);
00506         m[i] = atof(token);
00507     }
00508 
00509     Com_MatchToken( buf_p, ")" );
00510 }
00511 
00512 void Com_Parse2DMatrix( const char *(*buf_p), int y, int x, float *m ) {
00513     int     i;
00514 
00515     Com_MatchToken( buf_p, "(" );
00516 
00517     for (i = 0 ; i < y ; i++) {
00518         Com_Parse1DMatrix (buf_p, x, m + i * x);
00519     }
00520 
00521     Com_MatchToken( buf_p, ")" );
00522 }
00523 
00524 void Com_Parse3DMatrix( const char *(*buf_p), int z, int y, int x, float *m ) {
00525     int     i;
00526 
00527     Com_MatchToken( buf_p, "(" );
00528 
00529     for (i = 0 ; i < z ; i++) {
00530         Com_Parse2DMatrix (buf_p, y, x, m + i * x*y);
00531     }
00532 
00533     Com_MatchToken( buf_p, ")" );
00534 }
00535 

Generated on Thu Aug 25 12:37:58 2005 for Quake III Arena by  doxygen 1.3.9.1