/* ================= PC_Int_Parse ================= */ bool PC_Int_Parse( int handle, int *i ) { pc_token_t token; int negative = false; if ( !trap_Parse_ReadToken( handle, &token ) ) { return false; } if ( token.string[ 0 ] == '(' ) { float f; if ( PC_Expression_Parse( handle, &f ) ) { *i = ( int ) f; return true; } else { return false; } } if ( token.string[ 0 ] == '-' ) { if ( !trap_Parse_ReadToken( handle, &token ) ) { return false; } negative = true; } if ( token.type != TT_NUMBER ) { PC_SourceError( handle, "expected integer but found %s", token.string ); return false; } *i = token.intvalue; if ( negative ) { *i = -*i; } return true; }
pc_token_list *CreateTokenList( int handle ) { pc_token_t token; char filename[ MAX_QPATH ]; pc_token_list *current = nullptr; pc_token_list *root = nullptr; while ( trap_Parse_ReadToken( handle, &token ) ) { pc_token_list *list = ( pc_token_list * ) BG_Alloc( sizeof( pc_token_list ) ); if ( current ) { list->prev = current; current->next = list; } else { list->prev = list; root = list; } current = list; current->next = nullptr; current->token.floatvalue = token.floatvalue; current->token.intvalue = token.intvalue; current->token.subtype = token.subtype; current->token.type = token.type; current->token.string = BG_strdup( token.string ); trap_Parse_SourceFileAndLine( handle, filename, ¤t->token.line ); } return root; }
/* ================= PC_Script_Parse ================= */ bool PC_Script_Parse( int handle, const char **out ) { char script[ 1024 ]; pc_token_t token; memset( script, 0, sizeof( script ) ); // scripts start with { and have ; separated command lists.. commands are command, arg.. // basically we want everything between the { } as it will be interpreted at run time if ( !trap_Parse_ReadToken( handle, &token ) ) { return false; } if ( Q_stricmp( token.string, "{" ) != 0 ) { return false; } while ( 1 ) { if ( !trap_Parse_ReadToken( handle, &token ) ) { return false; } if ( Q_stricmp( token.string, "}" ) == 0 ) { *out = BG_strdup( script ); return true; } if ( token.string[ 1 ] != '\0' ) { Q_strcat( script, 1024, va( "\"%s\"", token.string ) ); } else { Q_strcat( script, 1024, token.string ); } Q_strcat( script, 1024, " " ); } return false; }
/* ================= PC_Float_Parse ================= */ bool PC_Float_Parse( int handle, float *f ) { pc_token_t token; int negative = false; if ( !trap_Parse_ReadToken( handle, &token ) ) { return false; } if ( token.string[ 0 ] == '(' ) { return PC_Expression_Parse( handle, f ); } if ( token.string[ 0 ] == '-' ) { if ( !trap_Parse_ReadToken( handle, &token ) ) { return false; } negative = true; } if ( token.type != TT_NUMBER ) { PC_SourceError( handle, "expected float but found %s", token.string ); return false; } if ( negative ) { *f = -token.floatvalue; } else { *f = token.floatvalue; } return true; }
/* ================ PC_Char_Parse ================ */ bool PC_Char_Parse( int handle, char *out ) { pc_token_t token; if ( !trap_Parse_ReadToken( handle, &token ) ) { return false; } *out = token.string[ 0 ]; return true; }
bool PC_String_ParseTranslate( int handle, const char **out ) { pc_token_t token; if ( !trap_Parse_ReadToken( handle, &token ) ) { return false; } * ( out ) = BG_strdup( _(token.string) ); return true; }
void CG_BuildableStatusParse( const char *filename, buildStat_t *bs ) { pc_token_t token; int handle; const char *s; int i; float f; vec4_t c; handle = trap_Parse_LoadSource( filename ); if( !handle ) return; while( 1 ) { if( !trap_Parse_ReadToken( handle, &token ) ) break; if( !Q_stricmp( token.string, "frameShader" ) ) { if( PC_String_Parse( handle, &s ) ) bs->frameShader = trap_R_RegisterShader( s ); continue; } else if( !Q_stricmp( token.string, "overlayShader" ) ) { if( PC_String_Parse( handle, &s ) ) bs->overlayShader = trap_R_RegisterShader( s ); continue; } else if( !Q_stricmp( token.string, "noPowerShader" ) ) { if( PC_String_Parse( handle, &s ) ) bs->noPowerShader = trap_R_RegisterShader( s ); continue; } else if( !Q_stricmp( token.string, "markedShader" ) ) { if( PC_String_Parse( handle, &s ) ) bs->markedShader = trap_R_RegisterShader( s ); continue; } else if( !Q_stricmp( token.string, "healthSevereColor" ) ) { if( PC_Color_Parse( handle, &c ) ) Vector4Copy( c, bs->healthSevereColor ); continue; } else if( !Q_stricmp( token.string, "healthHighColor" ) ) { if( PC_Color_Parse( handle, &c ) ) Vector4Copy( c, bs->healthHighColor ); continue; } else if( !Q_stricmp( token.string, "healthElevatedColor" ) ) { if( PC_Color_Parse( handle, &c ) ) Vector4Copy( c, bs->healthElevatedColor ); continue; } else if( !Q_stricmp( token.string, "healthGuardedColor" ) ) { if( PC_Color_Parse( handle, &c ) ) Vector4Copy( c, bs->healthGuardedColor ); continue; } else if( !Q_stricmp( token.string, "healthLowColor" ) ) { if( PC_Color_Parse( handle, &c ) ) Vector4Copy( c, bs->healthLowColor ); continue; } else if( !Q_stricmp( token.string, "foreColor" ) ) { if( PC_Color_Parse( handle, &c ) ) Vector4Copy( c, bs->foreColor ); continue; } else if( !Q_stricmp( token.string, "backColor" ) ) { if( PC_Color_Parse( handle, &c ) ) Vector4Copy( c, bs->backColor ); continue; } else if( !Q_stricmp( token.string, "frameHeight" ) ) { if( PC_Int_Parse( handle, &i ) ) bs->frameHeight = i; continue; } else if( !Q_stricmp( token.string, "frameWidth" ) ) { if( PC_Int_Parse( handle, &i ) ) bs->frameWidth = i; continue; } else if( !Q_stricmp( token.string, "healthPadding" ) ) { if( PC_Int_Parse( handle, &i ) ) bs->healthPadding = i; continue; } else if( !Q_stricmp( token.string, "overlayHeight" ) ) { if( PC_Int_Parse( handle, &i ) ) bs->overlayHeight = i; continue; } else if( !Q_stricmp( token.string, "overlayWidth" ) ) { if( PC_Int_Parse( handle, &i ) ) bs->overlayWidth = i; continue; } else if( !Q_stricmp( token.string, "verticalMargin" ) ) { if( PC_Float_Parse( handle, &f ) ) bs->verticalMargin = f; continue; } else if( !Q_stricmp( token.string, "horizontalMargin" ) ) { if( PC_Float_Parse( handle, &f ) ) bs->horizontalMargin = f; continue; } else { Com_Printf("CG_BuildableStatusParse: unknown token %s in %s\n", token.string, filename ); bs->loaded = qfalse; return; } } bs->loaded = qtrue; }
/* ================= PC_Expression_Parse ================= */ static bool PC_Expression_Parse( int handle, float *f ) { pc_token_t token; int unmatchedParentheses = 0; exprList_t stack, fifo; exprToken_t *value; bool expectingNumber = true; #define FULL( a ) ( a.b >= ( MAX_EXPR_ELEMENTS - 1 ) ) #define EMPTY( a ) ( a.f > a.b ) #define PUSH_VAL( a, v ) \ { \ if( FULL( a ) ) { \ return false; } \ a.b++; \ a.l[ a.b ].type = EXPR_VALUE; \ a.l[ a.b ].u.val = v; \ } #define PUSH_OP( a, o ) \ { \ if( FULL( a ) ) { \ return false; } \ a.b++; \ a.l[ a.b ].type = EXPR_OPERATOR; \ a.l[ a.b ].u.op = o; \ } #define POP_STACK( a ) \ { \ if( EMPTY( a ) ) { \ return false; } \ value = &a.l[ a.b ]; \ a.b--; \ } #define PEEK_STACK_OP( a ) ( a.l[ a.b ].u.op ) #define PEEK_STACK_VAL( a ) ( a.l[ a.b ].u.val ) #define POP_FIFO( a ) \ { \ if( EMPTY( a ) ) { \ return false; } \ value = &a.l[ a.f ]; \ a.f++; \ } stack.f = fifo.f = 0; stack.b = fifo.b = -1; while ( trap_Parse_ReadToken( handle, &token ) ) { if ( !unmatchedParentheses && token.string[ 0 ] == ')' ) { break; } // Special case to catch negative numbers if ( expectingNumber && token.string[ 0 ] == '-' ) { if ( !trap_Parse_ReadToken( handle, &token ) ) { return false; } token.floatvalue = -token.floatvalue; } if ( token.type == TT_NUMBER ) { if ( !expectingNumber ) { return false; } expectingNumber = !expectingNumber; PUSH_VAL( fifo, token.floatvalue ); } else { switch ( token.string[ 0 ] ) { case '(': unmatchedParentheses++; PUSH_OP( stack, '(' ); break; case ')': unmatchedParentheses--; if ( unmatchedParentheses < 0 ) { return false; } while ( !EMPTY( stack ) && PEEK_STACK_OP( stack ) != '(' ) { POP_STACK( stack ); PUSH_OP( fifo, value->u.op ); } // Pop the '(' POP_STACK( stack ); break; case '*': case '/': case '+': case '-': if ( expectingNumber ) { return false; } expectingNumber = !expectingNumber; if ( EMPTY( stack ) ) { PUSH_OP( stack, token.string[ 0 ] ); } else { while ( !EMPTY( stack ) && OpPrec( token.string[ 0 ] ) < OpPrec( PEEK_STACK_OP( stack ) ) ) { POP_STACK( stack ); PUSH_OP( fifo, value->u.op ); } PUSH_OP( stack, token.string[ 0 ] ); } break; default: // Unknown token return false; } } } while ( !EMPTY( stack ) ) { POP_STACK( stack ); PUSH_OP( fifo, value->u.op ); } while ( !EMPTY( fifo ) ) { POP_FIFO( fifo ); if ( value->type == EXPR_VALUE ) { PUSH_VAL( stack, value->u.val ); } else if ( value->type == EXPR_OPERATOR ) { char op = value->u.op; float operand1, operand2, result; POP_STACK( stack ); operand2 = value->u.val; POP_STACK( stack ); operand1 = value->u.val; switch ( op ) { case '*': result = operand1 * operand2; break; case '/': result = operand1 / operand2; break; case '+': result = operand1 + operand2; break; case '-': result = operand1 - operand2; break; default: Com_Error( ERR_FATAL, "Unknown operator '%c' in postfix string", op ); } PUSH_VAL( stack, result ); } } POP_STACK( stack ); *f = value->u.val; return true; #undef FULL #undef EMPTY #undef PUSH_VAL #undef PUSH_OP #undef POP_STACK #undef PEEK_STACK_OP #undef PEEK_STACK_VAL #undef POP_FIFO }
/* ============ BG_VoiceParse ============ */ static voiceCmd_t *BG_VoiceParse( const char *name ) { voiceCmd_t *voiceCmds = NULL; voiceCmd_t *top = NULL; pc_token_t token; qboolean parsingCmd = qfalse; int handle; handle = trap_Parse_LoadSource( va( "voice/%s.voice", name ) ); if ( !handle ) { return NULL; } while ( trap_Parse_ReadToken( handle, &token ) ) { if ( parsingCmd ) { if ( token.string[ 0 ] == '{' ) { voiceCmds->tracks = BG_VoiceParseCommand( handle ); parsingCmd = qfalse; continue; } else { int line; char filename[ MAX_QPATH ]; trap_Parse_SourceFileAndLine( handle, filename, &line ); Com_Error( ERR_FATAL, "BG_VoiceParse(): " "parse error on line %d of %s", line, filename ); } } if ( strlen( token.string ) >= MAX_VOICE_CMD_LEN ) { int line; char filename[ MAX_QPATH ]; trap_Parse_SourceFileAndLine( handle, filename, &line ); Com_Error( ERR_FATAL, "BG_VoiceParse(): " "command \"%s\" exceeds MAX_VOICE_CMD_LEN (%d) on line %d of %s", token.string, MAX_VOICE_CMD_LEN, line, filename ); } if ( top == NULL ) { voiceCmds = BG_Alloc( sizeof( voiceCmd_t ) ); top = voiceCmds; } else { voiceCmds->next = BG_Alloc( sizeof( voiceCmd_t ) ); voiceCmds = voiceCmds->next; } Q_strncpyz( voiceCmds->cmd, token.string, sizeof( voiceCmds->cmd ) ); voiceCmds->next = NULL; parsingCmd = qtrue; } trap_Parse_FreeSource( handle ); return top; }
/* ============ BG_VoiceParseCommand ============ */ static voiceTrack_t *BG_VoiceParseCommand( int handle ) { pc_token_t token; qboolean parsingTrack = qfalse; voiceTrack_t *voiceTracks = NULL; voiceTrack_t *top = NULL; while ( trap_Parse_ReadToken( handle, &token ) ) { if ( !parsingTrack && token.string[ 0 ] == '}' ) { return top; } if ( parsingTrack ) { if ( token.string[ 0 ] == '{' ) { BG_VoiceParseTrack( handle, voiceTracks ); parsingTrack = qfalse; continue; } else { BG_VoiceParseError( handle, va( "BG_VoiceParseCommand(): " "parse error at \"%s\"", token.string ) ); } } if ( top == NULL ) { voiceTracks = BG_Alloc( sizeof( voiceTrack_t ) ); top = voiceTracks; } else { voiceTracks->next = BG_Alloc( sizeof( voiceCmd_t ) ); voiceTracks = voiceTracks->next; } if ( !trap_FS_FOpenFile( token.string, NULL, FS_READ ) ) { int line; char filename[ MAX_QPATH ]; trap_Parse_SourceFileAndLine( handle, filename, &line ); Com_Printf( S_WARNING "BG_VoiceParseCommand(): " "track \"%s\" referenced on line %d of %s does not exist\n", token.string, line, filename ); } else { #ifdef CGAME voiceTracks->track = trap_S_RegisterSound( token.string, qfalse ); voiceTracks->duration = 0; // FIXME: Was always zero... #endif } voiceTracks->team = -1; voiceTracks->pClass = -1; voiceTracks->weapon = -1; voiceTracks->enthusiasm = 0; voiceTracks->text = NULL; voiceTracks->next = NULL; parsingTrack = qtrue; } return NULL; }
/* ============ BG_VoiceParseTrack ============ */ static qboolean BG_VoiceParseTrack( int handle, voiceTrack_t *voiceTrack ) { pc_token_t token; qboolean found = qfalse; qboolean foundText = qfalse; qboolean foundToken = qfalse; foundToken = trap_Parse_ReadToken( handle, &token ); while ( foundToken ) { if ( token.string[ 0 ] == '}' ) { if ( foundText ) { return qtrue; } else { BG_VoiceParseError( handle, "BG_VoiceParseTrack(): " "missing text attribute for track" ); } } else if ( !Q_stricmp( token.string, "team" ) ) { foundToken = trap_Parse_ReadToken( handle, &token ); found = qfalse; while ( foundToken ) { if ( voiceTrack->team < 0 ) { voiceTrack->team = 0; } if ( !Q_stricmp( token.string, "humans" ) ) { voiceTrack->team |= 1 << TEAM_HUMANS; } else if ( !Q_stricmp( token.string, "aliens" ) ) { voiceTrack->team |= 1 << TEAM_ALIENS; } else { break; } found = qtrue; foundToken = trap_Parse_ReadToken( handle, &token ); } if ( !found ) { BG_VoiceParseError( handle, "BG_VoiceParseTrack(): missing \"team\" name" ); } continue; } else if ( !Q_stricmp( token.string, "class" ) ) { qboolean negate = qfalse; foundToken = trap_Parse_ReadToken( handle, &token ); found = qfalse; while ( foundToken ) { classModelConfig_t *model; int modelno = -1; if ( voiceTrack->pClass < 0 ) { voiceTrack->pClass = 0; } if ( !Q_stricmp( token.string, "all" ) ) { modelno = PCL_ALL_CLASSES; } else if ( !Q_stricmp( token.string, "humans" ) ) { modelno = PCL_HUMAN_CLASSES; } else if ( !Q_stricmp( token.string, "aliens" ) ) { modelno = PCL_ALIEN_CLASSES; } else if ( !Q_stricmp( token.string, "-" ) ) // this must be outside quotation marks { negate = qtrue; modelno = 0; } else { model = BG_ClassModelConfigByName( token.string ); if ( model != BG_ClassModelConfigByName( NULL ) ) { modelno = 1 << ( model - BG_ClassModelConfig( 0 ) ); if ( modelno <= 1) { modelno = -1; // match failure } } } if ( modelno > 0 ) { if ( negate ) { negate = qfalse; voiceTrack->pClass &= ~modelno; } else { voiceTrack->pClass |= modelno; } } else if ( modelno < 0 ) { break; // possibly the next keyword } found = qtrue; foundToken = trap_Parse_ReadToken( handle, &token ); } if ( !found ) { BG_VoiceParseError( handle, "BG_VoiceParseTrack(): missing \"class\" name" ); } continue; } else if ( !Q_stricmp( token.string, "text" ) ) { if ( foundText ) { BG_VoiceParseError( handle, "BG_VoiceParseTrack(): " "duplicate \"text\" definition for track" ); } foundToken = trap_Parse_ReadToken( handle, &token ); if ( !foundToken ) { BG_VoiceParseError( handle, "BG_VoiceParseTrack(): " "missing \"text\" value" ); } foundText = qtrue; if ( strlen( token.string ) >= MAX_SAY_TEXT ) { BG_VoiceParseError( handle, va( "BG_VoiceParseTrack(): " "\"text\" value " "\"%s\" exceeds MAX_SAY_TEXT length", token.string ) ); } voiceTrack->text = ( char * ) BG_Alloc( strlen( token.string ) + 1 ); Q_strncpyz( voiceTrack->text, token.string, strlen( token.string ) + 1 ); foundToken = trap_Parse_ReadToken( handle, &token ); continue; } else if ( !Q_stricmp( token.string, "enthusiasm" ) ) { foundToken = trap_Parse_ReadToken( handle, &token ); if ( token.type == TT_NUMBER ) { voiceTrack->enthusiasm = token.intvalue; } else { BG_VoiceParseError( handle, "BG_VoiceParseTrack(): " "missing \"enthusiasm\" value" ); } foundToken = trap_Parse_ReadToken( handle, &token ); continue; } else { BG_VoiceParseError( handle, va( "BG_VoiceParseTrack():" " unknown token \"%s\"", token.string ) ); } } return qfalse; }