/* * freescope - Free source browser * Copyright (C) 2001 Olivier Deme * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ // FILE: dbinf.cpp /************/ /* INCLUDES */ /************/ #include #include "dbinf.h" #include "trace.h" #include "defs.h" /********************/ /* GLOBAL VARIABLES */ /********************/ Add2Db add2db; // Watch out, there shouldn't be any symbol equals to 0! symbol_type_t DEFINITION = 1; symbol_type_t FUNC_CALLED = 2; symbol_type_t FUNC_CALL = 3; symbol_type_t ASSIGNMENT = 4; symbol_type_t INCLUDE = 5; symbol_type_t ANY = 6; char* GLOBAL_SCOPE = "`GLOBAL"; size_t GLOBAL_SCOPE_LENGTH = 7; /**************************/ /* STATIC INITIALIZATIONS */ /**************************/ DbInf* DbInf::m_instance = 0; const size_t DbInf::RECORD_LENGTH = sizeof(symbol_code_t) + sizeof(symbol_type_t) + sizeof(symbol_code_t) + sizeof(line_nbr_t); const size_t DbInf::BUFFER_SIZE = 500 * DbInf::RECORD_LENGTH; const DbInf::symbol_code_t DbInf::SYMBOL_NEW_FILE = 0; const DbInf::symbol_code_t DbInf::SYMBOL_FREE_RECORD = 1; /***********************/ /* FUNCTION DEFINTIONS */ /***********************/ /* * FUNCTION: DbInf::DbInf * * DESCRIPTION: Constructor * * IN: * IN-OUT: * RETURN CODE: */ DbInf::DbInf () : m_db_modified(0), m_do_existing_file(false) { add2db = DbInf::add_entry; m_buffer.reserve(BUFFER_SIZE); } /* * FUNCTION: DbInf::~DbInf * * DESCRIPTION: Destructor * * IN: * IN-OUT: * RETURN CODE: */ DbInf::~DbInf () { // Close the file m_db_file.close(); } /* * FUNCTION: DbInf::instance * * DESCRIPTION: Return a pointer to the unique instance of this class. * * IN: * IN-OUT: * RETURN CODE: A pointer to the instance */ DbInf* DbInf::instance() { if (m_instance == NULL) m_instance = new DbInf; return m_instance; } /* * FUNCTION: DbInf::open * * DESCRIPTION: This function opens a database file. If the file does not exist, * it is created, otherwise the symbol table and file table are * loaded into the multimap attributes. * * IN: filename The name of the database file to open * IN-OUT: * RETURN CODE: */ void DbInf::open (const string& filename) { // Open the file m_db_file.open(filename.c_str(), ios::in | ios::out | ios::binary); if (m_db_file == 0) { LOG(ALL, ERROR) << "Failed to open database file" << endl; return; } m_symbol_code[GLOBAL_SCOPE] = SYMBOL_FREE_RECORD + 1; m_code_symbol[SYMBOL_FREE_RECORD + 1] = GLOBAL_SCOPE; // Check if file is empty m_db_file.seekg(0, ios::end); if (m_db_file.tellg() == 0) { m_db_file.seekg(0, ios::beg); m_db_modified = true; return; // File newly created } m_do_existing_file = true; // Load symbol table if (load_symbols() != 0) { LOG(ALL, ERROR) << "Failed to load file table" << endl; return; } // Load the file table if (load_files() != 0) { LOG(ALL, ERROR) << "Failed to load file table" << endl; return; } m_db_file.seekg(m_st_lower, ios::beg); } /* * FUNCTION: DbInf::load_symbols * * DESCRIPTION: This function reads the symbol table from the database file. * IN: * IN-OUT: * RETURN CODE: 0 on success. 1 otherwise */ int DbInf::load_symbols () { file_ptr_t cur; vector buffer(BUFFER_SIZE); vector::iterator it; // Get symbol table boundaries m_db_file.seekg((-4) * (int)sizeof(file_ptr_t), ios::end); m_db_file.read(&m_st_lower, sizeof(file_ptr_t)); m_db_file.read(&m_st_upper, sizeof(file_ptr_t)); // Go to start of symbol table m_db_file.seekg(m_st_lower, ios::beg); cur = m_st_lower; // Populate symbol table while (cur < m_st_upper) { file_ptr_t old_cur; old_cur = cur; // Fill the buffer if (m_st_upper - cur <= BUFFER_SIZE) { m_db_file.read(&buffer[0], m_st_upper - cur); buffer.resize(m_st_upper - cur); cur += m_st_upper - cur; } else { m_db_file.read(&buffer[0], BUFFER_SIZE); buffer.resize(BUFFER_SIZE); cur += BUFFER_SIZE; } it = buffer.begin(); while (it != buffer.end()) { size_t i; vector::iterator it2; string symbol_name; symbol_code_t symbol_code; // Find end of symbol it2 = (char*)(::find(it, buffer.end(), '\0')); if (it2 == (char*)buffer.end()) { cur = cur - (buffer.end() - it); m_db_file.seekg(cur, ios::beg); break; } symbol_name.assign((char*)it, it2 - (char*)it); // Do we have enough characters in the buffer to process one code? if (buffer.end() - (Uint8*)it2 < (int)sizeof(symbol_code_t)) { cur = cur - (buffer.end() - it); m_db_file.seekg(cur, ios::beg); break; } it = (Uint8*)it2 + 1; symbol_code = 0; // Get symbol code for (i = 0; i < sizeof(symbol_code); ++i) { symbol_code |= ((symbol_code_t)*it) << (8 * i); ++it; } m_symbol_code[symbol_name] = symbol_code; m_code_symbol[symbol_code] = symbol_name; } } return 0; } /* * FUNCTION: DbInf::load_files * * DESCRIPTION: This function reads the file table from the database file. * IN: * IN-OUT: * RETURN CODE: 0 on success. 1 otherwise */ int DbInf::load_files () { string filename; time_t time_stamp; // Get symbol table boundaries m_db_file.seekg((-2) * (int)sizeof(file_ptr_t), ios::end); m_db_file.read(&m_ft_lower , sizeof(file_ptr_t)); m_db_file.read(&m_ft_upper, sizeof(file_ptr_t)); // Go to start of symbol table m_db_file.seekg(m_ft_lower, ios::beg); // Populate symbol table while (m_db_file.tellg() <= (streampos)m_ft_upper) { getline(m_db_file, filename, '\0'); m_files.push_front(filename); m_db_file.read(&time_stamp, sizeof(time_t)); m_time_stamps[filename] = time_stamp; } m_files_copy = m_files; return 0; } /* * FUNCTION: DbInf::add_entry * * DESCRIPTION: This function adds an entry in the database. It should be * called directly from a parser module. * * IN: type The symbol type * symbol The symbol name * symbol_length The length of the symbol * scope The scope in which the symbol appears * scope_length The length of the scope * file The file containing the symbol * lineno The line nbr where is the symbol * * IN-OUT: * RETURN CODE: 0 on success. 1 on error */ int DbInf::add_entry (const symbol_type_t type, const char* symbol, const size_t symbol_length, const char* scope, const size_t scope_length, const line_nbr_t lineno) { static string tmp_symbol; static string tmp_scope; symbol_code_t symbol_code; symbol_code_t scope_code; symbol_code_t symbol_code_mask; symbol_type_t type_mask; line_nbr_t line_mask; size_t i; Uint8 my_byte; if (m_instance->m_db_modified == false) m_instance->m_db_modified = true; // Get the symbol code from the symbol table tmp_symbol.erase(); tmp_symbol.append(symbol, symbol_length); if ((symbol_code = m_instance->m_symbol_code[tmp_symbol]) == 0) { // Symbol is not in symbol table. Add it. symbol_code = (symbol_code_t)m_instance->m_symbol_code.size() + 2; m_instance->m_symbol_code[tmp_symbol] = symbol_code; m_instance->m_code_symbol[symbol_code] = tmp_symbol; } // Get the scope code from the symbol table tmp_scope.erase(); tmp_scope.append(scope, scope_length); scope_code = m_instance->m_symbol_code[tmp_scope]; if (m_instance->m_do_existing_file == true) { // This is a file being updated. if (m_instance->m_old_file != m_instance->m_file || m_instance->m_buffer.size() >= BUFFER_SIZE) { // Flush the buffer if needed if (m_instance->m_buffer.size() != 0) { if (m_instance->m_file != m_instance->m_old_file) { string tmp; tmp = m_instance->m_file; m_instance->m_file = m_instance->m_old_file; m_instance->update_records(); m_instance->m_file = tmp; } else m_instance->update_records(); } m_instance->m_old_file = m_instance->m_file; } // Add the record in the buffer for (i = 0; i < sizeof(symbol_code); ++i) { symbol_code_mask = 0xFF << (8*i); my_byte = (Uint8)((symbol_code & symbol_code_mask) >> (8*i)); m_instance->m_buffer.push_back(my_byte); } for (i = 0; i < sizeof(type); ++i) { type_mask = 0xFF << (8*i); my_byte = (Uint8)((type & type_mask) >> (8*i)); m_instance->m_buffer.push_back(my_byte); } for (i = 0; i < sizeof(scope_code); ++i) { symbol_code_mask = 0xFF << (8*i); my_byte = (Uint8)((scope_code & symbol_code_mask) >> (8*i)); m_instance->m_buffer.push_back(my_byte); } for (i = 0; i < sizeof(lineno); ++i) { line_mask = 0xFF << (8*i); my_byte = (Uint8)((lineno & line_mask) >> (8*i)); m_instance->m_buffer.push_back(my_byte); } } else { if (m_instance->m_old_file != m_instance->m_file) { symbol_code_t null_code = 0; // Flush the buffer if (m_instance->m_db_file.write(&m_instance->m_buffer[0], m_instance->m_buffer.size()) == 0) { abort(); } m_instance->m_buffer.clear(); m_instance->m_st_lower = m_instance->m_db_file.tellg(); // Write file name. if (m_instance->m_db_file.write(&null_code, sizeof(symbol_code_t)) == 0) { abort(); } m_instance->m_db_file << m_instance->m_file.c_str() << '\0'; m_instance->m_old_file = m_instance->m_file; } // Add a record in the buffer for (i = 0; i < sizeof(symbol_code); ++i) { symbol_code_mask = 0xFF << (8*i); my_byte = (Uint8)((symbol_code & symbol_code_mask) >> (8*i)); m_instance->m_buffer.push_back(my_byte); } for (i = 0; i < sizeof(type); ++i) { type_mask = 0xFF << (8*i); my_byte = (Uint8)((type & type_mask) >> (8*i)); m_instance->m_buffer.push_back(my_byte); } for (i = 0; i < sizeof(scope_code); ++i) { symbol_code_mask = 0xFF << (8*i); my_byte = (Uint8)((scope_code & symbol_code_mask) >> (8*i)); m_instance->m_buffer.push_back(my_byte); } for (i = 0; i < sizeof(lineno); ++i) { line_mask = 0xFF << (8*i); my_byte = (Uint8)((lineno & line_mask) >> (8*i)); m_instance->m_buffer.push_back(my_byte); } // Do we need to flush the buffer? if (m_instance->m_buffer.size() >= BUFFER_SIZE) { if (m_instance->m_db_file.write(&m_instance->m_buffer[0], m_instance->m_buffer.size()) == 0) { abort(); } m_instance->m_buffer.clear(); m_instance->m_st_lower = m_instance->m_db_file.tellg(); } } return 0; } /* * FUNCTION: DbInf::find * * DESCRIPTION: Find a series of matches for a given symbol and a given type * * IN: symbol The symbol * type The type of the symbol * IN-OUT: result A queueue object of Entry objects that will * contain the matches * RETURN CODE: */ void DbInf::find (const string& symbol, const symbol_type_t type, list& result) { match_t match; static string match_file; symbol_code_t symbol_code; vector buffer(BUFFER_SIZE); file_ptr_t cur = 0; if (result.empty() == false) result.erase(result.begin(), result.end()); // Get the code associated with the symbol. if (m_symbol_code.find(symbol) == m_symbol_code.end()) return; symbol_code = m_symbol_code[symbol]; // Iterate the database records. m_db_file.seekg(0, ios::beg); while(cur < m_st_lower) { symbol_type_t type2; symbol_code_t symbol_code2; symbol_code_t scope_code; vector::iterator it; // Fill the buffer if (m_st_lower - cur <= BUFFER_SIZE) { m_db_file.read(&buffer[0], m_st_lower - cur); buffer.resize(m_st_lower - cur); cur = m_st_lower; } else { m_db_file.read(&buffer[0], BUFFER_SIZE); buffer.resize(BUFFER_SIZE); cur += BUFFER_SIZE; } it = buffer.begin(); while (it != buffer.end()) { size_t i; // Do we have enough characters in the buffer to process one record? if (buffer.end() - it < (int)RECORD_LENGTH) { cur = cur - (buffer.end() - it); m_db_file.seekg(cur, ios::beg); break; } symbol_code2 = 0; for (i = 0; i < sizeof(symbol_code2); ++i) { symbol_code2 |= ((symbol_code_t)*it) << (8 * i); ++it; } if (symbol_code2 == SYMBOL_NEW_FILE) { // This is a new file vector::iterator it2; it2 = (char*)(::find(it, buffer.end(), '\0')); if (it2 == (char*)buffer.end()) { cur = cur - (buffer.end() - it) - sizeof(symbol_code_t); m_db_file.seekg(cur, ios::beg); break; } match_file.assign((char*)it, it2 - (char*)it); it = (Uint8*)it2 + 1; continue; } if ((symbol_code2 != symbol_code && type != FUNC_CALLED) || (symbol_code2 == SYMBOL_FREE_RECORD)) { it += RECORD_LENGTH - sizeof(symbol_code2); continue; } type2 = (symbol_type_t)*it; ++it; if ((type != type2 && type != ANY && type != FUNC_CALLED) || (type == FUNC_CALLED && type2 != FUNC_CALL)) { it += RECORD_LENGTH - sizeof(symbol_code2) - sizeof(type); continue; } // Get scope scope_code = 0; for (i = 0; i < sizeof(scope_code); ++i) { scope_code |= ((symbol_code_t)*it) << (8 * i); ++it; } match.scope = m_code_symbol[scope_code]; if ((type == DEFINITION && match.scope != GLOBAL_SCOPE) || (type == FUNC_CALLED && match.scope != symbol)) { it += RECORD_LENGTH - sizeof(symbol_code2) - sizeof(type) - sizeof(scope_code); continue; } if (type == FUNC_CALLED) match.scope = m_code_symbol[symbol_code2]; // GLOBAL_SCOPE has the form "`GLOBAL_SCOPE". Get rid of 1st char if (match.scope == GLOBAL_SCOPE) match.scope = GLOBAL_SCOPE + 1; match.file = match_file; // Get the line nbr match.lineno = 0; for (i = 0; i < sizeof(line_nbr_t); ++i) { match.lineno |= ((line_nbr_t)*it) << (8 * i); ++it; } //match.lineno = *(line_nbr_t*)it; //it += sizeof(line_nbr_t); // Add an element in the match list result.push_back(match); } } } /* * FUNCTION: DbInf::flush * * DESCRIPTION: Flush the database file * * IN: * IN-OUT: * RETURN CODE: */ void DbInf::flush () { cont_string_symcode_t::iterator it_symbols; cont_string_time_t::iterator it_time_stamps; for (list::iterator it = m_files.begin(); it != m_files.end(); ++it) { // m_time_stamps[*it] = 0; m_db_modified = true; } m_files.erase(m_files.begin(), m_files.end()); // Return directly if database didn't change since opening if (m_db_modified == false) return; // Do we need to flush the buffer? if (m_buffer.size() != 0) { if (m_do_existing_file == true) { update_records(); if (m_db_file.tellg() > (streampos)m_st_lower) m_st_lower = m_db_file.tellg(); } else { m_db_file.write(&m_buffer[0], m_buffer.size()); if (m_do_existing_file == false) m_st_lower = m_db_file.tellg(); else { if (m_db_file.tellg() > (streampos)m_st_lower) m_st_lower = m_db_file.tellg(); } } } // Flush symbol table, file and time stamp table to the file. m_db_file.seekg(m_st_lower, ios::beg); /****************/ /* SYMBOL TABLE */ /****************/ for (it_symbols = m_symbol_code.begin(); it_symbols != m_symbol_code.end(); ++it_symbols) { // Dump symbol name m_db_file << it_symbols->first.c_str(); m_db_file << '\0'; // Dump symbol code m_db_file.write(&m_symbol_code[it_symbols->first], sizeof(symbol_code_t)); } m_st_upper = (file_ptr_t)m_db_file.tellg() - 1; /**************/ /* FILE TABLE */ /**************/ m_ft_lower = (file_ptr_t)m_db_file.tellg(); for (it_time_stamps = m_time_stamps.begin(); it_time_stamps != m_time_stamps.end(); ++it_time_stamps) { // Dump file name m_db_file << it_time_stamps->first.c_str(); m_db_file << '\0'; // Dump time stamp m_db_file.write(&it_time_stamps->second, sizeof(time_t)); } m_ft_upper = (file_ptr_t)m_db_file.tellg() - 1; // Dump table boundaries m_db_file.write(&m_st_lower, sizeof(file_ptr_t)); m_db_file.write(&m_st_upper, sizeof(file_ptr_t)); m_db_file.write(&m_ft_lower, sizeof(file_ptr_t)); m_db_file.write(&m_ft_upper, sizeof(file_ptr_t)); // Flush the file m_db_file.flush(); m_old_file.erase(); m_do_existing_file = true; load_files(); m_buffer.clear(); m_files_copy = m_files; } /* * FUNCTION: DbInf::get_timestamp * * DESCRIPTION: This function returns the last modification time stamp * associated with a file. * * IN: file The file name * IN-OUT: * RETURN CODE: The time stamp associated with the file. 0 if the file hasn't * been found. */ time_t DbInf::get_timestamp (const string& file) { return m_time_stamps[file]; } /* * FUNCTION: DbInf::add_timestamp * * DESCRIPTION: This function adds the last modification time stamp * associated with a file. * * IN: file The file name * timestamp The time stamp * INOUT: * RETURN CODE: */ void DbInf::add_timestamp (const string& file, const time_t timestamp) { m_time_stamps[file] = timestamp; } /* * FUNCTION: DbInf::set_file * * DESCRIPTION: This function indicates which file is being parsed * * IN: file The file being parsed * IN-OUT: * RETURN CODE: */ void DbInf::set_file (const string& file) { m_file = file; } /* * FUNCTION: DbInf::next_completion * * DESCRIPTION: This function finds the next symbol completing the given * stub. * * IN: stub The stub used for completion. * IN-OUT: * RETURN CODE: A symbol if completion symbol was found. An enpty * string otherwise. */ string DbInf::next_completion (const string& stub, int& index, int& total) { if ((stub != m_stub) || (m_completions.size() == 0)) { find_completions(stub); if (m_completions.size() == 0) { index = 0; total = 0; return ""; } m_it_completion = m_completions.begin(); m_completion_index = 1; } else { if (++m_it_completion == m_completions.end()) { m_it_completion = m_completions.begin(); m_completion_index = 1; } else ++m_completion_index; } index = m_completion_index; total = m_completions.size(); return *m_it_completion; } /* * FUNCTION: DbInf::prev_completion * * DESCRIPTION: This function finds the previous symbol completing the given * stub. * * IN: stub The stub used for completion. * index The match index * total The total number of match * IN-OUT: * RETURN CODE: A symbol if completion symbol was found. An enpty * string otherwise. */ string DbInf::prev_completion (const string& stub, int& index, int& total) { if ((stub != m_stub) || (m_completions.size() == 0)) { find_completions(stub); if (m_completions.size() == 0) { index = 0; total = 0; return ""; } m_it_completion = m_completions.end(); --m_it_completion; m_completion_index = m_completions.size(); } else { if (m_it_completion == m_completions.begin()) { m_it_completion = m_completions.end(); --m_it_completion; m_completion_index = m_completions.size(); } else { --m_it_completion; --m_completion_index; } } index = m_completion_index; total = m_completions.size(); return *m_it_completion; } /* * FUNCTION: DbInf::find_completions * * DESCRIPTION: Build a list of all completions matching the given stub and * sort this list. * * index The match index * total The total number of match * IN: stub The stub used for finding completions. * IN-OUT: * RETURN CODE: */ void DbInf::find_completions (const string& stub) { cont_string_symcode_t::iterator it; if (stub != m_stub) m_stub = stub; if (m_completions.size() != 0) m_completions.erase(m_completions.begin(), m_completions.end()); // Find completions for (it = m_symbol_code.begin(); it != m_symbol_code.end(); ++it) { if (it->first.size() < stub.size()) continue; if (it->first.compare(stub, 0, stub.size()) == 0) m_completions.push_back(it->first); } // Sort completions. m_completions.sort(); } /* * FUNCTION: DbInf::update_records * * DESCRIPTION: This function flushes all records stored in the buffer in the * existing database. This is done the following way: * 1) Write one record at the cuurent location. * 2) If the current location is a new file, go to the next place * in the database that has records associated with the current * file and execute step 1. * * It is possible that we exceed the old number of records in the * database. In that case, we just write all the records at the * current location. * Exceeding the old number of records occurs when we are further * in the database file than m_st_lower. * IN: * IN-OUT: * OUT: * RETURN CODE: */ void DbInf::update_records () { size_t i; unsigned index = 0; static string old_file; if (m_file != old_file) { old_file = m_file; m_db_file.flush(); find_free_place(); } if (m_db_file.tellg() >= (streampos)m_st_lower) { /* Just write all the records at that place */ m_db_file.write(&m_instance->m_buffer[0], m_instance->m_buffer.size()); m_buffer.clear(); m_st_lower = m_db_file.tellg(); m_db_file.flush(); return; } while (index < m_buffer.size()) { if ((file_ptr_t)m_db_file.tellg() < m_st_lower) { symbol_code_t symbol_code; /* Check if we can write here */ symbol_code = 0; for (i = 0; i < sizeof(symbol_code_t); ++i) { Uint8 c; m_db_file.read(&c, 1); symbol_code |= ((symbol_code_t)c) << (8 * i); } m_db_file.seekg((-1) * (int)sizeof(symbol_code_t), ios::cur); if (symbol_code == SYMBOL_NEW_FILE) { find_free_place(); if ((file_ptr_t)m_db_file.tellg() >= m_st_lower) { m_db_file.write(&m_instance->m_buffer[index], m_instance->m_buffer.size() - index); m_buffer.clear(); m_db_file.flush(); m_st_lower = m_db_file.tellg(); return; } } else if (symbol_code != SYMBOL_FREE_RECORD) m_db_file.seekg(RECORD_LENGTH, ios::cur); } /* Write one record */ m_db_file.write(&m_instance->m_buffer[index], RECORD_LENGTH); index += RECORD_LENGTH; if ((file_ptr_t)m_db_file.tellg() > m_st_lower) m_st_lower = m_db_file.tellg(); } m_instance->m_buffer.clear(); m_db_file.clear(); m_db_file.flush(); } /* * FUNCTION: find_free_place * * DESCRIPTION: This function finds a place in the database that is suitable * for writing one record associated with the current file. * * IN: * IN-OUT: * OUT: * RETURN CODE: * SIDE EFFECT: */ void DbInf::find_free_place () { for(;;) { symbol_code_t symbol_code; // If we exceed the old database size, then this is a valid place. if ((file_ptr_t)m_db_file.tellg() >= m_st_lower) { for (size_t i = 0; i < sizeof(symbol_code_t); ++i) { if (m_db_file.write(&((Uint8*)&SYMBOL_NEW_FILE)[i], 1) == 0) abort(); } m_db_file << m_file << '\0'; m_db_file.flush(); break; } /* Get this symbol */ symbol_code = 0; for (size_t i = 0; i < sizeof(symbol_code_t); ++i) { Uint8 c; m_db_file.read(&c, 1); symbol_code |= ((symbol_code_t)c) << (8 * i); } if (symbol_code == SYMBOL_NEW_FILE) { string filename; /* Get the file name */ getline(m_db_file, filename, '\0'); if (filename == m_file) break; // We found a good place } else { // Go to the next record m_db_file.seekg(RECORD_LENGTH - sizeof(symbol_code_t), ios::cur); } } } /* * FUNCTION: DbInf::invalidate_records * * DESCRIPTION: This function invalidates all records associated with the * files passed as argument. This should be called whenever a * set of files is about to be re-scanned following modifications. * * IN: files * IN-OUT: * OUT: * RETURN CODE: */ void DbInf::invalidate_records (const list& files) { symbol_code_t code; vector buffer(BUFFER_SIZE); vector::iterator it; bool invalidate = false; file_ptr_t cur = 0; symbol_code_t free_record = SYMBOL_FREE_RECORD; list invalid_files; list::iterator it2; // Append all files that have been removed from freescope.files invalid_files = files; invalid_files.insert(invalid_files.end(), m_files_copy.begin(), m_files_copy.end()); for (it2 = m_files_copy.begin(); it2 != m_files_copy.end(); ++it2) { m_time_stamps[*it2] = 0; m_files.remove(*it2); } if (invalid_files.size() == 0 && m_files.size() == 0) return; m_db_file.seekg(0, ios::beg); while (cur < m_st_lower) { bool mod; file_ptr_t old_cur; old_cur = cur; // Fill the buffer if (m_st_lower - cur <= BUFFER_SIZE) { m_db_file.read(&buffer[0], m_st_lower - cur); buffer.resize(m_st_lower - cur); cur += m_st_lower - cur; } else { m_db_file.read(&buffer[0], BUFFER_SIZE); buffer.resize(BUFFER_SIZE); cur += BUFFER_SIZE; } it = buffer.begin(); mod = false; while (it != buffer.end()) { size_t i; // Do we have enough characters in the buffer to process one record? if (buffer.end() - it < (int)RECORD_LENGTH) { cur = cur - (buffer.end() - it); m_db_file.seekg(cur, ios::beg); break; } code = 0; // Get symbol code for (i = 0; i < sizeof(code); ++i) { code |= ((symbol_code_t)*it) << (8 * i); ++it; } if (code == SYMBOL_NEW_FILE) { string tmp_file; vector::iterator it2; // This is a new file it2 = (char*)(::find(it, buffer.end(), '\0')); if (it2 == (char*)buffer.end()) { cur = cur - (buffer.end() - it) - sizeof(symbol_code_t); m_db_file.seekg(cur, ios::beg); break; } tmp_file.assign((char*)it, it2 - (char*)it); it = (Uint8*)it2 + 1; // Is this a file in the list of modified files? if ((::find(invalid_files.begin(), invalid_files.end(), tmp_file) != invalid_files.end())) { invalidate = true; } else { invalidate = false; } } else { if (invalidate == true) { it -= sizeof(code); for (i = 0; i < sizeof(symbol_code_t); ++i) { *it = ((Uint8*)&free_record)[i]; ++it; } mod = true; } it += sizeof(symbol_type_t) + sizeof(symbol_code_t) + sizeof(line_nbr_t); } } // while iterate buffer if (mod == true) { // The buffer has been modified. Flush it. m_db_file.seekg(old_cur, ios::beg); m_db_file.write(&buffer[0], cur - old_cur); m_db_file.flush(); } } // while m_db_file.flush(); m_db_file.seekg(0, ios::beg); } /* * FUNCTION: DbInf::is_file_in_db * * DESCRIPTION: This function checks if a given file is already part of the * database. * * IN: file The file to check for. * IN-OUT: * OUT: * RETURN CODE: true if file is already in databse. false otherwise. * SIDE EFFECT: */ bool DbInf::is_file_in_db (string file) { list::iterator it; if (m_do_existing_file == false) return true; it = ::find(m_files_copy.begin(), m_files_copy.end(), file); if (it != m_files_copy.end()) { m_files_copy.erase(it); return true; } return false; } void DbInf::dump () { m_db_file.seekg(0, ios::beg); cout.setf(ios::hex, ios::basefield); cout << "SYMBOL TABLE STARTS AT 0x" << m_st_lower << endl << endl; cout.setf(ios::dec, ios::basefield); while ((file_ptr_t)m_db_file.tellg() < m_st_lower) { symbol_code_t symbol_code; symbol_code_t scope_code; symbol_type_t type; line_nbr_t lineno; unsigned int i; // Read symbol code symbol_code = 0; for (i = 0; i < sizeof(symbol_code); ++i) { Uint8 c; m_db_file.read(&c, 1); symbol_code |= ((symbol_code_t)c) << (8 * i); } if (symbol_code == SYMBOL_NEW_FILE) { string filename; /* Get the file name */ getline(m_db_file, filename, '\0'); cout << endl << "*** " << filename << endl << endl; continue; } // Get type m_db_file.read(&type, sizeof(type)); // Read scope code scope_code = 0; for (i = 0; i < sizeof(scope_code); ++i) { Uint8 c; m_db_file.read(&c, 1); scope_code |= ((symbol_code_t)c) << (8 * i); } // Get line number lineno = 0; for (i = 0; i < sizeof(lineno); ++i) { Uint8 c; m_db_file.read(&c, 1); lineno |= ((line_nbr_t)c) << (8 * i); } cout.setf(ios::hex, ios::basefield); cout << "0x" << m_db_file.tellg(); cout.setf(ios::dec, ios::basefield); cout << " -- " << m_code_symbol[symbol_code] << " " << (int)type << " " << m_code_symbol[scope_code] << " " << lineno << endl; } }