#include "ace/FILE_Connector.h" #include "ace/Message_Block.h" #include "ace/OS_NS_stdlib.h" #include "ace/OS_NS_string.h" #include "ace/Singleton.h" #include "ace/Synch.h" #include "ace/Unbounded_Queue.h" #ifndef JAWS_BUILD_DLL #define JAWS_BUILD_DLL #endif #include "jaws3/Config_File.h" #include "jaws3/Symbol_Table.h" // = Helper class to manage "constant" strings. class JAWS_strings { public: ~JAWS_strings (void) { void *p; while (this->queue_.dequeue_head (p) != -1) ACE_OS::free (p); } const ACE_TCHAR * duplicate (const ACE_TCHAR *s) { void **x; const ACE_TCHAR *d = 0; ACE_Unbounded_Queue_Iterator iter (this->queue_); while (iter.next (x)) { d = (const ACE_TCHAR *) *x; if (ACE_OS::strcmp (d, s) == 0) break; d = 0; iter.advance (); } if (d == 0) { d = ACE_OS::strdup (s); this->queue_.enqueue_tail ((void *) d); } return d; } private: ACE_Unbounded_Queue queue_; }; // = Underlying implementation class. class JAWS_Config_File_Impl { public: JAWS_Config_File_Impl (const ACE_TCHAR *config_file); ~JAWS_Config_File_Impl (void); int find (const ACE_TCHAR *key, const ACE_TCHAR *&value); void parse_file (void); void reset (void); void dump (void); enum { JAWS_CONFIG_FILE_SYMBOL_TABLE_SIZE = 211 }; private: ACE_FILE_Addr faddr_; JAWS_strings *strings_; JAWS_Symbol_Table *symbols_; }; JAWS_Config_File_Impl::JAWS_Config_File_Impl (const ACE_TCHAR *config_file) : faddr_ (config_file) , strings_ (0) , symbols_ (0) { this->strings_ = new JAWS_strings; this->symbols_ = new JAWS_Symbol_Table (JAWS_CONFIG_FILE_SYMBOL_TABLE_SIZE); this->parse_file (); } JAWS_Config_File_Impl::~JAWS_Config_File_Impl (void) { delete this->symbols_; this->symbols_ = 0; delete this->strings_; this->strings_ = 0; } int JAWS_Config_File_Impl::find (const ACE_TCHAR *key, const ACE_TCHAR *&value) { return this->symbols_->find (key, value); } void JAWS_Config_File_Impl::parse_file (void) { ACE_FILE_Connector fconnector; ACE_FILE_IO fio; if (fconnector.connect ( fio , this->faddr_ , 0 , ACE_Addr::sap_any , 0 , O_RDONLY ) == -1) return; ACE_Message_Block buffer (8192); ACE_Message_Block line (4096); ssize_t count = 0; const ACE_TCHAR *sym_name; const ACE_TCHAR *sym_value; int last_line_was_read = 0; ACE_TCHAR *end_of_current_line = 0; ACE_TCHAR *p = 0; while (last_line_was_read || (count = fio.recv (buffer.wr_ptr (), buffer.space () - 2)) >= 0) { end_of_current_line = 0; // Make sure input is newline terminated if it is the last line, // and always null terminated. if (! last_line_was_read) { if (count > 0) { buffer.wr_ptr (count); // Scan forward for at least one newline character p = buffer.rd_ptr (); while (p != buffer.wr_ptr ()) { if (*p == '\n') break; p++; } if (p == buffer.wr_ptr ()) continue; end_of_current_line = p; } else { if (buffer.wr_ptr ()[-1] != '\n') { buffer.wr_ptr ()[0] = '\n'; buffer.wr_ptr (1); } last_line_was_read = 1; } buffer.wr_ptr ()[0] = '\0'; } if (end_of_current_line == 0) { end_of_current_line = buffer.rd_ptr (); while (*end_of_current_line != '\n') end_of_current_line++; } // If buffer is not pointing to a continuation line, or there is // no more input, then can commit the scanned configuration // line. if (line.length () != 0 && ((last_line_was_read && buffer.length () == 0) || (buffer.rd_ptr ()[0] != ' ' && buffer.rd_ptr ()[0] != '\t'))) { ACE_TCHAR *name = 0; ACE_TCHAR *value = 0; name = line.rd_ptr (); for (p = name; *p != '\0'; p++) { if (*p == '=') { line.rd_ptr (p+1); while (p != name && (p[-1] == ' ' || p[-1] == '\t')) p--; *p = '\0'; } } if (*name) { value = line.rd_ptr (); while (*value == ' ' || *value == '\t') value++; p = line.wr_ptr (); while (p != value && (p[-1] == ' ' || p[-1] == '\t')) p--; *p = '\0'; sym_name = this->strings_->duplicate (name); sym_value = this->strings_->duplicate (value); this->symbols_->rebind (sym_name, sym_value); } line.reset (); } // If we are done, we are done! if (last_line_was_read && buffer.length () == 0) break; // If the buffer is pointing at a comment line, ignore it. if (buffer.rd_ptr ()[0] == '#' || buffer.rd_ptr ()[0] == '\n' || (buffer.rd_ptr ()[0] == '\r' && buffer.rd_ptr ()[1] == '\n')) { buffer.rd_ptr (end_of_current_line + 1); buffer.crunch (); continue; } // Whatever is left is either the start of a name-value-pair or a // continuation of one. line.copy (buffer.rd_ptr (), end_of_current_line - buffer.rd_ptr ()); p = line.wr_ptr (); while (p != line.rd_ptr () && (p[-1] == ' ' || p[-1] == '\t')) p--; line.wr_ptr (p); line.wr_ptr ()[0] = '\0'; buffer.rd_ptr (end_of_current_line + 1); buffer.crunch (); } fio.close (); } void JAWS_Config_File_Impl::reset (void) { delete this->symbols_; delete this->strings_; this->strings_ = new JAWS_strings; this->symbols_ = new JAWS_Symbol_Table (JAWS_CONFIG_FILE_SYMBOL_TABLE_SIZE); this->parse_file (); } void JAWS_Config_File_Impl::dump (void) { JAWS_SYMBOL_TABLE_ITERATOR iter (*this->symbols_); JAWS_SYMBOL_TABLE_ENTRY *entry = 0; while (iter.next (entry)) { ACE_DEBUG ((LM_DEBUG, "[%D|%t] %s=%s\n", entry->ext_id_, entry->int_id_)); iter.advance (); } } JAWS_Config_File::JAWS_Config_File (const ACE_TCHAR *config_file, const ACE_TCHAR *config_dir) { ACE_TCHAR filename[MAXPATHLEN]; ACE_OS::strcpy (filename, config_dir); ACE_OS::strcat (filename, config_file); this->impl_ = new JAWS_Config_File_Impl (filename); } int JAWS_Config_File::find (const ACE_TCHAR *key, const ACE_TCHAR *&value) { return this->impl_->find (key, value); } void JAWS_Config_File::reset (void) { this->impl_->reset (); } void JAWS_Config_File::dump (void) { this->impl_->dump (); }