#include "munga.h" #pragma hdrstop #include "gaugrend.h" #include "lamp.h" #include "mover.h" #include "terrain.h" #include "app.h" // #define LOCAL_TEST #if defined(LOCAL_TEST) # define Test_Tell(n) DEBUG_STREAM << n #else # define Test_Tell(n) #endif #define PROFILE_GAUGES #if defined(TRACE_GAUGE_RENDERER) BitTrace Gauge_Renderer("Gauge Renderer"); #endif //####################################################################### // Miscellaneous utilities //####################################################################### int LookupTable::Search(const char *string) { Check_Pointer(this); Verify(string != NULL); LookupTable *table = this; for(; table->typeString!=NULL; ++table) { if (stricmp(string, table->typeString) == 0) { break; } } Check_Fpu(); return table->value; } //####################################################################### // GaugeSymbol //####################################################################### GaugeSymbol::GaugeSymbol( GaugeSymbol **head_pointer, const char *new_label, GaugeInterpreterOffset new_offset, Logical new_resolved ) { Check(this); Check_Pointer(head_pointer); Check_Pointer(new_label); Test_Tell( "GaugeSymbol::GaugeSymbol(" << head_pointer << "," << new_label << "," << new_offset << "," << new_resolved << ")\n" ); nextSymbol = *head_pointer; *head_pointer = this; Str_Copy(label, new_label, sizeof(label)); offset = new_offset; resolved = new_resolved; Check_Fpu(); } GaugeSymbol::~GaugeSymbol() { Check(this); Check_Fpu(); } Logical GaugeSymbol::TestInstance() const { return True; } //####################################################################### // GaugeSymbolTable //####################################################################### GaugeSymbolTable::GaugeSymbolTable(char *table_pointer) { Test_Tell( "GaugeSymbolTable::GaugeSymbolTable(" << ((void *) table_pointer) << ")\n" ); Check_Pointer(this); head = NULL; tablePointer = table_pointer; Check_Fpu(); } GaugeSymbolTable::~GaugeSymbolTable() { Test_Tell( "GaugeSymbolTable::~GaugeSymbolTable()\n" ); Check(this); GaugeSymbol *symbol, *next_symbol; for(symbol=head; symbol!=NULL; symbol=next_symbol) { Check(symbol); next_symbol = symbol->nextSymbol; Unregister_Object(symbol); delete symbol; } head = NULL; Check_Fpu(); } Logical GaugeSymbolTable::TestInstance() const { return True; } void GaugeSymbolTable::Add(const char *label, GaugeInterpreterOffset new_offset) { Check(this); Check_Pointer(label); Test_Tell( "GaugeSymbolTable::Add(" << label << "," << new_offset << ")\n" ); GaugeSymbol *symbol; //------------------------------------------------- // Check to see if this label already exists //------------------------------------------------- for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol) { Check(symbol); if (stricmp(label, symbol->label) == 0) { Test_Tell("Exists.\n"); //------------------------------------------------- // It DOES exist. Has it already been resolved? //------------------------------------------------- if (!symbol->resolved) { Test_Tell("Unresolved.\n"); //------------------------------------------------- // No, resolve all forward references to it //------------------------------------------------- // Forward references (references to undefined // labels) are saved as a singly-linked list // of offsets within the table itself: each // reference to the label contains an offset to // the previous reference. The list is // terminated by an offset of -1. //------------------------------------------------- GaugeInterpreterOffset table_offset, next_offset, *offset_pointer; for ( table_offset=symbol->offset; table_offset>=0; table_offset = next_offset) { Test_Tell("Resolving " << table_offset << "\n"); offset_pointer = (GaugeInterpreterOffset *) &tablePointer[table_offset]; next_offset = *offset_pointer; *offset_pointer = (GaugeInterpreterOffset) new_offset; } symbol->offset = new_offset; symbol->resolved = True; Test_Tell("Done!\n"); Check_Fpu(); return; } else { Test_Tell("Resolved?!?!?.\n"); //------------------------------------------------- // Yes, this is an error. Throw a fit. //------------------------------------------------- DEBUG_STREAM << "label =" << label << "\n" << std::flush; Fail("Already resolved"); } } } //------------------------------------------------- // This is a new, resolved definition: just add it //------------------------------------------------- Test_Tell("New.\n"); # if DEBUG_LEVEL > 0 symbol = new GaugeSymbol(&head, label, new_offset, True); Check(symbol); Register_Object(symbol); # else new GaugeSymbol(&head, label, new_offset, True); # endif Check_Fpu(); } GaugeInterpreterOffset GaugeSymbolTable::Refer( const char *label, GaugeInterpreterOffset new_offset ) { Check(this); Check_Pointer(label); Test_Tell( "GaugeSymbolTable::Refer(" << label << "," << new_offset << ")\n" ); GaugeSymbol *symbol; //------------------------------------------------- // Check to see if this label already exists //------------------------------------------------- for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol) { Check(symbol); if (stricmp(label, symbol->label) == 0) { Test_Tell("Exists.\n"); //------------------------------------------------- // It DOES exist. Is it resolved? //------------------------------------------------- if (symbol->resolved) { Test_Tell("Resolved.\n"); //------------------------------------------------- // Yes, return the value. //------------------------------------------------- Check_Fpu(); return symbol->offset; } else { Test_Tell("Unresolved.\n"); //------------------------------------------------- // No, add to the list of forward references. //------------------------------------------------- GaugeInterpreterOffset previous_offset = symbol->offset; Test_Tell("Returning previous " << previous_offset << ".\n"); symbol->offset = new_offset; Check_Fpu(); return previous_offset; } } } //------------------------------------------------- // This is a new forward reference. // A (-1) is returned to mark the end of // the reference chain. // // IT IS NOT AN ERROR! //------------------------------------------------- Test_Tell("New.\n"); # if DEBUG_LEVEL > 0 symbol = new GaugeSymbol(&head, label, new_offset, False); Check(symbol); Register_Object(symbol); # else new GaugeSymbol(&head, label, new_offset, False); # endif Check_Fpu(); return -1; } GaugeInterpreterOffset GaugeSymbolTable::Get(const char *label) { Test_Tell( "GaugeSymbolTable::Get(" << label << ")\n" ); Check(this); Check_Pointer(label); GaugeSymbol *symbol; //------------------------------------------------- // Check to see if this label exists //------------------------------------------------- for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol) { Check(symbol); if (stricmp(label, symbol->label) == 0) { Test_Tell("Exists.\n"); //------------------------------------------------- // It DOES exist. Is it resolved? //------------------------------------------------- if (symbol->resolved) { Test_Tell("Resolved.\n"); //------------------------------------------------- // Yes, return the value. //------------------------------------------------- Check_Fpu(); return symbol->offset; } else { Test_Tell("Unresolved (error).\n"); //------------------------------------------------- // Return error. //------------------------------------------------- Check_Fpu(); return errUnresolvedForwardReference; } } } //------------------------------------------------- // Undefined, return error. //------------------------------------------------- Test_Tell("Undefined (error).\n"); Check_Fpu(); return errUndefinedSymbol; } const char * GaugeSymbolTable::LabelFromValue(GaugeInterpreterOffset value) { # if defined SHOW_EVERYTHING Test_Tell( "GaugeSymbolTable::LabelFromValue(" << value << ")\n" ); # endif Check(this); GaugeSymbol *symbol; //------------------------------------------------- // Check to see if this label exists //------------------------------------------------- for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol) { Check(symbol); if (symbol->offset == value) { //------------------------------------------------- // It DOES exist. Is it resolved? //------------------------------------------------- if (symbol->resolved) { //------------------------------------------------- // Yes, return the value. //------------------------------------------------- Check_Fpu(); return symbol->label; } else { //------------------------------------------------- // Return error. //------------------------------------------------- Check_Fpu(); return NULL; } } } //------------------------------------------------- // Undefined, return error. //------------------------------------------------- Check_Fpu(); return NULL; } Logical GaugeSymbolTable::UnresolvedForwardReferences() { Test_Tell( "GaugeSymbolTable::UnresolvedForwardReferences()\n" ); Check(this); GaugeSymbol *symbol; //------------------------------------------------- // Check for unrersolved symbols //------------------------------------------------- for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol) { Test_Tell("Symbol '" << symbol->label << "' at " << symbol << "\n"); Check(symbol); if (!symbol->resolved) { Test_Tell("Unresolved!\n"); Check_Fpu(); return True; } } //------------------------------------------------- // Everything is resolved! //------------------------------------------------- Test_Tell("All is resolved.\n"); Check_Fpu(); return False; } //####################################################################### // GaugeInterpreter //####################################################################### GaugeInterpreter::GaugeInterpreter() { Test_Tell("GaugeInterpreter::GaugeInterpreter()\n"); Check_Pointer(this); //------------------------------------------------- // Create interpreter table //------------------------------------------------- interpreterTable = new char[interpreterTableSize]; Check_Pointer(interpreterTable); Register_Pointer(interpreterTable); //------------------------------------------------- // Clear attribute variable array //------------------------------------------------- for (int i=0; i= sizeof(currentToken)) { Fail("Token too large"); return NULL; } if (c < 0) { if (char_pointer == currentToken) { # if defined(SHOW_EVERYTHING) Test_Tell("EOF, NULL\n"); # endif return NULL; } else { *char_pointer = '\0'; # if defined(SHOW_EVERYTHING) Test_Tell("EOF, token=<" << currentToken << ">\n"); # endif return currentToken; } } if (c == '\n') { # if defined(SHOW_EVERYTHING) Test_Tell("newline\n"); # endif ++lineNumber; } switch(parsingState) { case parsingWhiteSpace: switch(c) { case ' ': case '\t': case '\r': case '\n': case '\0': file.stossc(); // discard character break; case '#': file.stossc(); // discard character # if defined(SHOW_EVERYTHING) Test_Tell("start comment\n"); # endif parsingState = parsingComment; break; default: # if defined(SHOW_EVERYTHING) Test_Tell("non-white\n"); # endif parsingState = parsingToken; break; } break; case parsingToken: switch(c) { default: file.stossc(); // discard character *char_pointer++ = (char) c; break; case '"': file.stossc(); // discard character if (char_pointer == currentToken) { # if defined(SHOW_EVERYTHING) Test_Tell("start string\n"); # endif parsingState = parsingString; } else { *char_pointer = '\0'; # if defined(SHOW_EVERYTHING) Test_Tell("start string, token=<" << currentToken << ">\n"); # endif return currentToken; } break; case '{': case '}': case '(': case ')': case ',': case '=': case ';': if (char_pointer == currentToken) { file.stossc(); // discard character *char_pointer++ = (char) c; } *char_pointer = '\0'; # if defined(SHOW_EVERYTHING) Test_Tell("punctuation, token=<" << currentToken << ">\n"); # endif return currentToken; case '#': file.stossc(); // discard character # if defined(SHOW_EVERYTHING) Test_Tell("start comment\n"); # endif parsingState = parsingComment; break; case ' ': case '\t': case '\r': case '\n': case '\0': file.stossc(); // discard character *char_pointer = '\0'; # if defined(SHOW_EVERYTHING) Test_Tell("trailing white, token=<" << currentToken << ">\n"); # endif return currentToken; } break; case parsingComment: file.stossc(); // discard character switch(c) { case '\n': case '\r': if (char_pointer == currentToken) { # if defined(SHOW_EVERYTHING) Test_Tell("end of comment\n"); # endif parsingState = parsingWhiteSpace; } else { *char_pointer = '\0'; # if defined(SHOW_EVERYTHING) Test_Tell("end of comment, token=<" <\n"); # endif return currentToken; } break; } break; case parsingString: file.stossc(); // discard character if (c == '"') { *char_pointer = '\0'; # if defined(SHOW_EVERYTHING) Test_Tell("end of string, token=<" << currentToken << ">\n"); # endif return currentToken; } else { *char_pointer++ = (char) c; } break; } } Fail("Unintended exit"); Check_Fpu(); return NULL; } void GaugeInterpreter::UngetPreviousToken() { Check(this); tokenNotTaken = True; Check_Fpu(); } Logical GaugeInterpreter::GetInteger(int *int_pointer) { Test_Tell( "GaugeInterpreter::GetInteger(" << ((void *) int_pointer) << ")..." ); Check(this); Check_Pointer(int_pointer); const char *token = GetToken(); Check_Pointer(token); Test_Tell("token=" << token << "..."); int c, value = 0; Logical result, is_negative = False; if (*token == '-') { is_negative = True; ++token; } if (*token == '0') { ++token; if (*token == '\0') { Test_Tell("found zero value\n"); *int_pointer = 0; return True; } } if (*token == 'x' || *token == 'X') { for(++token; *token != '\0'; ++token) { c = toupper(*token); if (!isxdigit(c)) { return False; } if (c > '9') { c -= ('A'-':'); } value = (value << 4) + (c - '0'); } result = True; } else { for( ; *token != '\0'; ++token) { c = *token; if (!isdigit(c)) { return False; } value = (value*10) + (c - '0'); } result = True; } if (result == True) { if (is_negative) { value = - value; } Test_Tell("found value " << value << "\n"); *int_pointer = value; } # if defined(LOCAL_TEST) else { Test_Tell("FAILED\n"); } # endif Check_Fpu(); return result; } Logical GaugeInterpreter::GetScalar(Scalar *scalar_pointer) { Test_Tell( "GaugeInterpreter::GetScalar(" << ((void *) scalar_pointer) << ")..." ); Check(this); Check_Pointer(scalar_pointer); const char *token = GetToken(); Check_Pointer(token); Test_Tell("token=" << token << "\n"); float // HACK - I don't know how to avoid an explicit 'float'... value; Logical is_negative = False; if (*token == '-') { is_negative = True; ++token; } if (sscanf(token, "%f", &value) > 0) { Test_Tell("found " << value << "\n"); if (is_negative) { value = - value; } *scalar_pointer = (Scalar) value; return True; } ReportParsingError("Token not a scalar value"); Check_Fpu(); return False; } Logical GaugeInterpreter::GetVector(Vector2DOf *vector) { Test_Tell("GaugeInterpreter::GetVector(" << ((void *) vector) << ")..."); Check(this); Check_Pointer(vector); Vector2DOf local_vector; if (strcmp(GetToken(), "(") != 0) { ReportParsingError("Missing leading '(' for 2D vector"); return False; } if (!GetInteger(&local_vector.x)) { return False; } if (strcmp(GetToken(), ",") != 0) { ReportParsingError("Missing ',' for 2D vector"); return False; } if (!GetInteger(&local_vector.y)) { return False; } if (strcmp(GetToken(), ")") != 0) { ReportParsingError("Missing trailing ')' for 2D vector"); return False; } *vector = local_vector; Check_Fpu(); return True; } Logical GaugeInterpreter::GetRate(GaugeRate *rate) { Test_Tell("GaugeInterpreter::GetRate(" << ((void *) rate) << ")..."); Check(this); const char *text = GetToken(); Test_Tell("token='" << text << "'\n"); Check_Pointer(text); Check_Pointer(rate); int c; //----------------------------------------------- // Get rate (A..P) //----------------------------------------------- c = *text; if (!isalpha(c)) { ReportParsingError("Token is not a valid rate"); } else { c = toupper(c); if ((c >= 'A') && (c <= 'Z')) { *rate = Gauge::ConvertIndexToRate(c -'A'); Check_Fpu(); return True; } else { ReportParsingError("Token is not a valid rate"); } } Check_Fpu(); return False; } Logical GaugeInterpreter::GetModeMask(ModeMask *mask_pointer) { Test_Tell( "GaugeInterpreter::GetLong(" << ((void *) mask_pointer) << ")..." ); Check(this); Check_Pointer(mask_pointer); const char *token = GetToken(); Check_Pointer(token); Test_Tell("token=" << token << "..."); int c; ModeMask value = (ModeMask) 0; Logical result = False, is_negative = False; //------------------------------------------------------ // Deal with negative sign here //------------------------------------------------------ if (*token == '-') { is_negative = True; ++token; } if (isalpha(*token)) { //------------------------------------------------------ // Check for a named constant //------------------------------------------------------ Check(application); Check(application->GetModeManager()); result = application->GetModeManager()->ModeStringLookup(token, &value); } else { //-------------------------------------------------------- // Not a named constant. must be either number or an error //-------------------------------------------------------- if (*token == '0') { ++token; result = True; // might be a single lonely zero (which is legit) } if (*token == 'x' || *token == 'X') { //-------------------------------------------------------- // Process hex value //-------------------------------------------------------- for(++token; *token != '\0'; ++token) { c = toupper(*token); if (!isxdigit(c)) { return False; } if (c > '9') { c -= ('A'-':'); } value = (value << 4) + (ModeMask) (c - '0'); } result = True; } else { //-------------------------------------------------------- // Process decimal value //-------------------------------------------------------- for( ; *token != '\0'; ++token) { c = *token; if (!isdigit(c)) { Check_Fpu(); return result; } value = (value*10) + (ModeMask) (c - '0'); } result = True; } } if (result == True) { if (is_negative) { value = - value; } Test_Tell("found value " << value << "\n"); *mask_pointer = value; } # if defined(LOCAL_TEST) else { Test_Tell("FAILED\n"); } # endif Check_Fpu(); return result; } void GaugeInterpreter::ReportParsingError( const char *string ) { Check(this); Check_Pointer(string); DEBUG_STREAM << "Interpreter parsing error:" << string << " in line " << lineNumber << "\n"; Fail("Parsing error"); } void GaugeInterpreter::Initialize( const char *file_name, MethodDescription **method_list, Warehouse *warehouse_pointer ) { Check(this); Check_Pointer(file_name); Check_Pointer(method_list); Check(warehouse_pointer); //------------------------------------------------------------------------ // Determine the number of primitives //------------------------------------------------------------------------ MethodDescription *method_entry, **list; primitiveCount = 0; list = method_list; while(list != NULL) { Check_Pointer(list); method_entry = *list++; Check_Pointer(method_entry); if (method_entry->name == NULL) { //------------------------------------------------------------- // Attempt to chain to next list: if NULL, we're done. //------------------------------------------------------------- list = method_entry->parameterList[0].data.nextMethodList; } else { //------------------------------------------------------------- // Increment the primitive count //------------------------------------------------------------- ++primitiveCount; } } //------------------------------------------------------------------------ // Allocate the primitive table //------------------------------------------------------------------------ primitiveTable = new MethodDescription*[primitiveCount]; Register_Pointer(primitiveTable); //------------------------------------------------------------------------ // Fill in the primitiveTable //------------------------------------------------------------------------ MethodDescription **method_pointer = primitiveTable; list = method_list; while(list != NULL) { Check_Pointer(list); method_entry = *list++; Check_Pointer(method_entry); if (method_entry->name == NULL) { //------------------------------------------------------------- // Attempt to chain to next list: if NULL, we're done. //------------------------------------------------------------- list = method_entry->parameterList[0].data.nextMethodList; } else { //------------------------------------------------------------- // Save a pointer to the method description //------------------------------------------------------------- Verify((method_pointer-primitiveTable) < primitiveCount); *(method_pointer++) = method_entry; } } //------------------------------------------------------------------------ // Parse the text file to build the interpreter table //------------------------------------------------------------------------ //file.open(file_name, std::ios::in|std::ios::nocreate, std::filebuf::openprot); // alternate line added by RB 1/6/2007 file.open(file_name, std::ios::in, std::ios::_Openprot); if (!file.is_open()) { DEBUG_STREAM << "Cannot open interpreter file '" << file_name << "'\n" << std::flush; } else { lineNumber = 1; tokenNotTaken = False; const char *name; char local_name[32]; //---------------------------------------------------- // Parse the statement: // { } //---------------------------------------------------- // while((name = GetToken()) != NULL ) { Str_Copy(local_name, name, sizeof(local_name)); if (stricmp(GetToken(), "{") != 0) { ReportParsingError("Missing '{'"); } symbolTable->Add(local_name, currentOffset); GetProcedureBody(method_list, warehouse_pointer); } if (symbolTable->UnresolvedForwardReferences()) { ReportParsingError("Unresolved forward references"); } file.close(); { GaugeInterpreterCommand command = endMarker; Insert(&command, sizeof(GaugeInterpreterCommand)); # if defined(LOCAL_TEST) DumpTable(); # endif }; } //------------------------------------------------------------------------ // All done! //------------------------------------------------------------------------ Check_Fpu(); } void GaugeInterpreter::GetProcedureBody( MethodDescription **method_list, Warehouse *warehouse_pointer ) { Check(this); Check_Pointer(method_list); Check(warehouse_pointer); int running = 1; GaugeInterpreterCommand command; const char *name; char local_name[32]; while (running) { name = GetToken(); if (name == NULL) { ReportParsingError("Internal error (NULL token)"); } Str_Copy(local_name, name, sizeof(local_name)); if (stricmp(name, "}") == 0) { Test_Tell("End\n"); command = returnCommand; Insert(&command, sizeof(GaugeInterpreterCommand)); break; } else if (*name == '@') // example: @1 = ppc/reloadtime; { if (strlen(name) != 2) { ReportParsingError("Ill-formed attribute variable index"); } unsigned char index = (unsigned char) ((*(name+1)) - '0'); if (index > maxVariableNameArrayIndex) { ReportParsingError("Illegal attribute variable index"); } if (strcmp(GetToken(), "=") != 0) { ReportParsingError("Missing '='"); } Test_Tell("Attribute variable\n"); command = attributeVariableCommand; Insert(&command, sizeof(GaugeInterpreterCommand)); Insert(&index, sizeof(unsigned char)); InsertString(GetToken()); } else if (stricmp(name, "enable") == 0) { if (strcmp(GetToken(), "=") != 0) { ReportParsingError("Missing '='"); } ModeMask mode_mask; GetModeMask(&mode_mask); // fails to debugger if bad input Test_Tell("Enable\n"); command = enableCommand; Insert(&command, sizeof(GaugeInterpreterCommand)); Insert(&mode_mask, sizeof(ModeMask)); } else if (stricmp(name, "disable") == 0) { if (strcmp(GetToken(), "=") != 0) { ReportParsingError("Missing '='"); } ModeMask mode_mask; GetModeMask(&mode_mask); // fails to debugger if bad input Test_Tell("Disable\n"); command = disableCommand; Insert(&command, sizeof(GaugeInterpreterCommand)); Insert(&mode_mask, sizeof(ModeMask)); } else if (stricmp(name, "offset") == 0) { if (strcmp(GetToken(), "=") != 0) { ReportParsingError("Missing '='"); } Vector2DOf offset; GetVector(&offset); // fails to debugger if input bad Test_Tell("offset\n"); command = addOffsetCommand; Insert(&command, sizeof(GaugeInterpreterCommand)); Insert(&offset, sizeof(Vector2DOf)); } else if (stricmp(name, "port") == 0) { if (strcmp(GetToken(), "=") != 0) { ReportParsingError("Missing '='"); } command = setPortIndexCommand; Insert(&command, sizeof(GaugeInterpreterCommand)); InsertString(GetToken()); } else // must be either call or primitive { const char *token = GetToken(); if (stricmp(token, "(") == 0) { if ( ParsePrimitive( local_name, method_list, warehouse_pointer ) == False ) { ReportParsingError("Undefined primitive"); } if (stricmp(GetToken(), ")") != 0) { ReportParsingError("Missing ')'"); } } else { UngetPreviousToken(); Test_Tell("Call to '" << local_name << "'\n"); command = callCommand; Insert(&command, sizeof(GaugeInterpreterCommand)); Check(symbolTable); GaugeInterpreterOffset offset = symbolTable->Refer(local_name, currentOffset); Insert(&offset, sizeof(GaugeInterpreterOffset)); } } if (stricmp(GetToken(), ";") != 0) { ReportParsingError("Missing ';'"); } } Check_Fpu(); } Logical GaugeInterpreter::ParsePrimitive( const char *name, MethodDescription **method_list, Warehouse *warehouse_pointer ) { Test_Tell( "GaugeInterpreter::ParsePrimitive(" << name << ", " << method_list << ", " << warehouse_pointer << ")\n" ); Check(this); Check_Pointer(name); Check_Pointer(method_list); Check(warehouse_pointer); MethodDescription *method_entry, **list; GaugeInterpreterCommand command_number = nextAvailableCommand; int i; Logical first_parameter = True; list = method_list; while(list != NULL) { Check_Pointer(list); method_entry = *list++; Check_Pointer(method_entry); if (method_entry->name == NULL) { //------------------------------------------------------------- // Attempt to chain to next list: if NULL, we didn't match. //------------------------------------------------------------- list = method_entry->parameterList[0].data.nextMethodList; } else { //------------------------------------------------------------- // Attempt to match this entry //------------------------------------------------------------- Test_Tell("<" << method_entry->name << ">\n"); if (stricmp(method_entry->name, name) != 0) { command_number = (GaugeInterpreterCommand) (command_number + 1); } else { //------------------------------------------------------- // Name found, attempt to procure parameters //------------------------------------------------------- Test_Tell("Found, attempt to match parameters\n"); for ( i=0; method_entry->parameterList[i].type != ParameterDescription::typeEmpty; ++i ) { //------------------------------------------------------- // Eat commas (after first parameter) //------------------------------------------------------- if (first_parameter) { first_parameter = False; } else { if (stricmp(GetToken(), ",") != 0) { ReportParsingError("Missing ','"); return False; } } //------------------------------------------------------- // Read a parameter //------------------------------------------------------- if (method_entry->parameterList[i]. Extract(this, warehouse_pointer) == False ) { //---------------------------------------------- // Not found, error //---------------------------------------------- ReportParsingError("Wrong or missing parameter"); return False; } } //------------------------------------------------------- // All parameters found, write to the interpreter table //------------------------------------------------------- Test_Tell("All parameters matched\n"); Check_Pointer(method_entry->execute); // make sure it's executable Verify((command_number-nextAvailableCommand) >= 0); Verify((command_number-nextAvailableCommand) < primitiveCount); Insert(&command_number, sizeof(GaugeInterpreterCommand)); for ( i=0; method_entry->parameterList[i].type != ParameterDescription::typeEmpty; ++i ) { method_entry->parameterList[i].Save(this); } Test_Tell("All done\n"); Check_Fpu(); return True; } } } //------------------------------------------------------------- // Name not matched, return error //------------------------------------------------------------- Test_Tell("Not found!\n"); Check_Fpu(); return False; } void GaugeInterpreter::Insert(const void *value_pointer, int size_in_chars) { # if defined(SHOW_EVERYTHING) Test_Tell( "GaugeInterpreter::Insert(" << ((void *) value_pointer) << "," << size_in_chars << ")\n" ); # endif Check(this); Check_Pointer(value_pointer); Verify(size_in_chars > 0); Verify((currentOffset+size_in_chars) < interpreterTableSize); char *source; for( source= (char *) value_pointer; size_in_chars!=0; ++source, --size_in_chars ) { interpreterTable[currentOffset++] = *source; } Check_Fpu(); } void * GaugeInterpreter::Retrieve(int size_in_chars) { # if defined(SHOW_EVERYTHING) Test_Tell( "GaugeInterpreter::Retrieve(" << size_in_chars << ")\n" ); # endif Check(this); Verify(size_in_chars > 0); Verify(currentOffset >= 0); Verify(currentOffset < interpreterTableSize); void *here = &interpreterTable[currentOffset]; currentOffset = (GaugeInterpreterOffset) (currentOffset + size_in_chars); Verify(currentOffset < interpreterTableSize); Check_Fpu(); return here; } void GaugeInterpreter::InsertString(const char *string) { Check(this); Check_Pointer(string); unsigned short length = (unsigned short) (strlen(string)+1); Test_Tell( "GaugeInterpreter::InsertString(" << string << "), len=" << length << "\n" ); Verify(length < ParameterDescription::maxStringLength); Insert(&length, sizeof(unsigned short)); Insert(string, length); Check_Fpu(); } const char * GaugeInterpreter::RetrieveString() { # if defined(SHOW_EVERYTHING) Test_Tell( "GaugeInterpreter::RetrieveString()='" ); # endif Check(this); const char *pointer; unsigned short length = *(unsigned short *) Retrieve(sizeof(unsigned short)); Verify(length < ParameterDescription::maxStringLength); pointer = (const char *) &interpreterTable[currentOffset]; Check_Pointer(pointer); currentOffset = (GaugeInterpreterOffset) (currentOffset + length); # if defined(SHOW_EVERYTHING) Test_Tell( pointer << "', len=" << length << "\n"); # endif Check_Fpu(); return pointer; } void GaugeInterpreter::Interpret( const char *label, GaugeRenderer *renderer, int display_port_index, Vector2DOf position, Entity *entity ) { Test_Tell( "GaugeInterpreter::Interpret('" << label << "'," << renderer << "," << display_port_index << "," << position << "," << entity << "\n" ); Check(this); Check_Pointer(label); Check(renderer); // 'entity' is allowed to be NULL Check(symbolTable); Check_Pointer(interpreterTable); GaugeInterpreterOffset offset = symbolTable->Get(label); if (offset < 0) { DEBUG_STREAM << "GaugeInterpreter: undefined label '" << label << "'\n" << std::flush; } else { InterpretFromOffset( offset, renderer, display_port_index, position, entity ); } Check_Fpu(); } void GaugeInterpreter::InterpretFromOffset( GaugeInterpreterOffset offset, GaugeRenderer *renderer, int display_port_index, Vector2DOf original_position, Entity *entity ) { Test_Tell( "GaugeInterpreter::InterpretFromOffset(" << offset << "," << renderer << "," << display_port_index << "," << original_position << "," << entity << "\n" ); Check(this); Check(renderer); Verify(offset >= 0); // 'entity' is allowed to be NULL Check_Pointer(interpreterTable); currentOffset = offset; GaugeInterpreterCommand command; int running = 1; Vector2DOf position; position = original_position; while(running) { command = *(GaugeInterpreterCommand *) Retrieve(sizeof(GaugeInterpreterCommand)); switch(command) { case endMarker: case returnCommand: Test_Tell("Return\n"); running = 0; break; case setPortIndexCommand: { const char *port_name = RetrieveString(); Test_Tell("Set port=" << port_name << "\n"); //------------------------------------------ // Replace variable if needed //------------------------------------------ port_name = ReplaceVariable(port_name); int port = renderer->FindGraphicsPort(port_name); if (port >= 0) { display_port_index = port; } else { Tell( "GaugeInterpreter::InterpretFromOffset: port '"<< port_name << "' not found!\n" ); } } break; case addOffsetCommand: { Vector2DOf temp; temp = *(Vector2DOf *) Retrieve(sizeof(Vector2DOf)); Test_Tell("Add offset " << std::dec << temp); position.x = original_position.x + temp.x; position.y = original_position.y + temp.y; Test_Tell(" to " << position << "\n"); } break; case attributeVariableCommand: { unsigned char index = *(unsigned char *)Retrieve(sizeof(unsigned char)); const char *attribute_name = RetrieveString(); Test_Tell( "attribute variable #" << index << "=" << attribute_name << "\n" ); Verify(index < maxVariableNameArrayIndex); attributeNameArray[index] = attribute_name; } break; case callCommand: { GaugeInterpreterOffset new_offset = *(GaugeInterpreterOffset *) Retrieve(sizeof(GaugeInterpreterOffset)); Test_Tell("Call " << std::hex << new_offset << std::dec << "\n"); offset = currentOffset; // save for call InterpretFromOffset( new_offset, renderer, display_port_index, position, entity ); currentOffset = offset; // restore offset } break; case enableCommand: Test_Tell("Enable\n"); { Check(application); Check(application->GetModeManager()); application->GetModeManager()->AddModeMask( *(ModeMask*)Retrieve(sizeof(ModeMask)) ); } break; case disableCommand: Test_Tell("Disable\n"); { Check(application); Check(application->GetModeManager()); application->GetModeManager()->RemoveModeMask( *(ModeMask*)Retrieve(sizeof(ModeMask)) ); } break; default: command = (GaugeInterpreterCommand) (command - nextAvailableCommand); Verify(command < primitiveCount); Check_Pointer(primitiveTable); Test_Tell("****" << primitiveTable[command]->name<< "\n"); primitiveTable[command]->Execute( display_port_index, position, entity, renderer ); break; } } Check_Fpu(); } const char * GaugeInterpreter::ReplaceVariable(const char *string) { Check(this); Verify(string != NULL); if (*string == '@') { unsigned char index = *(string+1); if ((index >= '0') && (index <= '9')) { string = attributeNameArray[index - '0']; Verify(string != NULL); Test_Tell( "Variable @" << index << " replaced with '" << string <<"'\n" ); } } Check_Fpu(); return string; } void GaugeInterpreter::DumpTable() { Test_Tell("GaugeInterpreter::DumpTable\n"); Check(this); GaugeInterpreterCommand command; const char *label; currentOffset = 0; do { label = symbolTable->LabelFromValue(currentOffset); if (label != NULL) { DEBUG_STREAM << label << ":\n" << std::flush; } DEBUG_STREAM << " " << std::hex << currentOffset << ":" << std::flush; command = *(GaugeInterpreterCommand *) Retrieve(sizeof(GaugeInterpreterCommand)); switch(command) { case endMarker: DEBUG_STREAM << "---------End of table---------\n" << std::flush; break; case returnCommand: DEBUG_STREAM <<"return\n" << std::flush; break; case setPortIndexCommand: { const char *port_name = RetrieveString(); DEBUG_STREAM << "setport '" << port_name << "'\n" << std::flush; } break; case addOffsetCommand: { Vector2DOf offset = *(Vector2DOf *) Retrieve(sizeof(Vector2DOf)); DEBUG_STREAM << "offset " << std::dec << offset << "\n" << std::flush; } break; case callCommand: { GaugeInterpreterOffset new_offset = *(GaugeInterpreterOffset *) Retrieve(sizeof(GaugeInterpreterOffset)); DEBUG_STREAM << "call 0x" << new_offset << " (" << std::flush; const char *name = symbolTable->LabelFromValue(new_offset); if (name == NULL) { DEBUG_STREAM << "UNDEFINED!!!)\n" << std::flush; } else { DEBUG_STREAM << name << ")\n" << std::flush; } } break; case enableCommand: { ModeMask mask = *(ModeMask*)Retrieve(sizeof(ModeMask)); DEBUG_STREAM << "enable 0x" << mask << "\n" << std::flush; } break; case disableCommand: { ModeMask mask = *(ModeMask*)Retrieve(sizeof(ModeMask)); DEBUG_STREAM << "disable 0x" << mask << "\n" << std::flush; } break; default: { MethodDescription *method_entry = primitiveTable[command-nextAvailableCommand]; DEBUG_STREAM << method_entry->name << ":\n" << std::flush; int i; for ( i=0; method_entry->parameterList[i].type != ParameterDescription::typeEmpty; ++i ) { //------------------------------------------------------- // Show a parameter //------------------------------------------------------- method_entry->parameterList[i].DumpInterpreterEntry( this, " " ); } } break; } } while(command != endMarker); Check_Fpu(); } //############################################################################# // ParameterDescription //############################################################################# ParameterDescription::~ParameterDescription() { Check_Fpu(); } #if DEBUG_LEVEL <= 0 void ParameterDescription::CheckIt(int /*this_type*/) { } #else void ParameterDescription::CheckIt(int this_type) { Check_Pointer(this); Verify(type == this_type); switch(type) { case typeEmpty: case typeRate: case typeModeMask: case typeInteger: case typeColor: case typeScalar: case typeVector: case typeRectangle: break; case typeAttribute: case typeString: if (data.string != NULL) { Check_Pointer(data.string); } break; default: Fail("Illegal parameter type!"); } Check_Fpu(); } #endif void ParameterDescription::ShowInstance( char *indent ) { Check_Pointer(this); DEBUG_STREAM << indent << "ParameterDescription:" << std::dec << std::flush; switch(type) { case typeEmpty: DEBUG_STREAM << "empty" << std::flush; break; case typeRate: DEBUG_STREAM << "rate=" << std::flush; { int i,j; for(i='A',j=0x10000; i<'Q'; ++i, j<<=1) { if (data.rate & j) { DEBUG_STREAM << (char) i << std::flush; } } } break; case typeModeMask: DEBUG_STREAM << std::hex << "modeMask=" << data.modeMask << std::dec << std::flush; break; case typeInteger: DEBUG_STREAM << "integer=" << data.integer << std::flush; break; case typeColor: DEBUG_STREAM << "color=0x" << std::hex << data.color << std::dec << std::flush; break; case typeScalar: DEBUG_STREAM << "scalar=" << data.scalar << std::flush; break; case typeVector: DEBUG_STREAM << "vector= (" << data.vector.x << ", " << data.vector.y << ")"; break; case typeRectangle: DEBUG_STREAM << "rectangle= ((" << data.rectangle.bottomLeft.x << ", " << data.rectangle.bottomLeft.y << "),(" << data.rectangle.topRight.x << ", " << data.rectangle.topRight.y << ")"; break; case typeAttribute: if (data.string == NULL) { DEBUG_STREAM << "attribute=NULL\n" << std::flush; } else { DEBUG_STREAM << "attribute=<" << data.string << ">" << std::flush; } break; case typeString: if (data.string == NULL) { DEBUG_STREAM << "string=NULL\n" << std::flush; } else { DEBUG_STREAM << "string=<" << data.string << ">" << std::flush; } break; default: DEBUG_STREAM << "ILLEGAL TYPE=" << type << std::flush; } DEBUG_STREAM << "\n" << std::flush; Check_Fpu(); } void * ParameterDescription::ParseAttribute( const char *string_pointer, Entity *entity ) { Test_Tell( "ParameterDescription::ParseAttribute('" << string_pointer << "', " << entity << ")\n" ); Check_Pointer(this); Check_Pointer(string_pointer); Check(entity); Simulation* simulation; char temp_string[80], *source, *temp_ptr; Verify(type == typeAttribute); Str_Copy(temp_string, string_pointer, sizeof(temp_string)); source = temp_string; for(temp_ptr = source; *temp_ptr != '\0'; ++temp_ptr) { if (*temp_ptr == '/') { *temp_ptr = '\0'; Test_Tell("Subsystem name=" << source << "\n"); simulation = (Simulation *) entity->FindSubsystem(source); if (simulation == NULL) { Tell("parseAttribute - subsystem '" << source << "' not found\n"); Check_Fpu(); return NULL; } else { source = temp_ptr+1; Test_Tell("Subsystem attribute name=" << source << "\n"); void *attribute_pointer = simulation->GetAttributePointer(source); if (attribute_pointer == NULL) { Tell( "parseAttribute - attribute '" << string_pointer << "' not found\n" ); } Check_Fpu(); return attribute_pointer; } } } Test_Tell("Entity attribute name=" << source << "\n"); void *attribute_pointer = ((Simulation *)entity)->GetAttributePointer(source); if (attribute_pointer == NULL) { Tell( "parseAttribute - attribute '" << source << "' not found\n" ); } Check_Fpu(); return attribute_pointer; } Logical ParameterDescription::Extract( GaugeInterpreter *interpreter, Warehouse *warehouse_pointer ) { Test_Tell( "ParameterDescription::Extract(" << interpreter << ", " << warehouse_pointer << ")\n" ); Check_Pointer(this); Check(interpreter); // //---------------------------------------------------------------- // Choose the appropriate parameter type, attempt to create it //---------------------------------------------------------------- // switch(type) { case typeEmpty: Fail("type == empty!"); break; case typeRate: Test_Tell("rate? "); if (interpreter->GetRate(&data.rate)) { Test_Tell("yes.\n"); Check_Fpu(); return True; } break; case typeModeMask: Test_Tell("modeMask? "); if (interpreter->GetModeMask(&data.modeMask)) { Test_Tell("yes.\n"); Check_Fpu(); return True; } break; case typeInteger: Test_Tell("integer? "); if (interpreter->GetInteger(&data.integer)) { Test_Tell("yes.\n"); Check_Fpu(); return True; } break; case typeColor: Test_Tell("color? "); if (interpreter->GetInteger(&data.color)) { if (data.color <= 0xFF && data.color >= 0) { Test_Tell("yes.\n"); Check_Fpu(); return True; } } break; case typeScalar: Test_Tell("scalar? "); if (interpreter->GetScalar(&data.scalar)) { Test_Tell("yes.\n"); Check_Fpu(); return True; } break; case typeVector: Test_Tell("vector? "); { Vector2DOf temp_vector; if (interpreter->GetVector(&temp_vector)) { data.vector.x = temp_vector.x; data.vector.y = temp_vector.y; Test_Tell("yes.\n"); Check_Fpu(); return True; } } break; case typeRectangle: Test_Tell("rectangle? "); { int success; success = (strcmp(interpreter->GetToken(), "(") == 0); success &= interpreter->GetInteger(&data.rectangle.bottomLeft.x); success &= (strcmp(interpreter->GetToken(), ",") == 0); success &= interpreter->GetInteger(&data.rectangle.bottomLeft.y); success &= (strcmp(interpreter->GetToken(), ",") == 0); success &= interpreter->GetInteger(&data.rectangle.topRight.x); success &= (strcmp(interpreter->GetToken(), ",") == 0); success &= interpreter->GetInteger(&data.rectangle.topRight.y); success &= (strcmp(interpreter->GetToken(), ")") == 0); if (success) { Test_Tell("yes.\n"); Check_Fpu(); return True; } } break; case typeAttribute: { const char *token = interpreter->GetToken(); Test_Tell("attribute='"); Str_Copy(data.string, token, maxStringLength-1); Test_Tell(data.string << "'\n"); Check_Fpu(); } return True; case typeString: { const char *token = interpreter->GetToken(); Test_Tell("string='"); Str_Copy(data.string, token, maxStringLength-1); Test_Tell(data.string << "'\n"); Check_Fpu(); } return True; default: Fail("Illegal type"); return False; } Test_Tell("NO!\n"); Check_Fpu(); return False; } void ParameterDescription::Save(GaugeInterpreter *interpreter) { Test_Tell("ParameterDescription::Save(" << interpreter << ")\n"); Check_Pointer(this); Check(interpreter); // //---------------------------------------------------------------- // Choose the appropriate type, write to interpreter table //---------------------------------------------------------------- // switch(type) { case typeEmpty: Fail("type == empty!"); break; case typeRate: Test_Tell("rate\n"); interpreter->Insert(&data.rate, sizeof(GaugeRate)); break; case typeModeMask: Test_Tell("modeMask\n"); interpreter->Insert(&data.modeMask, sizeof(ModeMask)); break; case typeInteger: Test_Tell("integer\n"); interpreter->Insert(&data.integer, sizeof(int)); break; case typeColor: Test_Tell("color\n"); interpreter->Insert(&data.color, sizeof(int)); break; case typeScalar: Test_Tell("scalar\n"); interpreter->Insert(&data.scalar, sizeof(Scalar)); break; case typeVector: Test_Tell("vector\n"); interpreter->Insert(&data.vector.x, sizeof(int)); interpreter->Insert(&data.vector.y, sizeof(int)); break; case typeRectangle: Test_Tell("rectangle\n"); interpreter->Insert(&data.rectangle.bottomLeft.x, sizeof(int)); interpreter->Insert(&data.rectangle.bottomLeft.y, sizeof(int)); interpreter->Insert(&data.rectangle.topRight.x, sizeof(int)); interpreter->Insert(&data.rectangle.topRight.y, sizeof(int)); break; case typeAttribute: Test_Tell("attribute\n"); Check_Pointer(data.string); interpreter->InsertString(data.string); break; case typeString: Test_Tell("string\n"); interpreter->InsertString(data.string); break; default: Fail("Illegal type"); break; } Check_Fpu(); } void ParameterDescription::Restore( GaugeInterpreter *interpreter, Entity *entity ) { Check_Pointer(this); Check(interpreter); Test_Tell("\nParameterDescription::Restore-"); // //---------------------------------------------------------------- // Choose the appropriate type, read from interpreter table //---------------------------------------------------------------- // switch(type) { case typeEmpty: Fail("type == empty!"); break; case typeRate: data.rate = *(GaugeRate *)interpreter->Retrieve(sizeof(GaugeRate)); Test_Tell("rate=" << std::hex << data.rate << std::dec << "\n"); break; case typeModeMask: data.modeMask = *(ModeMask *) interpreter->Retrieve(sizeof(ModeMask)); Test_Tell("modeMask=" << std::hex << data.modeMask << std::dec << "\n"); break; case typeInteger: data.integer = *(int *) (interpreter->Retrieve(sizeof(int))); Test_Tell("integer=" << data.integer << "\n"); break; case typeColor: data.color = *(int *) (interpreter->Retrieve(sizeof(int))); Test_Tell("color=" << data.color << "\n"); break; case typeScalar: data.scalar = *(Scalar *) (interpreter->Retrieve(sizeof(Scalar))); Test_Tell("scalar=" << data.scalar << "\n"); break; case typeVector: data.vector.x = *(int*) interpreter->Retrieve(sizeof(int)); data.vector.y = *(int*) interpreter->Retrieve(sizeof(int)); Test_Tell("vector=(" << data.vector.x << "," << data.vector.y << ")\n"); break; case typeRectangle: data.rectangle.bottomLeft.x = *(int*) interpreter->Retrieve(sizeof(int)); data.rectangle.bottomLeft.y = *(int*) interpreter->Retrieve(sizeof(int)); data.rectangle.topRight.x = *(int*) interpreter->Retrieve(sizeof(int)); data.rectangle.topRight.y = *(int*) interpreter->Retrieve(sizeof(int)); Test_Tell( "rectangle=((" << data.rectangle.bottomLeft.x << "," << data.rectangle.bottomLeft.y << "),(" << data.rectangle.topRight.x << "," << data.rectangle.topRight.y << "))\n" ); break; case typeAttribute: { const char *string_pointer = interpreter->RetrieveString(); Verify(string_pointer != NULL); Test_Tell("attribute=" << string_pointer << "\n"); //-------------------------------------- // Replace if variable name //-------------------------------------- string_pointer = interpreter->ReplaceVariable(string_pointer); //-------------------------------------- // Change into true attribute pointer //-------------------------------------- Check(entity); data.attributePointer = ParseAttribute(string_pointer, entity); Verify(data.attributePointer != NULL); } break; case typeString: Test_Tell("string\n"); { // Get the string here INSTEAD of inside Str_Copy() because // of side effects! (string_pointer is referenced multiple times) const char *string_pointer = interpreter->RetrieveString(); //-------------------------------------- // Replace if variable name //-------------------------------------- string_pointer = interpreter->ReplaceVariable(string_pointer); Test_Tell("string=" << string_pointer << "\n"); Str_Copy( data.string, string_pointer, maxStringLength-1 ); } break; default: Fail("Illegal type"); break; } Check_Fpu(); } void ParameterDescription::DumpInterpreterEntry( GaugeInterpreter *interpreter, const char *indent ) { Check_Pointer(this); Check(interpreter); //---------------------------------------------------------------- // Choose the appropriate type, read from interpreter table //---------------------------------------------------------------- DEBUG_STREAM << indent << std::flush; switch(type) { case typeEmpty: DEBUG_STREAM << "***EMPTY***\n" << std::flush; break; case typeRate: { GaugeRate rate = *(GaugeRate *) interpreter->Retrieve(sizeof(GaugeRate)); DEBUG_STREAM << "rate " << rate << "\n" << std::flush; } break; case typeModeMask: { ModeMask mask = *(ModeMask *) interpreter->Retrieve(sizeof(ModeMask)); DEBUG_STREAM << "mask " << mask << "\n" << std::flush; } break; case typeInteger: { int i = *(int *) (interpreter->Retrieve(sizeof(int))); DEBUG_STREAM << std::dec << "int " << i << "\n" << std::flush; } break; case typeColor: { int i = *(int *) (interpreter->Retrieve(sizeof(int))); DEBUG_STREAM << "color 0x" << i << "\n" << std::flush; } break; case typeScalar: { Scalar s = *(int *) (interpreter->Retrieve(sizeof(Scalar))); DEBUG_STREAM << std::dec << "scalar " << s << "\n" << std::flush; } break; case typeVector: { Vector2DOf v; v.x = *(int *) (interpreter->Retrieve(sizeof(int))); v.y = *(int *) (interpreter->Retrieve(sizeof(int))); DEBUG_STREAM << std::dec << "vector " << v << "\n" << std::flush; } break; case typeRectangle: { Rectangle2D r; r.bottomLeft.x = *(int *) (interpreter->Retrieve(sizeof(int))); r.bottomLeft.y = *(int *) (interpreter->Retrieve(sizeof(int))); r.topRight.x = *(int *) (interpreter->Retrieve(sizeof(int))); r.topRight.y = *(int *) (interpreter->Retrieve(sizeof(int))); DEBUG_STREAM << std::dec << "rectangle " << r << "\n" << std::flush; } break; case typeAttribute: DEBUG_STREAM << "attribute '" << interpreter->RetrieveString() << "'\n" << std::flush; break; case typeString: DEBUG_STREAM << "string '" << interpreter->RetrieveString() << "'\n" << std::flush; break; default: DEBUG_STREAM << "ILLEGAL TYPE=" << type << "!!\n" << std::flush; break; } Check_Fpu(); } //############################################################################# // MethodDescription //############################################################################# void MethodDescription::ShowInstance(char *indent) { Check_Pointer(this); DEBUG_STREAM << indent << "MethodDescription:\n" << std::flush; char temp[80]; int i; DEBUG_STREAM << indent << "name =" << name << "\n" << std::flush; DEBUG_STREAM << indent << "execute=" << execute << "\n" << std::flush; for(i=0; i position, Entity *entity, GaugeRenderer *renderer ) { Check_Pointer(this); Check(renderer); Check(renderer->interpreter); int i; //------------------------------------------------------------- // Restore the parameters from the interpreter table //------------------------------------------------------------- for (i=0; parameterList[i].type != ParameterDescription::typeEmpty; ++i) { parameterList[i].Restore(renderer->interpreter, entity); } //------------------------------------------------------------- // Execute the call //------------------------------------------------------------- Check_Pointer(execute); # if DEBUG_LEVEL > 0 Logical result = (*execute)( display_port_index, position, entity, renderer ); Verify(result == True); # else (*execute)( display_port_index, position, entity, renderer ); # endif Check_Fpu(); } //####################################################################### // GaugeRendererStatistics //####################################################################### void GaugeRendererStatistics::Clear() { sampleCount = 0; sum = (Scalar) 0; maximum = (Scalar) 0; Check_Fpu(); } void GaugeRendererStatistics::Update(Scalar delta) { ++sampleCount; sum += delta; if (maximum < delta) { maximum = delta; } Check_Fpu(); } Scalar GaugeRendererStatistics::CalculateAverage() { Scalar average; if (sampleCount <= 0) { average = (Scalar) 0; } else { average = (Scalar) (sum/sampleCount); } Check_Fpu(); return average; } //############################################################################# // GaugeRenderer //############################################################################# GaugeRenderer *GaugeRenderer::headGaugeRenderer = NULL; GaugeRenderer::GaugeRenderer(): Renderer( application->GetApplicationLoopFrameRate(), MaxRendererComplexity, // in renderer.cc (3.0f) DefaultRendererPriority, // in renderer.hh (1) GaugeInterestType, // in interest.hh DefaultInterestDepth, // in interest.hh (1) GaugeRendererClassID // in vdata.hh ), newList(NULL), activeList(NULL), inactiveList(NULL), lampManager(NULL) // instantiated at topmost level only { Test_Tell("GaugeRenderer::GaugeRenderer()\n"); Check_Pointer(this); int i; suspended = False; previousModeMask = (ModeMask) 0; //--------------------------------------------------------------------- // Ensure that graphicsPort pointers are NULL //--------------------------------------------------------------------- for (i=0; i(activeList); Register_Object(activeIterator); //---------------------------------------------------- // Clear load-balancing data //---------------------------------------------------- for(i=0; inextGaugeRenderer ) { if (gauge_renderer == this) { // // Found! head of list? // if (previous_gauge_renderer == NULL) { headGaugeRenderer = nextGaugeRenderer; } // // Not head, remove from chain // else { previous_gauge_renderer->nextGaugeRenderer = nextGaugeRenderer; } break; } // // Keep track of 'previous' object // previous_gauge_renderer = gauge_renderer; } Check_Fpu(); } //=========================================================================== // EmergencyShutdown //=========================================================================== void GaugeRenderer::EmergencyShutdown() { Test_Tell("GaugeRenderer::EmergencyShutdown()\n"); GaugeRenderer *gauge_renderer; for( gauge_renderer = headGaugeRenderer; gauge_renderer != NULL; gauge_renderer = gauge_renderer->nextGaugeRenderer ) { gauge_renderer->LocalEmergencyShutdown(); } } //=========================================================================== // LocalEmergencyShutdown //=========================================================================== void GaugeRenderer::LocalEmergencyShutdown() { } // //=========================================================================== // TestInstance //=========================================================================== // Logical GaugeRenderer::TestInstance() const { //-------------------------------------------------------------------- // Check the base renderer //-------------------------------------------------------------------- return Renderer::TestInstance(); } // //=========================================================================== // LinkToEntity //=========================================================================== // void GaugeRenderer::LinkToEntity(Entity *entity) { Check(this); Check(entity); Test_Tell("GaugeRenderer::LinkToEntity(" << entity << ")\n"); // //-------------------------------------------------------------------- // Inform all gauges //-------------------------------------------------------------------- // GaugeBase *base_pointer; if (! suspended) { { SChainIteratorOf i(newList); while ((base_pointer=i.ReadAndNext()) != NULL) { Check(base_pointer); base_pointer->LinkToEntity(entity); } } { SChainIteratorOf i(activeList); while ((base_pointer=i.ReadAndNext()) != NULL) { Check(base_pointer); base_pointer->LinkToEntity(entity); } } { SChainIteratorOf i(inactiveList); while ((base_pointer=i.ReadAndNext()) != NULL) { Check(base_pointer); base_pointer->LinkToEntity(entity); } } } // //-------------------------------------------------------------------- // Call inherited method //-------------------------------------------------------------------- // Renderer::LinkToEntity(entity); Check_Fpu(); } // //=========================================================================== // NotifyOfNewInterestingEntity //=========================================================================== // void GaugeRenderer::NotifyOfNewInterestingEntity(Entity *entity) { Test_Tell("GaugeRenderer::NotifyOfNewInterestingEntity\n"); Check(this); Check(entity); //------------------------------------------------------ // This method used to update both the movingEntities // and staticEntities records. That functionality has // been moved up to the game-specific level (e.g., // RPL4GaugeRenderer) to allow the game to determine // what to show. Note that all descendents MUST chain // back to this base method... //------------------------------------------------------ // //-------------------------------------------------------------------- // Inform all gauges //-------------------------------------------------------------------- // GaugeBase *base_pointer; if (! suspended) { { SChainIteratorOf i(newList); while ((base_pointer=i.ReadAndNext()) != NULL) { Check(base_pointer); base_pointer->NotifyOfNewInterestingEntity(entity); } } { SChainIteratorOf i(activeList); while ((base_pointer=i.ReadAndNext()) != NULL) { Check(base_pointer); base_pointer->NotifyOfNewInterestingEntity(entity); } } { SChainIteratorOf i(inactiveList); while ((base_pointer=i.ReadAndNext()) != NULL) { Check(base_pointer); base_pointer->NotifyOfNewInterestingEntity(entity); } } } Check_Fpu(); } // //=========================================================================== // NotifyOfBecomingUninterestingEntity //=========================================================================== // void GaugeRenderer::NotifyOfBecomingUninterestingEntity(Entity *entity) { Test_Tell("GaugeRenderer::NotifyOfBecomingUninterestingEntity\n"); Check(this); Check(entity); //------------------------------------------------------ // This method used to update both the movingEntities // and staticEntities records. That functionality has // been moved up to the game-specific level (e.g., // RPL4GaugeRenderer) to allow the game to determine // what to show. Note that all descendents MUST chain // back to this base method... //------------------------------------------------------ // //-------------------------------------------------------------------- // Inform all gauges //-------------------------------------------------------------------- // GaugeBase *base_pointer; if (! suspended) { { SChainIteratorOf i(newList); while ((base_pointer=i.ReadAndNext()) != NULL) { Check(base_pointer); base_pointer->NotifyOfBecomingUninterestingEntity(entity); } } { SChainIteratorOf i(activeList); while ((base_pointer=i.ReadAndNext()) != NULL) { Check(base_pointer); base_pointer->NotifyOfBecomingUninterestingEntity(entity); } } { SChainIteratorOf i(inactiveList); while ((base_pointer=i.ReadAndNext()) != NULL) { Check(base_pointer); base_pointer->NotifyOfBecomingUninterestingEntity(entity); } } } Check_Fpu(); } // //=========================================================================== // Entity alarms //=========================================================================== // void GaugeRenderer::StartEntityAlarmImplementation( Entity *entity, Subsystem *subsystem, Enumeration condition, ResourceDescription::ResourceID resource_ID ) { Check(this); Check(gaugeAlarmManager); gaugeAlarmManager->Activate( entity, subsystem, condition, resource_ID ); Check_Fpu(); } void GaugeRenderer::StopEntityAlarmImplementation( Entity *entity, Subsystem *subsystem, Enumeration condition ) { Check(this); Check(gaugeAlarmManager); gaugeAlarmManager->Deactivate( entity, subsystem, condition ); Check_Fpu(); } // //=========================================================================== // LoadMissionImplementation //=========================================================================== // void GaugeRenderer::LoadMissionImplementation(Mission */*mission*/) { Tell("GaugeRenderer::LoadMissionImplementation()\n"); Check(this); //DEBUG_STREAM << "Mover list has " << // movingGaugeImages.NumberOfItems() << "items.\n"; //staticGaugeImages.PrintStatistics(); Check_Fpu(); } // //=========================================================================== // ShutdownImplementation //=========================================================================== // void GaugeRenderer::ShutdownImplementation() { Tell("GaugeRenderer::ShutdownImplementation()\n"); Check(this); //-------------------------------------------------------------------- // Turn off all gauge alarms //-------------------------------------------------------------------- if (gaugeAlarmManager != NULL) { Check(gaugeAlarmManager); gaugeAlarmManager->RemoveAllAlarms(); } //-------------------------------------------------------------------- // Delete all remaining gauges BEFORE clearing out the warehouse! // ...otherwise the gauges will attempt to reference items which // no longer exist in the warehouse... //-------------------------------------------------------------------- Remove(0); //-------------------------------------------------------------------- // Remove all lamps //-------------------------------------------------------------------- if (lampManager != NULL) { Check(lampManager); lampManager->RemoveAllLamps(); } //-------------------------------------------------------------------- // Clear out the warehouse //-------------------------------------------------------------------- if (warehousePointer != NULL) { Check(warehousePointer); warehousePointer->Purge(); } //-------------------------------------------------------------------- // Clear auxiliary data structures //-------------------------------------------------------------------- movingEntities.Clear(); staticEntities.Clear(); //--------------------------------------------------------------------- // Destroy all graphicsPort objects //--------------------------------------------------------------------- int i; for (i=0; iname << " "); if (stricmp(graphicsPort[i]->name, port_name) == 0) { Test_Tell("<-Found\n"); Check_Fpu(); return i; } } } } Check_Fpu(); return -1; } // //=========================================================================== // GetGraphicsPort //=========================================================================== // GraphicsPort *GaugeRenderer::GetGraphicsPort(const char * port_name) { int i(FindGraphicsPort(port_name)); Check_Fpu(); if (i >= 0) { return graphicsPort[i]; } return NULL; } GraphicsPort *GaugeRenderer::GetGraphicsPort(int port_number) { Check_Fpu(); if ((port_number >= 0) && (port_number < maximumGraphicsPorts)) { return graphicsPort[port_number]; } else { return NULL; } } // //=========================================================================== // Add //=========================================================================== // void GaugeRenderer::Add(GaugeBase *new_gauge) { Tell("GaugeRenderer::Add(" << std::hex << new_gauge << std::dec << ")\n"); Check(this); // // Don't call Check(new_gauge) here! // The Gauge creator calls AddGauge before the gauge is fully built! // Check_Pointer(new_gauge); //------------------------------------------------------------------------- // Add to 'new' list //------------------------------------------------------------------------- newList.Add(new_gauge); Check_Fpu(); } // //=========================================================================== // Remove //=========================================================================== // void GaugeRenderer::Remove(unsigned int owner_ID) { Tell("GaugeRenderer::Remove(" << owner_ID << ")\n"); Check(this); GaugeBase *the_base; //-------------------------------------------------- // Search active list first //-------------------------------------------------- { SChainIteratorOf i(activeList); //-------------------------------------------------- // Process all matching gauges //-------------------------------------------------- while ((the_base=i.GetCurrent()) != NULL) { Check(the_base); if ((owner_ID == 0) || (the_base->ownerID == owner_ID)) { //----------------------------------------------- // 'Flush' the gauge before deleting it //----------------------------------------------- the_base->Update(Gauge::gaugeRate_A); //----------------------------------------------- // Delete it //----------------------------------------------- i.Remove(); Tell(the_base->identificationString << "\n" << flush); Unregister_Object(the_base); delete the_base; } else { i.Next(); } } } //-------------------------------------------------- // Search inactive list second //-------------------------------------------------- { SChainIteratorOf i(inactiveList); //-------------------------------------------------- // Process all matching gauges //-------------------------------------------------- while ((the_base=i.GetCurrent()) != NULL) { Check(the_base); if ((owner_ID == 0) || (the_base->ownerID == owner_ID)) { //----------------------------------------------- // Delete it //----------------------------------------------- i.Remove(); Tell(the_base->identificationString << "\n" << flush); Unregister_Object(the_base); delete the_base; } else { i.Next(); } } } Check_Fpu(); } // //=========================================================================== // Remove //=========================================================================== // void GaugeRenderer::Inactivate(GaugeBase *the_base) { Tell("GaugeRenderer::Inactivate(" << std::hex << the_base << std::dec << ")\n"); Check(this); GaugeBase *the_other_base; //-------------------------------------------------- // Search active list for the base //-------------------------------------------------- SChainIteratorOf i(activeList); while ((the_other_base=i.GetCurrent()) != NULL) { Check(the_other_base); if (the_base == the_other_base) { //----------------------------------------------- // Remove from this list, place in inactive list //----------------------------------------------- i.Remove(); inactiveList.Add(the_base); the_base->BecameInactive(); break; } else { i.Next(); } } Check_Fpu(); } GaugeRate GaugeRenderer::FindBestFirstTierRate() { return Gauge::gaugeRate_B; // HACK -stubbed in } GaugeRate GaugeRenderer::FindBestSecondTierRate() { return Gauge::gaugeRate_D; // HACK -stubbed in } GaugeRate GaugeRenderer::FindBestThirdTierRate() { return Gauge::gaugeRate_H; // HACK -stubbed in } GaugeRate GaugeRenderer::FindBestFourthTierRate() { return Gauge::gaugeRate_P; // HACK -stubbed in } // //=========================================================================== // ExecuteImplementation //=========================================================================== // void GaugeRenderer::ExecuteImplementation( RendererComplexity /*complexity*/, RendererOrigin::InterestingEntityIterator */*iterator*/ ) { SET_GAUGE_RENDERER(); Check(this); if (! suspended) { if (taskMode == foreground) { ExecuteForeground(); } } Check_Fpu(); CLEAR_GAUGE_RENDERER(); } void GaugeRenderer::ExecuteForeground() { Check(this); Check(activeIterator); //------------------------------------------------------------------- // Get the current mode mask //------------------------------------------------------------------- Check(application); Check(application->GetModeManager()); ModeMask current_mode_mask = application->GetModeManager()->GetModeMask(); ModeMask previous_mode_mask = application->GetModeManager()->GetPreviousModeMask(); ModeMask change_mode_mask = current_mode_mask ^ previous_mode_mask; // xor tells me what has changed //------------------------------------------------------------------- // Update lamp manager //------------------------------------------------------------------- if (lampManager != NULL) { Check(lampManager); lampManager->Update(current_mode_mask); } //------------------------------------------------------------------- // Move new gauges to active/inactive lists //------------------------------------------------------------------- { SChainIteratorOf i(newList); GaugeBase *base_pointer; while ((base_pointer=i.GetCurrent()) != NULL) { //------------------------------------- // Always remove from 'new' list //------------------------------------- i.Remove(); //------------------------------------- // Place in appropriate list //------------------------------------- Check(base_pointer); if (base_pointer->modeMask & current_mode_mask) { // If not already flagged, or gauge's mode mask is always active, // or the mode change affects us, place into active list if (!(base_pointer->alreadyActivatedFlag) // || (base_pointer->modeMask == ModeManager::ModeAlwaysActive) || (base_pointer->modeMask & change_mode_mask)) { base_pointer->alreadyActivatedFlag = True; //------------------------------------- // Announce new status //------------------------------------- base_pointer->BecameActive(); //------------------------------------- // Place in active list only if legal //------------------------------------- if (base_pointer->stayInactive) { inactiveList.Add(base_pointer); } else { activeList.Add(base_pointer); } } } else { inactiveList.Add(base_pointer); } } } //--------------------------------------------------------------- // If the modeMask has changed, update the active/inactive lists. //--------------------------------------------------------------- if (previousModeMask != current_mode_mask) { previousModeMask = current_mode_mask; ActivateGaugeBases(current_mode_mask,change_mode_mask); DeactivateGaugeBases(current_mode_mask); } //--------------------------------------------------------------- // Restart background processing //--------------------------------------------------------------- taskMode = background; activeIterator->First(); //-------------------------------- // Reset rate bit mask if needed //-------------------------------- if (rateBitMask == 0) { rateBitMask = 0x8000; # if defined (PROFILE_GAUGES) rateProfileIndex = 0; # endif } Check_Fpu(); } // //=========================================================================== // ExecuteBackground //=========================================================================== // Logical GaugeRenderer::ExecuteBackground() { SET_GAUGE_RENDERER(); Check(this); Logical result; Time start, end; int oldTaskMode = taskMode; switch(taskMode) { case foreground: result = ExecuteBackgroundDisplayUpdate(); // might as well update break; case background: { result = ProcessOneActiveGauge(); break; } case copy: result = ExecuteBackgroundDisplayUpdate(); break; } if (end.ticks - start.ticks > 100) { end = start; } Check_Fpu(); CLEAR_GAUGE_RENDERER(); return result; } Logical GaugeRenderer::ExecuteBackgroundDisplayUpdate() { Check(this); return False; } // //=========================================================================== // ActivateGaugeBases //=========================================================================== // void GaugeRenderer::ActivateGaugeBases(ModeMask current_mode_mask, ModeMask change_mode_mask) { Check(this); //----------------------------------------------------------- // Test the objects in the 'inactive' list. If any of them // have bits in their modeMask corresponding to the // new mode mask, move them to the 'active' list. //----------------------------------------------------------- SChainIteratorOf i(inactiveList); GaugeBase *base_pointer; while ((base_pointer=i.GetCurrent()) != NULL) { Check(base_pointer); //----------------------------------- // Became active? //----------------------------------- if (base_pointer->modeMask & current_mode_mask) { if (!(base_pointer->alreadyActivatedFlag) // || (base_pointer->modeMask == ModeManager::ModeAlwaysActive) || (base_pointer->modeMask & change_mode_mask)) { #if 0 DEBUG_STREAM << "Activating an inactive (not visible) gauge on inactive list" << endl << std::flush; #endif //----------------------------------- // Inform object of new status //----------------------------------- base_pointer->BecameActive(); base_pointer->alreadyActivatedFlag = True; //----------------------------------- // Move to 'active' list if allowed //----------------------------------- if (base_pointer->stayInactive) { i.Next(); } else { i.Remove(); activeList.Add(base_pointer); } } else { i.Next(); } } else { //----------------------------------- // No, try the next one //----------------------------------- i.Next(); } } Check_Fpu(); } // //=========================================================================== // DeactivateGaugeBases //=========================================================================== // void GaugeRenderer::DeactivateGaugeBases(ModeMask current_mode_mask) { Check(this); //--------------------------------------------------------------- // Test the objects in the 'active' list. If any of them do NOT // have bits in their modeMask corresponding to the new mode // mask, move them to the 'inactive' list. //--------------------------------------------------------------- SChainIteratorOf i(activeList); GaugeBase *base_pointer; while ((base_pointer=i.GetCurrent()) != NULL) { Check(base_pointer); //----------------------------------- // Became inactive? //----------------------------------- if (!(base_pointer->modeMask & current_mode_mask)) { base_pointer->alreadyActivatedFlag = False; //----------------------------------- // Yes, move to 'inactive' list //----------------------------------- i.Remove(); inactiveList.Add(base_pointer); base_pointer->BecameInactive(); } else { //----------------------------------- // No, try the next one //----------------------------------- i.Next(); } } Check_Fpu(); } // //=========================================================================== // ProcessOneActiveGauge //=========================================================================== // Logical GaugeRenderer::ProcessOneActiveGauge() { Check(this); Check(activeIterator); Logical result; GaugeBase *base_pointer = activeIterator->ReadAndNext(); if (base_pointer == NULL) { //-------------------------------------------------- // We're done! // Bump the bit mask and index for the next pass //-------------------------------------------------- rateBitMask >>= 1; # if defined (PROFILE_GAUGES) ++rateProfileIndex; # endif //-------------------------------------------------- // Inform system that we are finished //-------------------------------------------------- taskMode = copy; result = True; // Don't stop just yet! Go into third phase! } else { //-------------------------------------------------- // Process one gauge //-------------------------------------------------- Check(base_pointer); # if defined (PROFILE_GAUGES) Scalar delta = GetCurrentFramePercentage(); Logical actually_ran = # endif base_pointer->Update(rateBitMask); # if defined (PROFILE_GAUGES) delta = GetCurrentFramePercentage() - delta; if (delta < (Scalar) 0) { // Hack - what does it REALLY mean when it's negative?!? delta = - delta; } if (actually_ran) { base_pointer->UpdateProfile(delta); } statistics[rateProfileIndex][base_pointer->DiscernTier()] .Update(delta); # endif //-------------------------------------------------- // Tell renderer manager that we have more to do //-------------------------------------------------- result = True; } return result; } // //=========================================================================== // GetCurrentFramePercentage //=========================================================================== // Scalar GaugeRenderer::GetCurrentFramePercentage() { Check(this); return (Scalar) 0; } enum { average_bar, maximum_bar }; #if defined (PROFILE_GAUGES) static Scalar draw_bar( GaugeRenderer *renderer, int bar_width, int slot_index, int bar_type ) { Check(renderer); //------------------------------------ // Show individual tier contributors //------------------------------------ Scalar value, total_value = (Scalar) 0; Scalar position = (Scalar) 0; int tier_index, char_position = 0, next_char_position; for(tier_index=0; tier_indexstatistics[slot_index][tier_index].CalculateAverage(); break; case maximum_bar: value= renderer->statistics[slot_index][tier_index].maximum; break; } //------------------------------------ // Add to total // Calculate next bar position //------------------------------------ total_value += value; position += bar_width * value; //------------------------------------ // Limit it in case of overflow //------------------------------------ if (position > (Scalar) bar_width) { position = (Scalar) bar_width; } //------------------------------------ // Draw with marker to next position //------------------------------------ next_char_position = (int) position; for( ; char_position < next_char_position; ++char_position) { DEBUG_STREAM << tier_marker << std::flush; } } //------------------------------------ // Fill unused space in bar //------------------------------------ for( ; char_position < bar_width; ++char_position) { DEBUG_STREAM << "." << std::flush; } Check_Fpu(); return total_value; } #endif void GaugeRenderer::ProfileReport() { Check(this); # if defined (PROFILE_GAUGES) //-------------------------------------------------------------- // Show all gauges //-------------------------------------------------------------- { SChainIteratorOf i(activeList); GaugeBase *the_base; DEBUG_STREAM <<"Active name count avg worst\n" << std::flush; DEBUG_STREAM <<"-------------------------------- ----- ------ -----\n" << std::flush; while ((the_base=i.ReadAndNext()) != NULL) { Check(the_base); the_base->ReportProfile(); } } { SChainIteratorOf i(inactiveList); GaugeBase *the_base; DEBUG_STREAM <<"Inactive name count avg worst\n" << std::flush; DEBUG_STREAM <<"-------------------------------- ----- ------ -----\n" << std::flush; while ((the_base=i.ReadAndNext()) != NULL) { Check(the_base); the_base->ReportProfile(); } } //-------------------------------------------------------------------- // Dump profiling data //-------------------------------------------------------------------- int slot_index, tier_index, bar_width = 40; // total width of bar graph char buffer[80]; //------------------------------------ // Print header bar //------------------------------------ DEBUG_STREAM << "\nSlot|Count|Tier values " << std::flush; DEBUG_STREAM << "|Total %\n" << std::flush; DEBUG_STREAM << "----+-----+" << std::flush; { for(int i=0; iInitialize(file_name, method_description, warehousePointer); //----------------------------------------------- // Execute app initialization call, if it exists //----------------------------------------------- Configure("Initialization", NULL); Check_Fpu(); } void GaugeRenderer::Configure( const char *label, Entity *entity ) { Test_Tell( "GaugeRenderer::Configure('" << label << "', " << entity << ")\n" ); Check(this); Check_Pointer(label); Vector2DOf position; position.x = 0; position.y = 0; Check(interpreter); interpreter->Interpret(label, this, 0, position, entity); Check_Fpu(); }