/*********************************************************************** * * ELMER, A Computational Fluid Dynamics Program. * * Copyright 1st April 1995 - , Center for Scientific Computing, * Finland. * * All rights reserved. No part of this program may be used, * reproduced or transmitted in any form or by any means * without the written permission of CSC. * * Address: Center for Scientific Computing * Tietotie 6, P.O. BOX 405 * 02101 Espoo, Finland * Tel. +358 0 457 2001 * Telefax: +358 0 457 2302 * EMail: Jari.Jarvinen@csc.fi ************************************************************************/ /*********************************************************************** Program: ELMER model file (emf) reader Module: frontlib..cpp Language: C++ Date: 01.10.98 Version: 1.00 Author(s): Martti Verho Revisions: Abstract: Implementation: Parser for ELMER model file (.emf files). ************************************************************************/ using namespace std; #include #include #include #include #include #include #include "frontlib.h" // Elmer MATC do-math call extern "C" char* mtc_domath(char* s); // ************************************************************************* // ************************************************************************* // // START: Library globals // // ************************************************************************* // ************************************************************************* // // Global interface variables // EMF_DECL int emf_ReadMode = 1; EMF_DECL struct emf_ObjectData_X* emf_ObjectData = 0; EMF_DECL char* emf_UnknownData = new char[1 + emf_MAX_STRING_LEN]; // CallBack functions // extern "C" int (*emf_readDataCB) (void** user_data) = 0; extern "C" int (*emf_readMessageCB) (char* msg_buffer) = 0; // Global function definitions // This function creates the reader and starts it // NOTE: It is called by the user! // EMF_DECL int emf_readData(char* in_file_name, void** user_data, int msg_buffer_size, char* msg_buffer, int evaluate_only_matc) { bool eval_only_matc = ( 0 != evaluate_only_matc); LibFrontReader* reader = new LibFrontReader(in_file_name, user_data, msg_buffer_size, msg_buffer, eval_only_matc); int rc = 0; // Ok if ( eval_only_matc ) return rc; if ( reader == NULL || !reader->isOk() || !reader->start() ) { rc = 1; // Error } delete reader; return rc; } // This function is called from the reader. // It calls the CallBack function given by the user // and thus informs about new available data. // int sendData(void** user_data) { return emf_readDataCB(user_data); } // ========================================================================= // END: Library globals // ========================================================================= // ************************************************************************* // ************************************************************************* // START Library locals // ************************************************************************* // ************************************************************************* // Data handling functions // ----------------------- //-Data arries template void setNumericData_impl(T*& target) { if (LibFront::isLogicalData) target = (T*) LibFront::logicalData; else if (LibFront::isIntegerData) target = (T*) LibFront::integerData; else if (LibFront::isRealData) target = (T*) LibFront::realData; } //-Data values by index template void setNumericData_impl(T& target, int value_index) { if (LibFront::isLogicalData) target = (T) LibFront::logicalData[value_index]; else if (LibFront::isIntegerData) target = (T) LibFront::integerData[value_index]; else if (LibFront::isRealData) target = (T) LibFront::realData[value_index]; } //-Variable values template void setNumericVariable_impl(T& target, int value_index) { if (LibFront::isRealVariable) target = (T) LibFront::realVariable[value_index]; } // Data output functions // --------------------- // Scalar data // template ostream& output_scalar_impl(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, const T data, bool quoted) { char QM = '\"'; // Field name if ( field_name != NULL ) { LibFront::output_string(out, indent_size, indent_level, field_name, false); } // Field type if ( field_type != NULL ) { out << endl; LibFront::output_string(out, indent_size, 1 + indent_level, field_type, false); } // If no name/type was output if ( field_name == NULL && field_type == NULL ) { LibFront::indent(out, indent_size, indent_level); // Data right after name/type string } else { out << " "; } //---Possible starting quote if (quoted) out << QM; // Null strings cannot be printed! if ( !(LibFront::ncEqual((char*)field_type, "string")) || data != 0 ) { //---Logical value as True/False if (LibFront::ncEqual((char*)field_type, "logical")) { if (data) out << "True"; else out << "False"; } //---Other data types else { out << data; } } //---Possible ending quote if (quoted) out << QM; out << endl; return out; } // Vector data // template ostream& output_vector_impl(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim, const T* data, bool output_size, bool quoted) { char QM = '\"'; // Field name if ( field_name != NULL ) { LibFront::output_string(out, indent_size, indent_level, field_name, false); } // Field size if (output_size) { out << endl; LibFront::indent(out, indent_size, 1 + indent_level); out << "Size " << dim << endl; } // Field type if (field_type != NULL ) { // If Size is not printed, we need a newline if (!output_size) out << endl; LibFront::output_string(out, indent_size, 2 + indent_level, field_type, false); } if (data == NULL) { return out; } // If no name/type was output if ( field_name == NULL && field_type == NULL ) { LibFront::indent(out, indent_size, indent_level); // Data right after name/type string } else { out << " "; } // Field data after type for (short i = 0; i < dim; i++) { //---Possible starting quote if (quoted) out << QM; // Null strings cannot be printed! if ( !(LibFront::ncEqual((char*)field_type, "string")) || data[i] != 0 ) { //---Logical value as True/Flase if (LibFront::ncEqual((char*)field_type, "logical")) { if ( data[i] ) out << "True"; else out << "False"; } //---Other data types else { out << data[i]; } } //---Possible ending quote if (quoted) out << QM; out << ' '; } out << endl; return out; } // Table data template ostream& output_table_impl(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim1, int dim2, const T** data, bool quoted) { char QM = '\"'; // Field name LibFront::output_string(out, indent_size, indent_level, field_name, true); // Field size LibFront::indent(out, indent_size, 1 + indent_level); out << "Size " << dim1 << " " << dim2 << endl; // Field type if (field_type != NULL ) LibFront::output_string(out, indent_size, 2 + indent_level, field_type, true); if (data == NULL) { return out; } // Data lines after type line for (int i = 0; i < dim1; i++) { LibFront::indent(out, indent_size, 3 + indent_level); for (short j = 0; j < dim2; j++) { out << " "; // Possible starting quote if (quoted) out << QM; // Null strings cannot be printed! if ( !(LibFront::ncEqual((char*)field_type, "string")) || data[i][j] != 0 ) { //---Logical value as True/Flase if (LibFront::ncEqual((char*)field_type, "logical")) { if ( data[i][j] ) out << "True"; else out << "False"; } //---Other data types else { out << data[i][j]; } // Possible ending quote if (quoted) out << QM; } // If data_ij != NULL } // For dim2 out << endl; } // For dim1 return out; } ostream& output_data(ostream& out, char* data_type, void* data) { if (data == NULL) { out << "NULL" << endl; return out; } // Associate to the data according to the data type if ( LibFront::ncEqual(data_type, "logical") ) { out << (int*)data; } else if ( LibFront::ncEqual(data_type, "integer") ) { out << (int*)data; } else if ( LibFront::ncEqual(data_type, "real") ) { out << (double*)data; } else if ( LibFront::ncEqual(data_type, "string") ) { out << (char*)data; } else if ( LibFront::ncEqual(data_type, "file") ) { out << (char*)data; } else { out << "Unknown datatype: " << data_type; } out << endl; return out; } // ========================================================================= // END: Library locals // ========================================================================= // ************************************************************************* // ************************************************************************* // // START: LibFront namespace implementation // // ************************************************************************* // ************************************************************************* // // Data values related flags set in the library by the Reader and // LibFront global data used to transfer data // bool LibFront::isFileData = false; bool LibFront::isIntegerData = false; bool LibFront::isLogicalData = false; bool LibFront::isRealData = false; bool LibFront::isStringData = false; bool LibFront::isVoidData = false; int* LibFront::integerData = NULL; int* LibFront::logicalData = NULL; double* LibFront::realData = NULL; char* LibFront::stringData = NULL; void* LibFront::voidData = NULL; int LibFront::dimension1 = NULL; int LibFront::dimension2 = NULL; int* LibFront::dataLengths = NULL; // Variables related flags set in the library by the Reader and // LibFront global data used to transfer variables // bool LibFront::isRealVariable = false; bool LibFront::isStringVariable = false; bool LibFront::isVoidVariable = false; double* LibFront::realVariable = NULL; char* LibFront::stringVariable = NULL; void* LibFront::voidVariable = NULL; int* LibFront::variableValuesLengths = NULL; char LibFront::stringSeparator = '\"'; char LibFront::matcSeparator = '$'; void LibFront::setStringSeparator(char sep) { stringSeparator = sep; } void LibFront::setMatcSeparator(char sep) { matcSeparator = sep; } // Read file into given buffer // // NOTE: Buffer is allocated in the function! // Skip empty line, comment lines and eol comments // Return: nof chars read or -1 if file not found // int LibFront::readFile(char* filename, char*& buffer, bool skip_comments) { // Initial size int bufferLen = 10000; int bufferPos = 0; buffer = new char[bufferLen]; ifstream inputFile; inputFile.open(filename, ios::in ); if ( inputFile.fail() ) return -1; bool is_string = false; bool skipping_comment = false; bool connecting_line = false; bool is_matc = false; int matc_start = -1; int fcount = 0; char c[1]; // Read file until end-of-file // while ( !inputFile.eof() ) { c[0] = '\0'; inputFile.read(c, 1); if ( c[0] == '\0' ) break; // Continuation marker (slash) irrelevant in a string and in comments if ( c[0] == '/' && !is_string && !skipping_comment) { connecting_line = true; } // String marker irrelevant in comments and after continuation marker if ( c[0] == stringSeparator && !(skipping_comment || connecting_line) ) { is_string = !is_string; } // Comment symbols irrelevant in strings if ( (c[0] == '!' || c[0] == '#') && skip_comments && !is_string) { skipping_comment = true; } // What newline means if ( c[0] == '\n' && skip_comments) { skipping_comment = false; // If we are connecting strings or we have an open string, // do not store the newline character if (connecting_line || is_string) { connecting_line = false; continue; } } // Skip carrage returns // NOTE: This way wwe can read dos-files (CR-LF) also in Unix // NOTE: Keep this after newline-handling, so that Dos files // are not ruined under Win32! if ( c[0] == '\r' && skip_comments) { continue; } // Comments and characters after continuation marker // in the same line can be skipped! if ( skipping_comment || connecting_line ) { continue; } // Allocate larget buffer is needed if ( fcount >= bufferLen - 1 ) { char* tmp = new char[bufferLen + 5000]; for (int i = 0; i < bufferLen; i++) tmp[i] = buffer[i]; bufferLen += 5000; delete[] buffer; buffer = tmp; } // Copy storable character to the buffer buffer[fcount++] = c[0]; } // While !eof inputFile.close(); // Check that data ends with eol! if ( buffer[fcount-1] != '\n' ) { buffer[fcount++] = '\n'; } // Actual buffer size buffer[fcount] = '\0'; return fcount; } // Read a Matc-expression from the source, starting from source_pos // Return source-position after reading the expression // NOTE: Source is NOT moved to this position actually, but the client // can use this return value if its wants to advandec the source! // int LibFront::readMatcExpression(char* source, int source_pos, int source_end, char* result, int max_result_len, bool skip_comments) { int i,j; static char matc_peek_buffer[10001]; bool is_string = false; bool skipping_comment = false; bool connecting_line = false; bool is_matc_end = false; bool is_matc_def = false; bool is_matc_func = false; bool check_matc_func = false; bool check_matc_end = false; int read_count = 0; int result_pos = 0; int matc_peek_pos = 0; int matc_lb_count = 0; int matc_rb_count = 0; int matc_lp_count = 0; int matc_rp_count = 0; char c_1 = '\0'; // Previous character char c = '\0'; // Current character // Read matc-expression in the result-buffer // advance the source-buffer to the end of the expression // while (true) { if ( source_pos >= source_end ) break; if ( result_pos >= max_result_len ) break; c = source[source_pos++]; read_count++; // NOTE: We want to check if first non-blank text after $-sign // 'function' if ( matc_peek_pos < 10000 && c != ' ' ) { matc_peek_buffer[matc_peek_pos++] = c; } // Matc marker ($) is irrelevant in comments if ( c == matcSeparator && !skipping_comment) { is_matc_end = true; break; } if ( c == '\0' ) { check_matc_end = true; } // Continuation marker (slash) irrelevant in a string and in comments if ( c == '/' && !is_string && !skipping_comment) { connecting_line = true; } // Matc separators // // Left brace if ( c == '{' ) { matc_lb_count += 1; if ( matc_lb_count == 1 ) { check_matc_func = true; } // Right brace } else if ( c == '}' ) { matc_rb_count += 1; check_matc_end = true; // Left parenthesis } else if ( c == '(' ) { matc_lp_count += 1; if ( matc_lp_count == 1 ) { check_matc_func = true; } // Right parenthesis } else if ( c == ')' ) { matc_rp_count += 1; // Sign '=' is a definition, if lp==rp } else if ( c == '=' && matc_lp_count == matc_rp_count) { is_matc_def = true; // If not a definition, could be at end when lp==rp or when something // non-ws which is not =-sign // } else if ( !is_matc_def && (c != '=' && c != ' ' && c != '\t') && (c_1 == ' ' || c_1 == '\t' || matc_lp_count > 0) && matc_lp_count == matc_rp_count) { check_matc_end = true; } // If we have the 'function' if ( check_matc_func ) { matc_peek_buffer[8] = '\0'; if ( LibFront::in("function", matc_peek_buffer) ) { is_matc_func = true; } } // String marker (toggle) if ( c == stringSeparator && !(skipping_comment || connecting_line) ) { is_string = !is_string; } // Comment symbols irrelevant in strings if ( (c == '!' || c == '#') && skip_comments && !is_string) { skipping_comment = true; } // What newline means if ( c == '\n' ) { check_matc_end = true; skipping_comment = false; // If we are connecting strings or we have an open string, // do not store the newline character if (connecting_line || is_string) { connecting_line = false; continue; } } // Skip carrage returns // NOTE: This way we can read dos-files (CR-LF) also in Unix // NOTE: Keep this test after newline-handling, so that Dos files // are not ruined under Win32! if ( c == '\r' ) { continue; } // Comments and characters after continuation marker // in the same line can be skipped! if ( skipping_comment || connecting_line ) { continue; } // If the matc-expression is possibly at end if ( check_matc_end ) { // If we have the 'function' matc_peek_buffer[8] = '\0'; if ( LibFront::in("function", matc_peek_buffer) ) { is_matc_func = true; } if ( !is_string && ( matc_lb_count == matc_rb_count && matc_lp_count == matc_rp_count && ( (is_matc_func && matc_lb_count > 0) || !is_matc_func ) ) ) { is_matc_end = true; } // If comments are not skipped, keep also the separating linefeeds! if ( !skip_comments && read_count == 1 && c == '\n' ) { result[result_pos++] = c; break; } } // if check matc-end // When to store the charcter into result if ( !is_matc_end || c == ')' || c == '}' ) { result[result_pos++] = c; } if ( is_matc_end ) { // Move source backwards if we have been peeking too much to see // the end of the expression!!! // if ( c != ')' && c != '}' && c_1 == ' ' || c_1 == '\t' ) { while ( source[source_pos] != ' ' && source[source_pos] != '\t' ) { source_pos--; } } break; } // Store previous character c_1 = c; } result[result_pos] = '\0'; // Return the source position just after the expression // return source_pos; } // Init Matc output format to 'plain' (ie. no Columns through) mode // Precision set to 8 // void LibFront::initMatcFrmt() { char matc_frmt[] = "format(8,\"rowform\")"; mtc_domath( matc_frmt ); } // Check that a Matc error message is Tcl-printable void LibFront::formatMatcError(char* err_msg) { // NOTE Tcl does not like [] !!! for(int i = 0; i < strlen(err_msg); i++) { if ( err_msg[i] == '[' ) err_msg[i] = ' '; if ( err_msg[i] == ']' ) err_msg[i] = ' '; } } // Check if the string is a matc function or variable definition // // NOTE: Whitespace must have been trimmed from 'str' before calling // this function // bool LibFront::isMatcDefinition(const char* str) { static char buffer[9]; int i; // Empty string or a comment or lf if ( str == NULL || str[0] == '\0' || str[0] == '!' || str[0] == '#' || str[0] == '\n' ) return false; char* tmp = (char*)str; // Skip possible Matc-separator ($) if ( tmp[0] == matcSeparator ) tmp++; // Pick first 8 charcaters for (i = 0; i < 8; i++) { buffer[i] = tmp[i]; } buffer[8] = '\0'; toLower(buffer); // Function definition if ( 0 == strncmp(buffer, "function", 8) ) return true; // Variable definition for (i = 0; i < strlen(tmp); i++) { if ( tmp[i] == '=' ) return true; } return false; } // Checks if the string has matc variables // // NOTE: Whitespace must have been trimmed from 'str' before calling // this function // bool LibFront::hasMatcVariables(const char* str) { if ( LibFront::isMatcDefinition(str) ) return false; int i; // Empty string or a comment or lf if ( str == NULL || str[0] == '\0' || str[0] == '!' || str[0] == '#' || str[0] == '\n' ) return false; // Contains a variable name for (i = 0; i < strlen(str); i++) { if ( isalpha(str[i]) ) return true; } return false; } // Get a function or variable name from a Matc definition // // NOTE: Whitespace must have been trimmed from 'str' before calling // this function // bool LibFront::getMatcName(const char* str, char* name_buffer, int max_len, bool& is_var, bool& is_func) { static char buffer[9]; int i, j; is_var = false; is_func = false; name_buffer[0] = '\0'; if ( !LibFront::isMatcDefinition(str) ) return false; char* tmp = (char*)str; // Skip possible Matc-separator ($) if ( tmp[0] == matcSeparator ) tmp++; // Pick first 8 characters to check if this // is a function definition for (i = 0; i < 8; i++) { buffer[i] = tmp[i]; } buffer[8] = '\0'; toLower(buffer); //--Function definition if ( 0 == strncmp(buffer, "function", 8) ) { tmp += 8; int start_pos = 0; LibFront::trimLeft(tmp, strlen(tmp), start_pos, true); tmp += start_pos; // Find function name end int len = 0; while (tmp[len] != '(' && tmp[len] != ' ' && tmp[len] != '\t' && tmp[len] != '\n' ) len++; // Copy name for (j = 0; j < len && j < max_len; j++) { name_buffer[j] = tmp[j]; } name_buffer[j] = '\0'; is_func = true; return true; } //--Variable definition for (i = 0; i < strlen(tmp); i++) { if ( tmp[i] == '=' ) { // Find function name end int len = 0; while (tmp[len] != '=' && tmp[len] != ' ' && tmp[len] != '\t' && tmp[len] != '\n' ) len++; // Copy name for (j = 0; j < len && j < max_len; j++) { name_buffer[j] = tmp[j]; } name_buffer[j] = '\0'; is_var = true; return true; } } return false; } // Check if result is a Matc error // // NOTE: Whitespace must have been trimmed from 'str' before calling // this function // bool LibFront::isMatcError(const char* str) { static char buffer[11]; int i; if ( str == NULL || str[0] == '\0' ) return false; int len = 10; // Pick first 10 charcaters for (i = 0; i < len; i++) { buffer[i] = str[i]; } buffer[len] = '\0'; toUpper(buffer); if ( 0 == strncmp("MATC ERROR", buffer, len) ) { return true; } else { return false; } } // Evaluate a string containing Matc-expressions // // char* LibFront::evalMatcString(const char* str) { if ( str == NULL || str[0] == '\0' ) return NULL; int len = strlen(str); char* buffer = new char[1+len]; strcpy(buffer, str); for (int i = 0; i < len; i++) { if ( buffer[i] == matcSeparator ) { buffer[i] = ' '; } } char* res = mtc_domath(buffer); delete[] buffer; if ( isMatcError(res) ) return NULL; return res; } //--Data reading functions void LibFront::setNumericData(bool*& target) { setNumericData_impl(target); } void LibFront::setNumericData(int*& target) { setNumericData_impl(target); } void LibFront::setNumericData(long*& target) { setNumericData_impl(target); } void LibFront::setNumericData(float*& target) { setNumericData_impl(target); } void LibFront::setNumericData(double*& target) { setNumericData_impl(target); } void LibFront::setStringData(char*& buffer) { buffer = stringData; } void LibFront::setNumericData(bool& target, int value_index) { setNumericData_impl(target, value_index); } void LibFront::setNumericData(int& target, int value_index) { setNumericData_impl(target, value_index); } void LibFront::setNumericData(long& target, int value_index) { setNumericData_impl(target, value_index); } void LibFront::setNumericData(float& target, int value_index) { setNumericData_impl(target, value_index); } void LibFront::setNumericData(double& target, int value_index) { setNumericData_impl(target, value_index); } // NOTE: Buffer size must be large enough for the result! // void LibFront::setStringData(char* buffer, int value_index) { // Starting position in variable values string int start_pos = 0; for (int i = 0; i < value_index; i++) start_pos += dataLengths[i]; // Copy string referred by the value_index int size = dataLengths[value_index]; char* source = stringData + start_pos; strncpy(buffer, source, size); // End mark buffer[size] = '\0'; } // NOTE: 'strings' argument is allocated here! // void LibFront::setStringData(int nof_strings, char**& strings) { strings = NULL; if ( nof_strings == 0 ) return; strings = new char*[nof_strings]; for (int i = 0; i < nof_strings; i++) { int len = dataLengths[i]; strings[i] = new char[1 + len]; setStringData(strings[i], i); } } void LibFront::setNumericVariable(bool& target, int value_index) { setNumericVariable_impl(target, value_index); } void LibFront::setNumericVariable(int& target, int value_index) { setNumericVariable_impl(target, value_index); } void LibFront::setNumericVariable(long& target, int value_index) { setNumericVariable_impl(target, value_index); } void LibFront::setNumericVariable(float& target, int value_index) { setNumericVariable_impl(target, value_index); } void LibFront::setNumericVariable(double& target, int value_index) { setNumericVariable_impl(target, value_index); } void LibFront::setStringVariable(char* buffer, int value_index) { // Starting position in varaible values string int start_pos = 0; for (int i = 0; i < value_index; i++) start_pos += variableValuesLengths[i]; // Copy string referred by the value_index int size = variableValuesLengths[value_index]; char* source = stringVariable + start_pos; strncpy(buffer, source, size); // End mark buffer[size] = '\0'; } //--Field output functions // Shorthand for "is_name" function bool LibFront::in(const char* field_name, const char* test_name) { return LibFront::ncEqual((char*)field_name, (char*)test_name); } // Simple strin (field name etc.) ostream& LibFront::output_string(ostream& out, short indent_size, short indent_level, const char* field_name, bool add_eol) { LibFront::indent(out, indent_size, indent_level); out << field_name; if ( add_eol ) { out << endl; } return out; } // Callable cover functions // ======================== ostream& LibFront::output_matcDef(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, const char* def, bool add_dsign) { strstream strm; if ( add_dsign ) { strm << '$'; } strm << def << ends; return LibFront::output_scalar(out, indent_size, indent_level, field_name, field_type, strm.str(), false); } // Scalar data ostream& LibFront::output_scalar(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, const bool data) { return output_scalar_impl(out, indent_size, indent_level, field_name, field_type, data, false); } ostream& LibFront::output_scalar(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, const short data) { return output_scalar_impl(out, indent_size, indent_level, field_name, field_type, data, false); } ostream& LibFront::output_scalar(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, const int data) { return output_scalar_impl(out, indent_size, indent_level, field_name, field_type, data, false); } ostream& LibFront::output_scalar(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, const long data) { return output_scalar_impl(out, indent_size, indent_level, field_name, field_type, data, false); } ostream& LibFront::output_scalar(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, const float data) { return output_scalar_impl(out, indent_size, indent_level, field_name, field_type, data, false); } ostream& LibFront::output_scalar(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, const double data) { return output_scalar_impl(out, indent_size, indent_level, field_name, field_type, data, false); } ostream& LibFront::output_scalar(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, const char* data, bool quoted) { return output_scalar_impl(out, indent_size, indent_level, field_name, field_type, data, quoted); } // Vector data ostream& LibFront::output_vector(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim, const bool* data, bool output_size) { return output_vector_impl(out, indent_size, indent_level, field_name, field_type, dim, data, output_size, false); } ostream& LibFront::output_vector(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim, const short* data, bool output_size) { return output_vector_impl(out, indent_size, indent_level, field_name, field_type, dim, data, output_size, false); } ostream& LibFront::output_vector(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim, const int* data, bool output_size) { return output_vector_impl(out, indent_size, indent_level, field_name, field_type, dim, data, output_size, false); } ostream& LibFront::output_vector(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim, const long* data, bool output_size) { return output_vector_impl(out, indent_size, indent_level, field_name, field_type, dim, data, output_size, false); } ostream& LibFront::output_vector(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim, const float* data, bool output_size) { return output_vector_impl(out, indent_size, indent_level, field_name, field_type, dim, data, output_size, false); } ostream& LibFront::output_vector(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim, const double* data, bool output_size) { return output_vector_impl(out, indent_size, indent_level, field_name, field_type, dim, data, output_size, false); } ostream& LibFront::output_vector(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim, const char** data, bool output_size, bool quoted) { return output_vector_impl(out, indent_size, indent_level, field_name, field_type, dim, data, output_size, quoted); } // Table data ostream& LibFront::output_table(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim1, int dim2, const bool** data) { return output_table_impl(out, indent_size, indent_level, field_name, field_type, dim1, dim2, data, false); } ostream& LibFront::output_table(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim1, int dim2, const short** data) { return output_table_impl(out, indent_size, indent_level, field_name, field_type, dim1, dim2, data, false); } ostream& LibFront::output_table(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim1, int dim2, const int** data) { return output_table_impl(out, indent_size, indent_level, field_name, field_type, dim1, dim2, data, false); } ostream& LibFront::output_table(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim1, int dim2, const long** data) { return output_table_impl(out, indent_size, indent_level, field_name, field_type, dim1, dim2, data, false); } ostream& LibFront::output_table(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim1, int dim2, const float** data) { return output_table_impl(out, indent_size, indent_level, field_name, field_type, dim1, dim2, data, false); } ostream& LibFront::output_table(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim1, int dim2, const double** data) { return output_table_impl(out, indent_size, indent_level, field_name, field_type, dim1, dim2, data, false); } ostream& LibFront::output_table(ostream& out, short indent_size, short indent_level, const char* field_name, const char* field_type, int dim1, int dim2, const char*** data, bool quoted) { return output_table_impl(out, indent_size, indent_level, field_name, field_type, dim1, dim2, (const char**)data, quoted); } //**************** // Other utilities //**************** // Check if string is a number using atof bool LibFront::isNumber(const char* str) { if ( str == NULL || str[0] == '\0' ) return false; int len = strlen(str); int index = 0; char* tmp = (char*)str; // Skip +/- sign if (tmp[0] == '-' || tmp[0] == '+' ) { tmp++; index++; } // Digits before decimal point are missing! if ( index == len || !isdigit(tmp[0]) ) return false; // Skip digits before deciaml point while ( index < len && isdigit(tmp[0]) ) { tmp++; index++; } // OK: [+-]{digits} if ( index == len ) return true; // Skip decimal point if ( tmp[0] == '.' ) { tmp++; index++; } // Skip digits after decimal point while ( index < len && isdigit(tmp[0]) ) { tmp++; index++; } // OK: [+-]{digits}.{digits} if ( index == len ) return true; // Skip exponent indicator if ( tmp[0] == 'E' || tmp[0] == 'e' || tmp[0] == 'D' || tmp[0] == 'd' ) { tmp++; index++; // Anything else is non-numeric! } else { return false; } // Digits after exponent are missing! if ( index == len ) return false; // Skip +/- exponent's sign if (tmp[0] == '-' || tmp[0] == '+' ) { tmp++; index++; } // Digits after exponent's sign are missing! if ( index == len || !isdigit(tmp[0]) ) return false; // Skip exponent's digits while ( index < len && isdigit(tmp[0]) ) { tmp++; index++; } // Now we should be at the end! // Not --> Error if ( index < len ) return false; // Yes --> OK else return true; } // Compare two string (non-case sensitive) // If string are same returns: true // otherwise: false bool LibFront::ncEqual(char* str1, char* str2) { if ( str1 == NULL || str2 == NULL ) { return false; } int i; int len1 = strlen(str1); int len2 = strlen(str2); if (len1 != len2) return false; for (i = 0; i < len1; i++) if ( toupper(str1[i]) != toupper(str2[i]) ) return false; return true; } // Compare partially (according to the lengt of str2) // two strings (non-case sensitive). // If string are same returns: true // otherwise: false bool LibFront::ncEqualPartial(char* str1, char* str2) { int i; int len1 = strlen(str1); int len2 = strlen(str2); if (len1 < len2) return false; for (i = 0; i < len2; i++) if ( toupper(str1[i]) != toupper(str2[i]) ) return false; return true; } // Indent stream by putting spaces into it ostream& LibFront::indent(ostream& out, short indent_size, short indent_level) { for (int i = 0; i < indent_size * indent_level; i++) out << ' '; return out; } // Make a "indented" string by putting enough spaces into it char* LibFront::indent(short indent_size, short indent_level) { const int MAX_INDENT = 80; static char buffer[1 + MAX_INDENT]; int indent = indent_size * indent_level; if (indent > MAX_INDENT) indent = MAX_INDENT; for (int i = 0; i < indent; i++) buffer[i] = ' '; buffer[indent] = '\0'; return buffer; } char* LibFront::trim(char* buffer, bool trim_nl) { LibFront::trimLeft(buffer, trim_nl); LibFront::trimRight(buffer, trim_nl); return buffer; } // Remove leading whitespace char* LibFront::trimLeft(char* buffer, bool trim_nl) { int len = strlen(buffer); if ( len == 0) return buffer; int pos = 0; if ( trim_nl ) { while (buffer[pos] == '\t' || buffer[pos] == ' ' || buffer[pos] == '\n' ) { if (++pos == len) break; } } else { while (buffer[pos] == '\t' || buffer[pos] == ' ' ) { if (++pos == len) break; } } if (pos == 0) return buffer; // Start copying "back" from the first non-space position strcpy(buffer, buffer + pos); buffer[len-pos] = '\0'; return buffer; } // Remove trailing whitespace char* LibFront::trimRight(char* buffer, bool trim_nl) { int len = strlen(buffer); if ( len == 0) return buffer; // Put NULL after the last non-spce character in the buffer int pos = len - 1; if ( trim_nl ) { while (buffer[pos] == ' ' || buffer[pos] == '\t' || buffer[pos] == '\n' ) { buffer[pos] = '\0'; if (--pos < 0) break; } } else { while (buffer[pos] == '\t' || buffer[pos] == ' ' ) { buffer[pos] = '\0'; if (--pos < 0) break; } } return buffer; } // Find first non-ws position in the string // void LibFront::trimLeft(const char* str, int max_pos, int& start_pos, bool trim_nl) { // Pass by white-space at the end of the string while (1) { if (start_pos >= max_pos) break; char c = str[start_pos]; if ( trim_nl ) { if (c != ' ' && c != '\t' && c != '\n' ) break; } else { if (c != ' ' && c != '\t' ) break; } start_pos++; } } // Find last non-ws position in the string // void LibFront::trimRight(const char* str, int min_pos, int& end_pos, bool trim_nl) { // Pass by white-space at the end of the string while (1) { if (end_pos <= min_pos) break; char c = str[end_pos]; if ( trim_nl ) { if (c != ' ' && c != '\t' && c != '\n' ) break; } else { if (c != ' ' && c != '\t' ) break; } end_pos--; } } char* LibFront::toLower(char* str) { int i, len; len = strlen(str); for (i =0; i < len; i++) { str[i] = tolower(str[i]); } return str; } char* LibFront::toLower(const char* source, char* target) { int i, len; len = strlen(source); for (i =0; i <= len; i++) { target[i] = tolower(source[i]); } return target; } char* LibFront::toUpper(char* str) { int i, len; len = strlen(str); for (i =0; i < len; i++) { str[i] = toupper(str[i]); } return str; } char* LibFront::toUpper(const char* source, char* target) { int i, len; len = strlen(source); for (i =0; i <= len; i++) { target[i] = toupper(source[i]); } return target; } #if 0 // FILL GLOBAL FIELD NAME TABLE // NOTE: This is strictly internal function // bool deleteFieldInfoTable() { if (FieldInfoTable == NULL) { FieldInfoTableSize = 0; return true; } for (int i = 0; i < FieldInfoTableSize; i++) delete FieldInfoTable[i]; delete[] FieldInfoTable; FieldInfoTableSize = 0; return true; } bool LibFront::createFieldInfoTable(int table_size) { // Delete possible old table deleteFieldInfoTable(); if (table_size <= 0) return false; // Allocate new table FieldInfoTable = new FieldInfo*[table_size]; FieldInfoTableSize = table_size; for (int i = 0; i < table_size; i++) FieldInfoTable[i] = NULL; return true; } #endif // ========================================================================= // END: LibFront namespace implementation // ========================================================================= // ************************************************************************* // ************************************************************************* // // START: LibFrontReaderFlags class implementation // // ************************************************************************* // ************************************************************************* // LibFrontReaderFlags::LibFrontReaderFlags() { init(); } LibFrontReaderFlags::LibFrontReaderFlags(LibFrontReaderFlags& flags) { copy(flags); } void LibFrontReaderFlags::copy(LibFrontReaderFlags& flags) { nonSizedDataAtEnd = flags.nonSizedDataAtEnd; canSkipSpace = flags.canSkipSpace; canSkipNewline = flags.canSkipNewline; endsField = flags.endsField; endsObject = flags.endsObject; equalSignPeeked = flags.equalSignPeeked; hasEvaluatedBuffer = flags.hasEvaluatedBuffer; matcPeeked = flags.matcPeeked; newlinePeeked = flags.newlinePeeked; hangingFieldNameNumber = flags.hangingFieldNameNumber; readingEndMarkedData = flags.readingEndMarkedData; readingFieldData = flags.readingFieldData; readingFileName = flags.readingFileName; readingGroupNames = flags.readingGroupNames; readingNonSizedData = flags.readingNonSizedData; readingProcedureName = flags.readingProcedureName; startsNewField = flags.startsNewField; startsNewObject = flags.startsNewObject; } void LibFrontReaderFlags::init() { nonSizedDataAtEnd = false; canSkipSpace = false; canSkipNewline = false; endsField = false; endsObject = false; equalSignPeeked = false; hasEvaluatedBuffer = false; matcPeeked = false; newlinePeeked = false; hangingFieldNameNumber = false; readingEndMarkedData = false; readingFieldData = false; readingFileName = false; readingGroupNames = false; readingNonSizedData = false; readingProcedureName = false; startsNewField = false; startsNewObject = false; } // ========================================================================= // END: LibFrontReaderFlags class implementation // ========================================================================= // ************************************************************************* // ************************************************************************* // START: LibFrontReader class implementation // ************************************************************************* // ************************************************************************* // LibFrontReader::LibFrontReader(char* filename, void** user_data, int msg_buffer_size, char* msg_buffer, bool is_matc_file) { readerOk = true; matcDefsWarned = false; inputFileName = new char[1 + strlen(filename)]; strcpy(inputFileName, filename); // Attach stream to the file inputFile.open(inputFileName); inputFile.close(); msgBufferSize = msg_buffer_size; msgBuffer = msg_buffer; stringSeparator = '\"'; matcSeparator = '$'; // Read file data into the readBuffer array (comments cleaned) readBufferPos = 0; readBufferLen = LibFront::readFile(inputFileName, readBuffer); // Read file data into the readBuffer array (comments cleaned) if ( readBufferLen <= 0 ) { readerOk = false; } if ( is_matc_file ) { if ( readerOk ) { evalMatcBuffer(readBuffer); } return; } dataBuffer = NULL; dataBufferSize = 0; dataLengths = NULL; dataAsStringBuffer[0] = '\0'; dataAsStringPos = 0; dimension1 = 1; dimension2 = 1; evaluatedBufferEnd = -1; nameBuffer = new char[1 + emf_MAX_NAME_LEN]; nameBufferMaxLen = emf_MAX_NAME_LEN; //nameBufferLen = 0; nofEntries = 0; nofVariables = 0; //tokenBuffer = new char[1 + emf_MAX_NAME_LEN]; tokenBufferMaxLen = emf_MAX_NAME_LEN; tokenBufferLen = 0; userData = user_data; variableBuffer = NULL; variableBufferSize = 0; variableLengths = NULL; currentFlagsIndex = 0; flags = &flagsStack[currentFlagsIndex]; } LibFrontReader::~LibFrontReader() { inputFile.close(); delete[] inputFileName; delete[] nameBuffer; delete[] readBuffer; delete_data_buffer(); delete_variable_buffer(); } bool LibFrontReader::allocate_data_buffer(int current_size, int new_size) { if (new_size == 0) { delete_data_buffer(); return true; } void* new_buffer = NULL; int i; switch (dataBufferType) { case LibFront::EMF_INTEGER: case LibFront::EMF_LOGICAL: { int* new_data = new int[new_size]; for (i = 0; i < current_size; i++) new_data[i] = ((int*)dataBuffer)[i]; new_buffer = new_data; } break; case LibFront::EMF_REAL: { double* new_data = new double[new_size]; for (i = 0; i < current_size; i++) new_data[i] = ((double*)dataBuffer)[i]; new_buffer = new_data; } break; case LibFront::EMF_STRING: case LibFront::EMF_FILE: { char* new_data = new char[1 + new_size]; new_data[new_size] = '\0'; for (i = 0; i < current_size; i++) new_data[i] = ((char*)dataBuffer)[i]; new_buffer = new_data; } break; } // Delete old buffer and set the new buffer delete_data_buffer(); dataBufferSize = new_size; dataBuffer = new_buffer; return true; } // NOTE: Variable values are either Reals or Strings bool LibFrontReader::allocate_variable_buffer(int current_size, int new_size) { if (new_size == 0) { delete_variable_buffer(); return true; } void* new_buffer = NULL; int i; switch (variableBufferType) { case LibFront::EMF_REAL: { double* new_data = new double[new_size]; for (i = 0; i < current_size; i++) new_data[i] = ((double*)variableBuffer)[i]; new_buffer = new_data; } break; case LibFront::EMF_STRING: { char* new_data = new char[1 + new_size]; new_data[new_size] = '\0'; for (i = 0; i < current_size; i++) new_data[i] = ((char*)variableBuffer)[i]; new_buffer = new_data; } break; } // Delete old buffer and set new delete_variable_buffer(); variableBufferSize = new_size; variableBuffer = new_buffer; return true; } bool LibFrontReader::appendReadBuffer(char c, int& bufferPos, bool init) { int i,j; char* matc_result; static char matc_buffer[10001]; static bool is_string = false; static bool skipping_comment = false; static bool connecting_line = false; static bool is_matc = false; static bool is_matc_def = false; static bool is_matc_func = false; static int matc_start = -1; static int matc_peek_pos = 0; static int matc_lb_count = 0; static int matc_rb_count = 0; static int matc_lp_count = 0; static int matc_rp_count = 0; if ( init ) { is_string = false; skipping_comment = false; connecting_line = false; is_matc = false; is_matc_func = false; is_matc_def = false; matc_start = -1; matc_peek_pos = 0; matc_lb_count = 0; matc_rb_count = 0; matc_lp_count = 0; matc_rp_count = 0; } bool check_matc_func = false; bool check_matc_end = false; bool do_matc = false; // NOTE: We want to check if first non-blank text after $-sign // 'function' if ( is_matc && matc_peek_pos < 10000 && c != ' ' ) { matc_buffer[matc_peek_pos++] = c; } // Matc marker ($) is irrelevant in a string and in comments //if ( c == '$' && !is_string && !skipping_comment) { if ( c == '$' && !skipping_comment) { if ( is_matc ) { do_matc = true; } is_matc = true; is_matc_def = false; is_matc_func = false; matc_start = bufferPos; matc_lb_count = 0; matc_rb_count = 0; matc_lp_count = 0; matc_rp_count = 0; matc_peek_pos = 0; return true; } if ( c == '\0' ) { check_matc_end = true; if ( is_matc ) { do_matc = true; } } // Continuation marker (slash) irrelevant in a string and in comments if ( c == '/' && !is_string && !skipping_comment) { connecting_line = true; } // Matc separators // if ( is_matc ) { // Left brace if ( c == '{' ) { matc_lb_count += 1; if ( matc_lb_count == 1 ) { check_matc_func = true; } // Right brace } else if ( c == '}' ) { matc_rb_count += 1; check_matc_end = true; // Left parenthesis } else if ( c == '(' ) { matc_lp_count += 1; if ( matc_lp_count == 1 ) { check_matc_func = true; } // Right parenthesis } else if ( c == ')' ) { matc_rp_count += 1; // Sign '=' is a definition, if lp==rp } else if ( c == '=' && matc_lp_count == matc_rp_count) { is_matc_def = true; // If a definition, could be at end when lp==rp } else if ( !is_matc_def && (c != '=' && c != ' ' && c != '\t') && matc_lp_count > 0 && matc_lp_count == matc_rp_count) { check_matc_end = true; } } // If we have the 'function' after $-sign if ( check_matc_func ) { matc_buffer[8] = '\0'; if ( LibFront::in("function", matc_buffer) ) { is_matc_func = true; } } // String marker irrelevant in comments and after continuation marker if ( c == stringSeparator && !(skipping_comment || connecting_line) ) { if ( is_string && is_matc ) { do_matc = true; is_string = false; } else { is_string = !is_string; } } // Comment symbols irrelevant in strings if ( (c == '!' || c == '#') && !is_string) { skipping_comment = true; } // What newline means if ( c == '\n' ) { check_matc_end = true; skipping_comment = false; // If we are connecting strings or we have an open string, // do not store the newline character if (connecting_line || is_string) { connecting_line = false; return true; } } // Skip carrage returns // NOTE: This way we can read dos-files (CR-LF) also in Unix // NOTE: Keep this test after newline-handling, so that Dos files // are not ruined under Win32! if ( c == '\r' ) { return true; } // Comments and characters after continuation marker // in the same line can be skipped! if ( skipping_comment || connecting_line ) { return true; } // If the matc-expression is possibly at end if ( is_matc && check_matc_end ) { // If we have the 'function' first after $-sign matc_buffer[8] = '\0'; if ( LibFront::in("function", matc_buffer) ) { is_matc_func = true; } if ( !is_string && ( matc_lb_count == matc_rb_count && matc_lp_count == matc_rp_count && ( (is_matc_func && matc_lb_count > 0) || !is_matc_func ) ) ) { do_matc = true; } } // Allocate larger buffer is needed if ( bufferPos >= readBufferLen - 1 ) { char* tmp = new char[readBufferLen + 5000]; for (int i = 0; i < readBufferLen; i++) tmp[i] = readBuffer[i]; readBufferLen += 5000; delete[] readBuffer; readBuffer = tmp; } // Copy storable character to the buffer readBuffer[bufferPos++] = c; // Evaluate a Matc-expression // ------------------------ if ( do_matc ) { // Copy all matc-stuff to the matc-buffer for (i = matc_start; i < bufferPos; i++) { matc_buffer[i-matc_start] = readBuffer[i]; } matc_buffer[bufferPos - matc_start] = '\0'; // EVALUATE Matc // matc_result = mtc_domath(matc_buffer); // If Matc-ERROR // if ( matc_result != NULL && 0 == strncmp(matc_result, "MATC ERROR", 10 ) ) { // NOTE Tcl does not like [] !!! for(j = 0; j < strlen(matc_result); j++) { if ( matc_result[j] == '[' ) matc_result[j] = ' '; if ( matc_result[j] == ']' ) matc_result[j] = ' '; } if ( matc_result != NULL ) { sendMessage(matc_result); sendMessage(matc_buffer); } is_matc = false; matc_start = -1; return false; } bufferPos = matc_start; is_matc = false; matc_start = -1; // If a Matc-expression result, insert result into read buffer // to be read 'normally' // for (i = 0; matc_result != NULL && i < strlen(matc_result); i++) { appendReadBuffer(matc_result[i], bufferPos, false); } return true; } return true; } bool LibFrontReader::bufferAtEnd() { if ( readBufferPos >= readBufferLen || readBuffer[readBufferPos] == '\0' ) { return true; } else { return false; } } // NOTE: Equal sign (=) is also considered as white space! // void LibFrontReader::bufferEatWs() { // Skip spaces, tabs, newlines and equal sign // // NOTE: checkReadBuffer() handles also newlines while ( checkReadBuffer() && ( readBuffer[readBufferPos] == ' ' || readBuffer[readBufferPos] == '\t' || readBuffer[readBufferPos] == '\n' || readBuffer[readBufferPos] == '=' ) ) { readBufferPos++; } } // NOTE: Equal sign (=) is also considered as white space! // NOTE: This version checks if an equal sign (token at end) or // a newline was eaten (ie. data ended with a newline) // void LibFrontReader::bufferEatWs(bool& eq_eaten, bool& nl_eaten) { eq_eaten = false; nl_eaten = false; // Skip spaces, tabs, newlines and equal sign // // NOTE: checkReadBuffer() handles also newlines while ( checkReadBuffer() && ( readBuffer[readBufferPos] == ' ' || readBuffer[readBufferPos] == '\t' || readBuffer[readBufferPos] == '\n' || readBuffer[readBufferPos] == '=' ) ) { if ( readBuffer[readBufferPos] == '=' ) { eq_eaten = true; } if ( readBuffer[readBufferPos] == '\n' ) { nl_eaten = true; } readBufferPos++; } } bool LibFrontReader::case_compare(char* str1, char* str2) { int len1 = strlen(str1); int len2 = strlen(str2); if (len1 =! len2) return false; for (int i = 0; i < len1; i++) { if ( str1[i] != str2[i] ) return false; } return true; } // Check if read buffer is at end // bool LibFrontReader::checkReadBuffer() { if ( bufferAtEnd() ) { return false; } bool ok = true; char c = readBuffer[readBufferPos]; if ( c == '\n' ) { ok = handleEol(); } if (bufferAtEnd()) { return false; } return ok; } void LibFrontReader::constructStringFromTokens(char* buffer, int nof_string_tokens) { char* tmp = buffer; for (int i = 0; i < nof_string_tokens; i++) { int old_len = strlen(tmp); getNextToken(tmp + old_len); int new_len = strlen(tmp); // Add space separator between tokens if (i < nof_string_tokens - 1) { tmp[new_len] = ' '; tmp[++new_len] = '\0'; tmp += new_len - old_len; } } } bool LibFrontReader::data_at_end() { bool at_end = false; //-these need two strings if ( flags->readingFileName || flags->readingProcedureName) { if (nofEntries == 2) at_end = true; //-if data end is marked with "End" } else if ( flags->readingEndMarkedData ) { //if ( next_is_text("end") ) if ( next_is_end_keyword() ) at_end = true; //-if there is not following a string starting with quote } else if ( !flags->readingEndMarkedData && flags->readingNonSizedData ) { if ( !next_is_text("\"") ) at_end = true; //-otherwise dimensions define data size // and it is always read to the end } else { at_end = true; } return at_end; } void LibFrontReader::delete_data_buffer() { if (dataBuffer == NULL) return; switch (dataBufferType) { case LibFront::EMF_INTEGER: case LibFront::EMF_LOGICAL: delete[] (int*)dataBuffer; break; case LibFront::EMF_REAL: delete[] (double*)dataBuffer; break; case LibFront::EMF_STRING: case LibFront::EMF_FILE: delete[] (char*)dataBuffer; break; } dataBuffer = NULL; dataBufferSize = 0; } void LibFrontReader::delete_variable_buffer() { if (variableBuffer == NULL) return; switch (dataBufferType) { case LibFront::EMF_REAL: delete[] (double*)variableBuffer; break; case LibFront::EMF_STRING: delete[] (char*)variableBuffer; break; } variableBuffer = NULL; variableBufferSize = 0; } // Evalute a source buffer containing possible Matc-expressions. // Copy source buffer and all evaluated results into result-buffer // // NOTE: No $-sign accepted // bool LibFrontReader::evalMatcBuffer(char* source) { char matc_buffer[10001]; int source_pos = 0; int source_len = strlen(source); // Read source buffer till end // while (source_pos < source_len ) { // Read expression and set new source-pos just after the expression // source_pos = LibFront::readMatcExpression(source, source_pos, source_len, matc_buffer, 10000); LibFront::trim(matc_buffer); if ( matc_buffer[0] == '\0' ) continue; // Evaluate the Matc-expression // char* matc_result = mtc_domath(matc_buffer); // An empty result if ( matc_result == NULL || matc_result[0] == '\0' ) continue; // Matc Error if ( LibFront::isMatcError(matc_result) ) { strstream strm, strm2; strm << "***WARNING: Matc evaluation error (" << matc_buffer << ")!" << ends; sendMessage(strm.str()); strm2 << matc_result<< ends; sendMessage(strm2.str()); continue; } } return true; } int LibFrontReader::evalAndInsertNextMatc() { readBufferPos = LibFront::readMatcExpression(readBuffer, readBufferPos, readBufferLen, matcBuffer, 10000); // WARNING: Matc definitions are not stored in the egf file, so a warning is in place! // if ( LibFront::isMatcDefinition(matcBuffer) && !matcDefsWarned ) { strstream strm; strm << "***WARNING: Matc definitions are not recommended in the egf-file! (" << matcBuffer << ")" << ends; if ( 1 == sendMessage(strm.str()) ) { matcDefsWarned = true; } } char* matc_result = mtc_domath(matcBuffer); if ( matc_result == NULL || matc_result[0] == '\0' ) return 0; // Matc error if ( LibFront::isMatcError(matc_result) ) { // NOTE Tcl does not like [] !!! for(int i = 0; i < strlen(matc_result); i++) { if ( matc_result[i] == '[' ) matc_result[i] = ' '; if ( matc_result[i] == ']' ) matc_result[i] = ' '; } if ( matc_result != NULL ) { sendMessage(matc_result); sendMessage(matcBuffer); } return -1; } LibFront::trim(matc_result); // Insert matc-expression int eof_insert = insertReadBuffer(matc_result); // If something was inserted, update eval-end-position if ( eof_insert > 0 ) { evaluatedBufferEnd = eof_insert; } storeDataAsString(matcBuffer, true); if ( LibFront::hasMatcVariables(matcBuffer) ) { dataHasMatcVars = true; } return strlen(matcBuffer); } void LibFrontReader::evalAndSkipNextMatc() { readBufferPos = LibFront::readMatcExpression(readBuffer, readBufferPos, readBufferLen, matcBuffer, 10000); // WARNING: Matc definitions are not stored nowhere if in the body of an egf file! if ( LibFront::isMatcDefinition(matcBuffer) && !matcDefsWarned ) { strstream strm; strm << "***WARNING: Matc definitions are not recommended in the egf-file! (" << matcBuffer << ")" << ends; if ( 1 == sendMessage(strm.str()) ) { matcDefsWarned = true; } } char* matc_result = mtc_domath(matcBuffer); } bool LibFrontReader::extractSeparator(char sep) { bufferEatWs(); if (bufferAtEnd()) return false; char c = readBuffer[readBufferPos]; if ( c != sep ) { return false; } else { readBufferPos++; return true; } } bool LibFrontReader::getNextNumber(int& number) { return getNextNumber_impl(number); } bool LibFrontReader::getNextNumber(double& number) { return getNextNumber_impl(number); } template bool LibFrontReader::getNextNumber_impl(T& number) { if (bufferAtEnd()) { return false; } getNextToken(tokenBuffer); strstream strm; strm << tokenBuffer; return ( strm >> number ); } // Basic version without any flag arguments // int LibFrontReader::getNextToken(char* buffer) { if (bufferAtEnd()) { return 0; } bool store_as_string = true; if ( !flags->readingFieldData || ( flags->hasEvaluatedBuffer && evaluatedBufferEnd >= readBufferPos ) ) { store_as_string = false; } // A Matc-expression in the input // if ( readBuffer[readBufferPos] == matcSeparator ) { readBufferPos++; // Evaluate and insert the possible result // if ( flags->readingFieldData ) { int ec = evalAndInsertNextMatc(); // Something as a result if ( ec > 0 ) { flags->hasEvaluatedBuffer = true; // Error, not a definition, but however no result value! } else if ( ec < 0 ) { return -1; } // Evaluate, but do not insert the possible result // } else { evalAndSkipNextMatc(); } bufferEatWs(); return getNextToken(buffer); } if ( readBuffer[readBufferPos] == stringSeparator ) { readBufferPos++; return getToSeparator(buffer, stringSeparator ); } flags->nonSizedDataAtEnd = false; buffer[0] = '\0'; int counter = 0; // Find next token separator // while ( checkReadBuffer() ) { char c = readBuffer[readBufferPos]; // These stop reading (ws + nl + equal sign + $) if ( c == ' ' || c == '\t' || c == '\n' || c == '=' || c == matcSeparator ) { break; } readBufferPos++; buffer[counter++] = c; } // Clean ws from readBuffer bufferEatWs(); buffer[counter] = '\0'; if ( store_as_string ) { storeDataAsString(buffer); } return strlen(buffer); } // NOTE: Checks also if a newline or an equal sign was // after the token // // NOTE: This version inserts only non-data related field items (names etc.) into // readBuffer, field data related expression are inserted by the 'plain' getNextToken-function // // It also evaluates 'loose' Matc-expressions between fields! // // It is meant mainly for peeking tokens in the input! // int LibFrontReader::getNextToken(char* buffer, bool& eq_found, bool& nl_found, bool& matc_found) { static char matc_buffer[10001]; if (bufferAtEnd()) { eq_found = false; nl_found = true; matc_found = false; return 0; } if ( readBuffer[readBufferPos] == matcSeparator ) { readBufferPos++; readBufferPos = LibFront::readMatcExpression(readBuffer, readBufferPos, readBufferLen, matc_buffer, 10000); char* matc_result = mtc_domath(matc_buffer); if ( matc_result != NULL && matc_result[0] != '\0' ) { strstream strm; strm << matc_result << ends; strm >> buffer; matc_found = true; return strlen(buffer); } else { bufferEatWs(); return getNextToken(buffer, eq_found, nl_found, matc_found); } } if ( readBuffer[readBufferPos] == stringSeparator ) { readBufferPos++; return getToSeparator(buffer, stringSeparator ); } flags->nonSizedDataAtEnd = false; buffer[0] = '\0'; int counter = 0; // Find next token separator // while ( checkReadBuffer() ) { char c = readBuffer[readBufferPos]; // These stop reading (ws + nl + equal sign + $) if ( c == ' ' || c == '\t' || c == '\n' || c == '=' || c == matcSeparator ) { matc_found = ( c == matcSeparator ); break; } readBufferPos++; buffer[counter++] = c; } // Clean ws from readBuffer bufferEatWs(eq_found, nl_found); buffer[counter] = '\0'; return strlen(buffer); } int LibFrontReader::getToSeparator(char* buffer, char sep) { buffer[0] = '\0'; if (bufferAtEnd()) return 0; bool store_as_string = true; if ( !flags->readingFieldData || ( flags->hasEvaluatedBuffer && evaluatedBufferEnd >= readBufferPos ) ) { store_as_string = false; } flags->nonSizedDataAtEnd = false; int counter = 0; while ( checkReadBuffer() ) { char c = readBuffer[readBufferPos++]; if ( c == sep ) break; buffer[counter++] = c; } bufferEatWs(); buffer[counter] = '\0'; if ( store_as_string ) { storeDataAsString(buffer); } return strlen(buffer); } bool LibFrontReader::handleEol() { flags->nonSizedDataAtEnd = true; //readBufferPos++; return true; } void LibFrontReader::init_transfer_info() { LibFront::isLogicalData = false; LibFront::isIntegerData = false; LibFront::isRealData = false; LibFront::isStringData = false; LibFront::isFileData = false; LibFront::isVoidData = false; LibFront::logicalData = NULL; LibFront::integerData = NULL; LibFront::realData = NULL; LibFront::stringData = NULL; LibFront::voidData = NULL; LibFront::dimension1 = 0; LibFront::dimension2 = 0; LibFront::dataLengths = NULL; LibFront::isRealVariable = false; LibFront::isStringVariable = false; LibFront::isVoidVariable = false; LibFront::realVariable = NULL; LibFront::stringVariable = NULL; LibFront::variableValuesLengths = NULL; } // Insert new data into readBuffer // This is typically used to insert an evaluated Matc-epxerssion // into input buffer // // Return: end-of-insert position or -1 if nothing was inserted // int LibFrontReader::insertReadBuffer(char* data) { int eof_insert = -1; if ( data == NULL || data[0] == '\0' ) return eof_insert; int data_len = strlen(data); eof_insert = readBufferPos + data_len; // Allocate more space for the new read buffer char* tmp = new char[readBufferLen + data_len]; int i; //-Copy old leading data for (i = 0; i < readBufferPos; i++) { tmp[i] = readBuffer[i]; } //-Insert new data for (i = 0; i < data_len; i++) { tmp[readBufferPos + i] = data[i]; } //-Copy old trailing data for (i = readBufferPos; i < readBufferLen; i++) { tmp[data_len + i] = readBuffer[i]; } // Update readBuffer delete[] readBuffer; readBuffer = tmp; readBufferLen += data_len; return eof_insert; } bool LibFrontReader::is_end_keyword(char* str) { LibFront::toLower(str); if ( 0 == strcmp(str, "end") ) return true; else return false; } bool LibFrontReader::is_file_keyword(char* str) { if ( 0 == strcmp(str, "file") ) return true; else return false; } bool LibFrontReader::is_keyword(char* str) { LibFront::toLower(str); if ( is_size_keyword(str) || is_type_keyword(str) || is_variable_keyword(str) ) return true; else return false; } bool LibFrontReader::is_number(char* str) { if ( str == NULL || str[0] == '\0' ) return false; return LibFront::isNumber(str); } bool LibFrontReader::is_procedure_keyword(char* str) { if ( 0 == strcmp(str, "procedure") ) return true; else return false; } bool LibFrontReader::is_separated_string() { char c = inputFile.peek(); if ( c == '\"' ) return true; return false; } bool LibFrontReader::is_size_keyword(char* str) { LibFront::toLower(str); if ( 0 == strcmp(str, "size") ) return true; else return false; } bool LibFrontReader::is_type_keyword(char* str) { LibFront::toLower(str); if ( 0 == strcmp(str, "integer") || 0 == strcmp(str, "real") || 0 == strcmp(str, "logical") || 0 == strcmp(str, "string") || 0 == strcmp(str, "file") || 0 == strcmp(str, "procedure") ) return true; else return false; } bool LibFrontReader::is_variable_keyword(char* str) { LibFront::toLower(str); if ( 0 == strcmp(str, "variable") ) return true; else return false; } // NOTE: End keyword must be the last token in the line!!! // bool LibFrontReader::next_is_end_keyword() { static char peek_buffer[emf_MAX_STRING_LEN]; if ( !peek_token(peek_buffer) || !(flags->newlinePeeked && !flags->equalSignPeeked) ) { return false; } LibFront::toLower(peek_buffer); if ( is_end_keyword(peek_buffer) ) return true; else return false; } bool LibFrontReader::next_is_group_names() { static char peek_buffer[emf_MAX_STRING_LEN]; if ( !peek_token(peek_buffer) ) { return false; } if ( peek_buffer[0] == '[' ) { return true; } else { return false; } } bool LibFrontReader::next_is_keyword() { static char peek_buffer[emf_MAX_STRING_LEN]; if ( next_is_end_keyword() ) return true; if ( !peek_token(peek_buffer) ) { return false; } LibFront::toLower(peek_buffer); if ( is_keyword(peek_buffer) ) { return true; } else { return false; } } bool LibFrontReader::next_is_matc() { if (bufferAtEnd()) return false; push_flags(); int old_pos = readBufferPos; bufferEatWs(); char c = readBuffer[readBufferPos]; readBufferPos = old_pos; pop_flags(); if ( c == matcSeparator ) return true; else return false; } bool LibFrontReader::next_is_number() { static char buffer[emf_MAX_STRING_LEN]; if ( !peek_token(buffer) ) return false; return is_number(buffer); } bool LibFrontReader::next_is_separated_string() { if (bufferAtEnd()) return false; push_flags(); int old_pos = readBufferPos; bufferEatWs(); char c = readBuffer[readBufferPos]; readBufferPos = old_pos; pop_flags(); if ( c == stringSeparator ) return true; else return false; } bool LibFrontReader::next_is_size_keyword() { static char peek_buffer[emf_MAX_STRING_LEN]; if ( !peek_token(peek_buffer) ) return false; LibFront::toLower(peek_buffer); if ( is_size_keyword(peek_buffer) ) return true; else return false; } bool LibFrontReader::next_is_text(char* text) { static char buffer[emf_MAX_STRING_LEN]; if ( !peek_token(buffer) ) return false; if ( LibFront::ncEqual(buffer, text) ) return true; else return false; } bool LibFrontReader::next_is_type_keyword() { static char peek_buffer[emf_MAX_STRING_LEN]; if ( !peek_token(peek_buffer) ) return false; LibFront::toLower(peek_buffer); if ( is_type_keyword(peek_buffer) ) return true; else return false; } bool LibFrontReader::next_is_variable_keyword() { static char peek_buffer[emf_MAX_STRING_LEN]; if ( !peek_token(peek_buffer) ) return false; LibFront::toLower(peek_buffer); if ( is_variable_keyword(peek_buffer) ) return true; else return false; } bool LibFrontReader::next_non_number_is_data_keyword() { static char peek_buffer[emf_MAX_STRING_LEN]; if ( !peek_next_string(peek_buffer) ) return false; LibFront::toLower(peek_buffer); if ( is_size_keyword(peek_buffer) || is_type_keyword(peek_buffer) || is_variable_keyword(peek_buffer) ) return true; else return false; } bool LibFrontReader::next_non_number_is_keyword() { static char peek_buffer[emf_MAX_STRING_LEN]; if ( next_is_end_keyword() ) return true; if ( !peek_next_string(peek_buffer) ) return false; LibFront::toLower(peek_buffer); if ( is_keyword(peek_buffer) ) return true; else return false; } bool LibFrontReader::object_at_end() { if (bufferAtEnd()) return false; if ( next_is_end_keyword() ) { return true; } else { return false; } } // Method checks the number of string tokens before possible TWO // consecutive numeric tokens. // NOTE: the total number of numeric tokens is not counted, it is // enough to know if there is 0, 1 or >= 2 of them!!! // NOTE: Keywords are accepted as name tokens! ==> a LINEFEED must // be after the object/field name before a possible keyword! bool LibFrontReader::peek_field_name_tokens(int& nof_tokens) { nof_tokens = 0; bool nl_found = false; bool eq_found = false; bool mc_found = false; push_flags(); int old_pos = readBufferPos; flags->nonSizedDataAtEnd = false; int nof_picked_tokens = 0; int nof_name_tokens = 0; bool next_found = false; bool tmp = flags->readingFieldData; flags->readingFieldData = false; // Read all tokens in the line while( !bufferAtEnd() && !flags->nonSizedDataAtEnd ) { if ( next_is_separated_string() ) { flags->readingNonSizedData = true; break; } // Try to read next token next_found = ( 0 != getNextToken(tokenBuffer, eq_found, nl_found, mc_found)); // If data at end or next starst with matc-$ sign, field name must end if ( !next_found || mc_found ) { break; } if ( next_found ) { nof_picked_tokens++; } // If next still was text, add to the field name // if ( next_found && !is_number(tokenBuffer) ) { nof_name_tokens = nof_picked_tokens; } // If an equal sign was found, field name must end if ( eq_found ) { break; } } // while flags->readingFieldData = tmp; // If next is keyword, all picked tokens belong to field name! if ( next_is_keyword() && !next_is_end_keyword() ) { nof_tokens = nof_picked_tokens; } else { nof_tokens = nof_name_tokens; } readBufferPos = old_pos; pop_flags(); return true; } // Peeks first "real" string token in readStream, so all numbers are first skipped bool LibFrontReader::peek_next_string(char* buffer) { buffer[0] = '\0'; if (bufferAtEnd()) { return false; } push_flags(); int old_pos = readBufferPos; bool tmp = flags->readingFieldData; flags->readingFieldData = false; // Skip numbers double test_number; while (!bufferAtEnd()) { getNextToken(tokenBuffer); strstream strm; strm << tokenBuffer; if ( !(strm >> test_number) ) { break; } } flags->readingFieldData = tmp; strcpy(buffer, tokenBuffer); readBufferPos = old_pos; pop_flags(); if ( strlen(buffer) == 0 ) { return false; } else { return true; } } // Method checks the number of string tokens before possible TWO // consecutive numeric tokens. // NOTE: the total number of numeric tokens is not counted, it is // enough to know if there is 0, 1 or >= 2 of them!!! // NOTE: Keywords are accepted as name tokens! ==> a LINEFEED must // be after the object/field name before a possible keyword! bool LibFrontReader::peek_object_name_tokens(int& nof_tokens) { nof_tokens = 0; push_flags(); int old_pos = readBufferPos; flags->nonSizedDataAtEnd = false; int nof_picked_tokens = 0; int nof_consecutive_nbr_tokens = 0; bool tmp = flags->readingFieldData; flags->readingFieldData = false; while( !bufferAtEnd() && !flags->nonSizedDataAtEnd ) { // No separated strings accepted in object name if ( next_is_separated_string() ) { return false; } getNextToken(tokenBuffer); nof_picked_tokens++; // Include keyword is a bit exceptional!!! // if ( nof_picked_tokens == 1 && LibFront::in(tokenBuffer, "Include") ) { break; } if ( is_number(tokenBuffer) ) { nof_consecutive_nbr_tokens++; } else { nof_consecutive_nbr_tokens = 0; } // Only one number accepted after object name (object id) if ( nof_consecutive_nbr_tokens > 1 ) { return false; } } // while flags->readingFieldData = tmp; nof_tokens = nof_picked_tokens - nof_consecutive_nbr_tokens; readBufferPos = old_pos; pop_flags(); return true; } // Peeks next token in the readBuffer // NOTE: Checks also if an equal sign or a newline was ahed // bool LibFrontReader::peek_token(char* buffer) { bool eq_found = false; bool nl_found = false; bool mc_found = false; flags->equalSignPeeked = eq_found; flags->newlinePeeked = nl_found; flags->matcPeeked = mc_found; buffer[0] = '\0'; if (bufferAtEnd()) { return false; } push_flags(); int old_pos = readBufferPos; bool tmp = flags->readingFieldData; flags->readingFieldData = false; getNextToken(buffer, eq_found, nl_found, mc_found); flags->readingFieldData = tmp; readBufferPos = old_pos; pop_flags(); flags->equalSignPeeked = eq_found; flags->newlinePeeked = nl_found; flags->matcPeeked = mc_found; if ( strlen(buffer) == 0 ) { return false; } else { return true; } } void LibFrontReader::pop_flags() { currentFlagsIndex--; flags = &flagsStack[currentFlagsIndex]; } void LibFrontReader::push_flags(bool copy_current) { currentFlagsIndex++; if (copy_current) flagsStack[currentFlagsIndex].copy(flagsStack[currentFlagsIndex - 1]); else flagsStack[currentFlagsIndex].init(); flags = &flagsStack[currentFlagsIndex]; } // Read data in the entry bool LibFrontReader::read_entry_data(struct emf_ObjectData_X* od, int data_alloc_count, int data_size, int& read_count) { // Buffer sizes int old_data_buffer_size, new_data_buffer_size; // Extra size allocated for this entry int data_alloc_size; data_alloc_size = data_alloc_count * data_size; old_data_buffer_size = dataBufferSize; new_data_buffer_size = dataBufferSize + data_alloc_size; allocate_data_buffer(old_data_buffer_size, new_data_buffer_size); currentBuffer = dataBuffer; currentBufferSize = dataBufferSize; currentBufferType = dataBufferType; int* read_sizes = new int[data_alloc_count]; // Read values if ( !read_entry_data_values(old_data_buffer_size, new_data_buffer_size, data_alloc_count, read_sizes, read_count) ) { // If no succes: ERROR MSG! sendMessage("\n"); sendMessage("*** ERROR ***: When reading data for:"); //-- Object name FieldName { strstream strm; strm << "OBJECT: " << od->object_name; if (od->object_id != -1) { strm << " " << od->object_id; } strm << " FIELD: " << od->field_name; strm << ends; sendMessage(strm.str()); } //--Size info { strstream strm; strm << "Expected size: " << data_alloc_size; strm << " Actual size: " << read_count; strm << ends; sendMessage(strm.str()); } sendMessage("\n"); return false; } #if 0 // Debugging cerr << endl; cerr << "Object: " << od->object_name; if (od->object_id != -1) cerr << " " << od->object_id; cerr << endl; cerr << "Field: " << od->field_name << endl; cerr << "Datatype: " << od->data_type << endl; cerr << "Data: "; output_data(cerr, od->data_type, od->data); cerr << "Buffer: " << readBuffer << endl; cerr << "Is sep string: " << isSeparatedStrings << endl; #endif nofDataValues += read_count; int data_read_size = 0; // Actual total size of the read data for (int i = 0; i < read_count; i++) data_read_size += read_sizes[i]; // Remove possible extra DATA entry space (relevant for string data!) if ( data_read_size < data_alloc_size ) { new_data_buffer_size += data_read_size - data_alloc_size; allocate_data_buffer(new_data_buffer_size, new_data_buffer_size); } update_data_lengths(read_count, read_sizes); delete[] read_sizes; if (bufferAtEnd()) { return false; } return true; } bool LibFrontReader::read_entry_data_values(int old_data_buffer_size, int new_data_buffer_size, int data_count, int* data_sizes, int& read_count) { if (data_count == 0) { read_count = 0; return true; } // Default data value sizes (for logical and numeric data) for (int i = 0; i < data_count; i++) data_sizes[i] = 1; // Character data if ( flags->readingProcedureName || currentBufferType == LibFront::EMF_STRING || currentBufferType == LibFront::EMF_FILE ) { if ( !read_string_data(old_data_buffer_size, new_data_buffer_size, data_count, data_sizes, read_count) ) { return false; } // Logical data } else if ( currentBufferType == LibFront::EMF_LOGICAL ) { if ( !read_logical_data(old_data_buffer_size, new_data_buffer_size, read_count) ) { return false; } // Numeric data } else { if ( !read_numeric_data(old_data_buffer_size, new_data_buffer_size, read_count) ) { return false; } } return true; } // Read variables in the entry bool LibFrontReader::read_entry_variables(struct emf_ObjectData_X* od, int var_alloc_count, int var_size) { // Buffer sizes int old_var_buffer_size, new_var_buffer_size; // Extra size allocated for this entry int var_alloc_size; // Actual nof of read values int var_read_count; var_alloc_size = var_alloc_count * var_size; old_var_buffer_size = variableBufferSize; new_var_buffer_size = variableBufferSize + var_alloc_size; allocate_variable_buffer(old_var_buffer_size, new_var_buffer_size); currentBuffer = variableBuffer; currentBufferSize = variableBufferSize; currentBufferType = variableBufferType; // Sizes of the actually read values (normally 1, but string length for string data) int* read_sizes = new int[var_alloc_count]; if ( !read_entry_variable_values(old_var_buffer_size, new_var_buffer_size, var_alloc_count, read_sizes, var_read_count) ) { // If no succes: ERROR MSG! sendMessage("\n"); sendMessage("*** ERROR ***: When reading variable data for:"); //--Object name, Field name { strstream strm; strm << "OBJECT: " << od->object_name; if (od->object_id != -1) { strm << " " << od->object_id; } strm << " FIELD: " << od->field_name; strm << ends; sendMessage(strm.str()); } // Size info { strstream strm; strm << "Expected size: " << var_alloc_size; strm << " Actual size: " << var_read_count; strm << ends; sendMessage(strm.str()); } sendMessage("\n"); return false; } else { #if 0 // Debugging cerr << endl; cerr << "Object: " << od->object_name; if (od->object_id != -1) cerr << " " << od->object_id; cerr << endl; cerr << "Field: " << od->field_name << endl; cerr << "Datatype: " << od->data_type << endl; cerr << "Data: "; output_data(cerr, od->data_type, od->data); cerr << "Buffer: " << readBuffer << endl; cerr << "Hanging sep string: " << hangingSeparatedString << endl; cerr << "Contains sep string: " << containsSeparatedStrings << endl; #endif } nofVariableValues += var_read_count; int var_read_size = 0; // Actual total size of the read variable values for (int i = 0; i < var_read_count; i++) var_read_size += read_sizes[i]; // Remove possible extra VARIABLE value space (relevant for name variables!) if ( var_read_size < var_alloc_size ) { new_var_buffer_size += var_read_size - var_alloc_size; allocate_variable_buffer(new_var_buffer_size, new_var_buffer_size); } update_variable_lengths(var_read_count, read_sizes); return true; } bool LibFrontReader::read_entry_variable_values(int old_var_buffer_size, int new_var_buffer_size, int var_count, int* var_sizes, int& read_count) { if (var_count == 0) { read_count = 0; return true; } // Default variable value sizes (for numeric data) for (int i = 0; i < var_count; i++) var_sizes[i] = 1; // Character variable values (a name string!) if ( currentBufferType == LibFront::EMF_STRING ) { if ( !read_string_data(old_var_buffer_size, new_var_buffer_size, var_count, var_sizes, read_count) ) { return false; } // Numeric data } else { if ( !read_numeric_data(old_var_buffer_size, new_var_buffer_size, read_count) ) { return false; } } return true; } // Read field name (optional) and data entries // bool LibFrontReader::read_field(struct emf_ObjectData_X* od) { static char peek_buffer[emf_MAX_STRING_LEN]; flags->endsField = false; flags->readingNonSizedData = false; bool size_given, type_given, variable_given; if ( flags->startsNewField ) { dimension1 = 1; dimension2 = 1; nofEntries = 0; nofVariables = 0; od->field_name[0] = '\0'; od->is_procedure = false; //---Read field name. NOTE: In some cases name is not needed! if (! read_field_name(od, od->field_name, emf_MAX_NAME_LEN) ) return false; od->field_name_length = strlen(od->field_name); flags->startsNewField = false; // If there were group names (like [A B C] ) after field name if ( flags->readingGroupNames ) read_group_names(od); } // All field data have been read if ( flags->endsField ) { flags->endsField = false; return true; } //---Check if Variable-keyword is given if (bufferAtEnd()) return false; variable_given = false; if ( next_is_variable_keyword() ) { getNextToken(tokenBuffer); variable_given = true; } //---If Variable given, read variable names // NOTE: Read until the Size-keyword or a Type keyword comes! if (variable_given) { while (1) { if (bufferAtEnd()) return false; if (next_is_type_keyword() || next_is_size_keyword() ) break; getNextToken(od->variable_names[nofVariables]); od->variable_name_lengths[nofVariables] = strlen(od->variable_names[nofVariables]); nofVariables++; if (nofVariables > emf_MAX_NOF_VARIABLES) return false; } } if ( variable_given && nofVariables == 0 ) return false; //---Check if Size-keyword is given if (bufferAtEnd()) return false; size_given = false; if ( next_is_size_keyword() ) { getNextToken(tokenBuffer); size_given = true; } if (bufferAtEnd()) return false; //---If Size given, read dimensions if (size_given) { getNextNumber(dimension1); // If second (column) dimension is given // read it from the stream int test_nbr; if ( try_to_read(test_nbr) ) { getNextNumber(dimension2); } } // NOTE: When variable is given, data rows are ended // by the "end" mark and Size-parameters tell the size of // the data entry rows!!! if ( nofVariables > 0 ) flags->readingEndMarkedData = true; //---Check data type keyword if (bufferAtEnd()) return false; type_given = false; if ( next_is_type_keyword() ) type_given = true; if ( size_given && !type_given ) { // ERROR MSG strstream strm; strm << "UNKNOWN DATA TYPE: " << peek_buffer << ends; sendMessage(strm.str()); sendMessage("\n"); return false; } //---If field-name is not yet resolved if ( flags->hangingFieldNameNumber ) { flags->hangingFieldNameNumber = false; // Hanging number belongs to the field name if (type_given) { strstream strm; strm << od->field_name << ' ' << (int)hangingNumber << ends; strm >> od->field_name; od->field_name_length = strlen(od->field_name); // We had one single data value } else { return storeNumber(od, LibFront::EMF_REAL, &hangingNumber); } } //---Read possible data type if (type_given) { getNextToken(od->data_type); LibFront::toLower(od->data_type); od->data_type_length = strlen(od->data_type); if ( 0 == strcmp(od->data_type, "procedure") ) { od->is_procedure = true; } } //---Check if we have a procedure definition (for int,real // data types bool read_procedure = false; if (bufferAtEnd()) return false; if ( peek_token(peek_buffer) ) { LibFront::toLower(peek_buffer); read_procedure = is_procedure_keyword(peek_buffer); } //---Set possible data type if (type_given) { // integer if ( 0 == strcmp(od->data_type, "integer") ) { dataBufferType = LibFront::EMF_INTEGER; flags->readingProcedureName = read_procedure; // real } else if ( 0 == strcmp(od->data_type, "real") ) { dataBufferType = LibFront::EMF_REAL; flags->readingProcedureName = read_procedure; // logical } else if ( 0 == strcmp(od->data_type, "logical") ) { dataBufferType = LibFront::EMF_LOGICAL; flags->readingProcedureName = read_procedure; // string } else if ( 0 == strcmp(od->data_type, "string") ) { dataBufferType = LibFront::EMF_STRING; flags->readingProcedureName = read_procedure; // file name } else if ( 0 == strcmp(od->data_type, "file") ) { dataBufferType = LibFront::EMF_FILE; flags->readingFileName = true; // unknown --> string } else { dataBufferType = LibFront::EMF_STRING; strcpy(od->data_type, "string"); } } // Reading field data // ================== flags->readingFieldData = true; dataAsStringBuffer[0] = '\0'; dataAsStringPos = 0; //---Non-sized data if (!size_given) { return read_field_data_non_sized(od, type_given); } //---Sized data od->dimension1 = dimension1; od->dimension2 = dimension2; od->nof_variables = nofVariables; // Default sizes for variable value and data parts // in the entry row int var_count = nofVariables; int var_size = 1; int data_count = (dimension1 * dimension2); int data_size = 1; // Set size info for these data types if ( 0 == strcmp(od->data_type, "string") || 0 == strcmp(od->data_type, "file") ) { data_size = readBufferLen; // we do not know the string size in advance! } int read_count = 0; return read_field_data_sized(od, var_count, var_size, data_count, data_size, read_count); } // Read LOOP, read variables and data in the entries // *_count arguments tell the number of varaible values and data values // *_size arguments tell the size to allocated for theses values // NOTE: size is normally 1, but for strings it is the text buffer length // and this size must be updated when the value is read, because we // do not know the size in advance! bool LibFrontReader::read_field_data_sized(struct emf_ObjectData_X* od, int var_alloc_count, int var_size, int data_alloc_count, int data_size, int& read_count) { nofDataValues = 0; nofEntries = 0; nofVariableValues = 0; // Check variable value types (NOTE: Real or String currently!) if ( nofVariables > 0 ) { if ( next_is_number() ) { variableBufferType = LibFront::EMF_REAL; strcpy(od->variable_type, "real"); od->variable_type_length = strlen(od->variable_type); } else { variableBufferType = LibFront::EMF_STRING; strcpy(od->variable_type, "string"); od->variable_type_length = strlen(od->variable_type); var_size = readBufferLen; } } delete_data_buffer(); delete_variable_buffer(); // Read LOOP while (1) { nofEntries++; // Read possible variable values if ( nofVariables > 0) { if (bufferAtEnd()) { return false; } read_entry_variables(od, var_alloc_count, var_size); } if (bufferAtEnd()) { return false; } // Read data values read_entry_data(od, data_alloc_count, data_size, read_count); if (bufferAtEnd()) { return false; } if (data_at_end()) { flags->readingFieldData = false; // Consume "End" mark for the data if ( flags->readingEndMarkedData ) { getNextToken(tokenBuffer); flags->readingEndMarkedData = false; } break; } } // Update transfer data od->data = dataBuffer; od->data_length = dataBufferSize; od->data_lengths = dataLengths; if ( currentBufferType == LibFront::EMF_STRING ) { od->nof_entries = read_count; } else { od->nof_entries = nofEntries; } od->variable_values = variableBuffer; od->variable_values_length = variableBufferSize; od->variable_values_lengths = variableLengths; return true; } // Read "simple" data entries when Size,Type is not given // data type is either Real (for numbers) or String bool LibFrontReader::read_field_data_non_sized(struct emf_ObjectData_X* od, bool type_given) { flags->readingNonSizedData = true; flags->nonSizedDataAtEnd = false; delete_data_buffer(); int data_count = 1024; int data_size = 1; od->dimension1 = 1; od->dimension2 = 1; od->nof_variables = 0; if (!type_given) { if ( next_is_number() ) { dataBufferType = LibFront::EMF_REAL; strcpy(od->data_type, "real"); } else { dataBufferType = LibFront::EMF_STRING; strcpy(od->data_type, "string"); data_count = 10; // Max 10 strings per entry! data_size = readBufferLen; } } od->data_type_length = strlen(od->data_type); int read_count = 0; bool rc = read_field_data_sized(od, 0, 0, data_count, data_size, read_count); od->dimension1 = od->data_length; return rc; } bool LibFrontReader::read_field_name(struct emf_ObjectData_X* od, char* name_buffer, int buffer_len) { if (bufferAtEnd()) return false; //-Check if End-keyword is given, then we have // no field-name or data, just object and its data!!! if ( next_is_end_keyword() ) { flags->endsField = true; return true; } //-Check if Type or Variable-keyword is given, then we have // no field-name just object and data!!! if ( next_is_type_keyword() || next_is_variable_keyword() ) { return true; } //-We have to check if there is any number in the buffer // to resolve the the "Fieldname 1" problem int nbr_of_tokens = 0; if ( !peek_field_name_tokens(nbr_of_tokens) ) return false; constructStringFromTokens(name_buffer, nbr_of_tokens); if ( name_buffer == NULL || name_buffer[0] == '\0' ) { return false; } else { return true; } } bool LibFrontReader::read_group_names(struct emf_ObjectData_X* od) { if (bufferAtEnd()) return false; char groups_buffer[1024]; char group_buffer[1024]; int len; // Pick away group starting character '[' readBufferPos++; // Read until next ']' getToSeparator(groups_buffer, ']'); LibFront::trim(groups_buffer); len = strlen(groups_buffer); // Make input stream from the whole string between [] istrstream groups_strm(groups_buffer, len); short group_index = 0; // Split string by group "grouper" characeter ';' while ( !groups_strm.eof() ) { groups_strm.getline(group_buffer, 1024, ';'); LibFront::trim(group_buffer); len = strlen(group_buffer); // Make input stream from one group string between ';' characters istrstream group_strm(group_buffer, len); short name_index = 0; while( !group_strm.eof() ) { group_strm >> od->group_names[group_index][name_index]; od->group_name_lengths[group_index][name_index] = strlen(od->group_names[group_index][name_index]); od->nof_group_names[group_index] = ++name_index; } if (++group_index > emf_MAX_NOF_GROUPS) break; } return true; } bool LibFrontReader::read_logical_data(int start_pos, int max_pos, int& read_count) { static char buffer[emf_MAX_STRING_LEN]; int logical_value; double numeric_value; read_count = 0; for (int i = start_pos; i < max_pos; i++) { if (bufferAtEnd()) { return false; } //---Read logical value //-text True if ( next_is_text("True") ) { logical_value = 1; getNextToken(buffer); //-text False } else if ( next_is_text("False") ) { logical_value = 0; getNextToken(buffer); //-numeric (0/1) value } else if ( next_is_number() ) { getNextNumber(numeric_value); if (numeric_value > 0) logical_value = 1; else logical_value = 0; //-ERROR } else { return false; } ((int*)currentBuffer)[i] = logical_value; read_count++; } // for return true; } bool LibFrontReader::read_numeric_data(int start_pos, int max_pos, int& read_count) { read_count = 0; for (int i = start_pos; i < max_pos; i++) { if (bufferAtEnd()) { return false; } if ( flags->readingNonSizedData ) { if ( flags->nonSizedDataAtEnd || !next_is_number() ) return true; } switch (currentBufferType) { case LibFront::EMF_INTEGER: case LibFront::EMF_LOGICAL: int int_number; if ( !getNextNumber(int_number) ) { return false; } ((int*)currentBuffer)[i] = int_number; break; case LibFront::EMF_REAL: // NonSized is always read as doubles and next non-number // ends the data and we should not try to tread it!!! // Normal Sized data should always succeed double dbl_number; if ( !getNextNumber(dbl_number) ) { return false; } ((double*)currentBuffer)[i] = dbl_number; break; } // switch read_count++; } // for return true; } bool LibFrontReader::read_object(struct emf_ObjectData_X* od) { //---Read object (section) name and a possible (id) number // or a separated string (data like "string data") od->object_name[0] = '\0'; od->object_id = -1; if ( !read_object_name(od, od->object_name, emf_MAX_NAME_LEN) ) { return false; } od->object_name_length = strlen(od->object_name); //-If there were group names (like [A B C] ) after object name if ( flags->readingGroupNames ) { read_group_names(od); } #if 0 // For debbugging cerr << od->object_name; if (od->object_id != -1) cerr << " " << od->object_id; cerr << endl; #endif return true; } bool LibFrontReader::read_object_name(struct emf_ObjectData_X* od, char* name_buffer, int buffer_len) { if (next_is_separated_string()) { return false; } int nbr_of_tokens; if ( !peek_object_name_tokens(nbr_of_tokens) ) { return false; } constructStringFromTokens(name_buffer, nbr_of_tokens); // Remove white-space from the end of the string LibFront::trimRight(name_buffer); // Read possible id if ( next_is_number() ) { getNextNumber(od->object_id); } return true; } bool LibFrontReader::read_string_data(int start_pos, int max_pos, int string_count, int* string_sizes, int& read_count) { // Result will be put into currentBuffer char* result_string = (char*)currentBuffer; read_count = 0; int string_pos = start_pos; int string_pos_prev = start_pos; for (int i = 0; i < string_count; i++) { bufferEatWs(); if ( !checkReadBuffer() ) { return false; } // New line (ie. lf without continuation mark) // has stopped non-sized data reading! if ( flags->readingNonSizedData && flags->nonSizedDataAtEnd ) return true; // Append next token to the result_string char* buffer = result_string + string_pos; if ( -1 == getNextToken(buffer) ) return false; // Find current end position of the result // // NOTE: We will start writing from the NULL character, so // string-pos must be on that character --> -1. // If null charcaters are left in the buffer, they will // truncate the data! // BE CAREFUL WITH THIS!!!***!!! // string_pos = strlen(result_string) - 1; // Remove white-space from the end of the string // // NOTE: This function just tells the position of the last // non-ws character, it does NOT manipulate the string itself!!! // LibFront::trimRight(result_string, start_pos, string_pos); // This many was actually put into array int string_size = 1 + string_pos - string_pos_prev; string_sizes[i] = string_size; string_pos++; string_pos_prev = string_pos; read_count++; } return true; } void LibFrontReader::reset_flags() { flagsStack[currentFlagsIndex].init(); } int LibFrontReader::sendMessage(char* msg) { cerr << msg; if (emf_readMessageCB == NULL || msgBuffer == NULL) return false; strncpy(msgBuffer, msg, msgBufferSize); return emf_readMessageCB(msgBuffer); } void LibFrontReader::set_transfer_info() { struct emf_ObjectData_X* od = emf_ObjectData; init_transfer_info(); // Data values if ( LibFront::ncEqual(od->data_type, "logical") ) { LibFront::logicalData = (int*) od->data; LibFront::isLogicalData = true; } else if ( LibFront::ncEqual(od->data_type, "integer") ) { LibFront::integerData = (int*) od->data; LibFront::isIntegerData = true; } else if ( LibFront::ncEqual(od->data_type, "real") ) { LibFront::realData = (double*) od->data; LibFront::isRealData = true; } else if ( LibFront::ncEqual(od->data_type, "string") ) { LibFront::stringData = (char*) od->data; LibFront::isStringData = true; } else if ( LibFront::ncEqual(od->data_type, "file") ) { LibFront::stringData = (char*) od->data; LibFront::isFileData = true; } else { LibFront::voidData = (void*) od->data; LibFront::isVoidData = true; } LibFront::dimension1 = od->dimension1; LibFront::dimension2 = od->dimension2; LibFront::dataLengths = od->data_lengths; // Variable values if ( LibFront::ncEqual(od->variable_type, "real") ) { LibFront::realVariable = (double*) od->variable_values; LibFront::isRealVariable = true; } else if ( LibFront::ncEqual(od->variable_type, "string") ) { LibFront::stringVariable = (char*) od->variable_values; LibFront::isStringVariable = true; } else { LibFront::voidVariable = (void*) od->variable_values; LibFront::isVoidVariable = true; } LibFront::variableValuesLengths = od->variable_values_lengths; } bool LibFrontReader::start() { struct emf_ObjectData_X* od = emf_ObjectData; od->dataAsString = NULL; od->dataHasMatcVars = 0; init_transfer_info(); flags->startsNewObject = true; for (int i = 0; i < emf_MAX_NOF_GROUPS; i++) { od->nof_group_names[i] = 0; } bufferEatWs(); if (bufferAtEnd()) { return false; } while ( !bufferAtEnd() ) { //---New object is started if ( flags->startsNewObject ) { od->is_object_start = 1; od->is_object_end = 0; if ( !read_object(od) ) { strstream strm; strm << "***ERROR When reading object data for object: " << od->object_name << " " << od->object_id; strm << ends; sendMessage(strm.str()); sendMessage("\n"); return false; } flags->startsNewObject = false; //---New field for the object } else { flags->startsNewField = true; dataHasMatcVars = false; if ( !read_field(od) ) { strstream strm; strm << "***ERROR When reading field data for object: " << od->object_name << " " << od->object_id; strm << ". Reading field: " << od->field_name << ends; sendMessage(strm.str()); sendMessage("\n"); return false; } dataAsStringBuffer[dataAsStringPos] = '\0'; flags->readingFieldData = false; flags->hasEvaluatedBuffer = false; if ( object_at_end() || LibFront::in(tokenBuffer, "Include") ) { od->is_object_end = 1; // Consume the possible object end marker "End" if ( object_at_end() ) { getNextToken(tokenBuffer); } flags->startsNewObject = true; } set_transfer_info(); // Send data after each field delete[] od->dataAsString; od->dataAsString = new char[1+dataAsStringPos]; strcpy(od->dataAsString, dataAsStringBuffer); od->dataHasMatcVars = int(dataHasMatcVars); int rc = sendData(userData); // ERROR!!! if ( rc != emf_OK ) { return false; } od->is_object_start = 0; // NOTE: Group data is "reset" after each send ==> // If you want to read object-level group // info, it must be done when "object-start = 1"!!! for (int i = 0; i < emf_MAX_NOF_GROUPS; i++) od-> nof_group_names[i] = 0; } flags->nonSizedDataAtEnd = false; flags->hangingFieldNameNumber = false; flags->readingNonSizedData = false; flags->readingFileName = false; flags->readingFieldData = false; flags->readingGroupNames = false; flags->readingProcedureName = false; } return true; } // Store field input data as a string. // This is used to store Matc-expressions in input data etc. // void LibFrontReader::storeDataAsString(const char* buffer, bool is_matc) { // Add a separator before new data // if ( dataAsStringPos > 0 ) { dataAsStringBuffer[dataAsStringPos++] = ' '; } char* tmp = dataAsStringBuffer; tmp += dataAsStringPos; // Add $-sign in front of an Matc-expression, so it can be // used later as an input data!!! // if ( is_matc ) { strncpy(tmp, &matcSeparator, 1); strcpy(tmp+1, buffer); } else { strcpy(tmp, buffer); } // Add new data // dataAsStringPos += strlen(tmp); } // Read one given number bool LibFrontReader::storeNumber(struct emf_ObjectData_X* od, LibFront::dataValueType data_type, void* data) { // Delete old buffer delete_data_buffer(); // Allocate new with given type dataBufferType = data_type; allocate_data_buffer(dataBufferSize ,1); nofEntries = 1; nofDataValues = 1; int data_sizes[1] = {1}; update_data_lengths(1, data_sizes); switch (data_type) { case LibFront::EMF_LOGICAL: strcpy(od->data_type,"logical"); ((int*)dataBuffer)[0] = *((int*)data); break; case LibFront::EMF_INTEGER: strcpy(od->data_type, "integer"); ((int*)dataBuffer)[0] = *((int*)data); break; case LibFront::EMF_REAL: strcpy(od->data_type, "real"); ((double*)dataBuffer)[0] = *((double*)data); break; } od->data = dataBuffer; od->data_length = dataBufferSize; od->data_lengths = dataLengths; od->nof_entries = nofEntries; return true; } template bool LibFrontReader::try_to_read(T& data) { if (bufferAtEnd()) { return false; } push_flags(); int old_pos = readBufferPos; bool rc = getNextNumber(data); readBufferPos = old_pos; pop_flags(); return rc; } bool LibFrontReader::update_data_lengths(int data_count, int* data_sizes) { int old_nof_values = nofDataValues - data_count; int* data_lengths = new int[nofDataValues]; int i; for (i = 0; i < old_nof_values; i++) // Copy old values data_lengths[i] = dataLengths[i]; for (i = 0; i < data_count; i++) // Add new values data_lengths[old_nof_values + i] = data_sizes[i]; delete[] dataLengths; dataLengths = data_lengths; return true; } bool LibFrontReader::update_variable_lengths(int var_count, int* var_sizes) { if (nofVariableValues == 0) return true; int old_nof_values = nofVariableValues - var_count; int* var_lengths = new int[nofVariableValues]; int i; // Copy old values for (i = 0; i < old_nof_values; i++) var_lengths[i] = variableLengths[i]; // Add new values for (i = 0; i < var_count; i++) var_lengths[old_nof_values + i] = var_sizes[i]; delete[] variableLengths; variableLengths = var_lengths; return true; } // ========================================================================= // END: LibFrontReader class implementation // =========================================================================