diff options
author | schmidt <douglascraigschmidt@users.noreply.github.com> | 2001-04-14 23:36:59 +0000 |
---|---|---|
committer | schmidt <douglascraigschmidt@users.noreply.github.com> | 2001-04-14 23:36:59 +0000 |
commit | e4c8f52beb46ca2d0c00158f8ec72735b792db6c (patch) | |
tree | ceec871cef7a5eab4acb6dc6cac0b54671463e33 | |
parent | c43c12c2fde446ac6a7976114b7e80df99ae2045 (diff) | |
download | ATCD-e4c8f52beb46ca2d0c00158f8ec72735b792db6c.tar.gz |
ChangeLogTag:Sat Apr 14 18:31:15 2001 Douglas C. Schmidt <schmidt@tango.doc.wustl.edu>
-rw-r--r-- | ace/Configuration.cpp | 769 | ||||
-rw-r--r-- | ace/Configuration.h | 115 | ||||
-rw-r--r-- | ace/Configuration_Import_Export.cpp | 552 | ||||
-rw-r--r-- | ace/Configuration_Import_Export.h | 225 | ||||
-rw-r--r-- | ace/Makefile | 1 | ||||
-rw-r--r-- | tests/Config_Test.cpp | 942 | ||||
-rw-r--r-- | tests/Config_Test.h | 66 |
7 files changed, 1993 insertions, 677 deletions
diff --git a/ace/Configuration.cpp b/ace/Configuration.cpp index dcf05dd12a2..5574b8dc936 100644 --- a/ace/Configuration.cpp +++ b/ace/Configuration.cpp @@ -165,305 +165,289 @@ ACE_Configuration::expand_path (const ACE_Configuration_Section_Key& key, ACE_Configuration_Section_Key& key_out, int create) { + const ACE_TCHAR* begin = path_in.fast_rep (); + const ACE_TCHAR* end = 0; + // Make a copy of key ACE_Configuration_Section_Key current_section = key; - ACE_TString data (path_in); - ACE_TCHAR *pData = (ACE_TCHAR *) data.c_str (); - ACE_Tokenizer parser (pData); - parser.delimiter_replace ('\\', '\0'); - parser.delimiter_replace ('/', '\0'); - - for (ACE_TCHAR *temp = parser.next (); - temp != 0; - temp = parser.next ()) + + // recurse through the path + while (1) { + // Detmine the begin/ending of the key name + end = ACE_OS::strchr (begin, ACE_LIB_TEXT ('\\')); + size_t length = end ? (size_t)(end-begin) : ACE_OS::strlen (begin); + + // Make sure length is not 0 + if (!length) + return -1; + + ACE_TString section (begin, length); + // Open the section + ACE_Configuration_Section_Key child_section; if (open_section (current_section, - temp, + section.fast_rep (), create, - key_out)) + child_section)) return -1; - current_section = key_out; - } - - return 0; -} -int -ACE_Configuration::validate_name (const ACE_TCHAR *name) -{ - const ACE_TCHAR *pos; - - for (pos = name; - // Make sure it doesn't contain any invalid characters - *pos != '\0'; - pos++) - if (ACE_OS::strchr (ACE_LIB_TEXT ("\\]["), *pos)) - return -1; + current_section = child_section; - // Make sure its not too long. - if (pos - name > ACE_Configuration::MAX_NAME_LEN) - return -2; + // If end is NULL, we are done, return the result + if (!end) + { + key_out = current_section; + break; + } + begin = end + 1; + } return 0; } int -ACE_Configuration::export_section (const ACE_Configuration_Section_Key& section, - const ACE_TString& path, - FILE* out) +ACE_Configuration::validate_name (const ACE_TCHAR* name) { - // don't export the root - if (path.length ()) + const ACE_TCHAR* pos = name; + // make sure it doesn't contain any invalid characters + while (*pos) { - // Write out the section header - ACE_TString header = ACE_LIB_TEXT ("["); - header += path; - header += ACE_LIB_TEXT ("]"); - header += ACE_LIB_TEXT (" \n"); - if (ACE_OS::fputs (header.fast_rep (), out) < 0) + if (ACE_OS::strchr (ACE_LIB_TEXT ("\\]["), *pos)) return -1; - // Write out each value - int index = 0; - ACE_TString name; - VALUETYPE type; - ACE_TString line; - ACE_TCHAR int_value[32]; - ACE_TCHAR bin_value[3]; - void* binary_data; - u_int binary_length; - ACE_TString string_value; - - while (!enumerate_values (section, index, name, type)) - { - line = ACE_LIB_TEXT ("\"") + name + ACE_LIB_TEXT ("\"="); - switch (type) - { - case INTEGER: - { - u_int value; - if (get_integer_value (section, name.fast_rep (), value)) - return -2; - - ACE_OS::sprintf (int_value, ACE_LIB_TEXT ("%08x"), value); - line += ACE_LIB_TEXT ("dword:"); - line += int_value; - break; - } - case STRING: - { - if (get_string_value (section, - name.fast_rep (), - string_value)) - return -2; - - line += ACE_LIB_TEXT ("\""); - line += string_value + ACE_LIB_TEXT ("\""); - break; - } -#if defined (ACE_WIN32) - case INVALID: -#endif /* ACE_WIN32 */ - case BINARY: - { - // not supported yet - maybe use BASE64 codeing? - if (get_binary_value (section, - name.fast_rep (), - binary_data, - binary_length)) - return -2; - - line += ACE_LIB_TEXT ("hex:"); - - u_char *ptr = (u_char *) binary_data; - while (binary_length) - { - if (ptr != binary_data) - line += ACE_LIB_TEXT (","); - - ACE_OS::sprintf (bin_value, ACE_LIB_TEXT ("%02x"), *ptr); - line += bin_value; - --binary_length; - ++ptr; - } - delete (char *) binary_data; - break; - } - default: - return -3; - } - - line += ACE_LIB_TEXT ("\n"); - if (ACE_OS::fputs (line.fast_rep (), out) < 0) - return -4; - - index++; - } + pos++; } - // Export all sub sections - int index = 0; - ACE_TString name; - ACE_Configuration_Section_Key sub_key; - ACE_TString sub_section; - - while (!enumerate_sections (section, index, name)) - { - ACE_TString sub_section (path); - if (path.length ()) - sub_section += ACE_LIB_TEXT ("\\"); - - sub_section += name; - if (open_section (section, name.fast_rep (), 0, sub_key)) - return -5; - - if (export_section (sub_key, sub_section.fast_rep (), out)) - return -6; - - index++; - } + // Make sure its not too long + if (pos - name > 255) + return -2; return 0; } -int -ACE_Configuration::export_config (const ACE_TCHAR* filename) -{ - FILE *out = ACE_OS::fopen (filename, ACE_LIB_TEXT ("w")); - if (!out) - return -1; - int result = export_section (root_, ACE_LIB_TEXT (""), out); - ACE_OS::fclose (out); - return result; +const ACE_Configuration_Section_Key& +ACE_Configuration::root_section (void) +{ + return root_; } -int -ACE_Configuration::import_config (const ACE_TCHAR* filename) +/** + * Determine if the contents of this object is the same as the + * contents of the object on the right hand side. + * Returns 1 (True) if they are equal and 0 (False) if they are not equal + */ +int ACE_Configuration::operator==(const ACE_Configuration& rhs) const { - FILE* in = ACE_OS::fopen (filename, ACE_LIB_TEXT ("r")); - if (!in) - return -1; + int rc = true; + int sectionIndex = 0; + ACE_TString sectionName; - // @@ XXX - change this to a dynamic buffer - ACE_TCHAR buffer[4096]; - ACE_Configuration_Section_Key section; - while (ACE_OS::fgets (buffer, 4096, in)) - { - // Check for a comment - if (buffer[0] == ACE_LIB_TEXT (';') || buffer[0] == ACE_LIB_TEXT ('#')) - continue; + const ACE_Configuration_Section_Key& rhsRoot = const_cast<ACE_Configuration&>(rhs).root_section(); + ACE_Configuration_Section_Key rhsSection; + ACE_Configuration_Section_Key thisSection; - if (buffer[0] == ACE_LIB_TEXT ('[')) + // loop through each section in this object + while( (rc) && + (!const_cast<ACE_Configuration*>(this)->enumerate_sections(this->root_, + sectionIndex, + sectionName)) ) + { + // find that section in the rhs object + if(const_cast<ACE_Configuration&>(rhs).open_section(rhsRoot, + sectionName.c_str(), + 0, + rhsSection) != 0) { - // We have a new section here, strip out the section name - ACE_TCHAR* end = ACE_OS::strrchr (buffer, ACE_LIB_TEXT (']')); - if (!end) - { - ACE_OS::fclose (in); - return -3; - } - *end = 0; - - if (expand_path (root_, buffer + 1, section, 1)) - { - ACE_OS::fclose (in); - return -3; - } - - continue; + // If the rhs object does not contain the section then we are not equal. + rc = false; } - - if (buffer[0] == ACE_LIB_TEXT ('"')) + else if(const_cast<ACE_Configuration*>(this)->open_section(this->root_, + sectionName.c_str(), + 0, + thisSection) != 0) { - // we have a value - ACE_TCHAR* end = ACE_OS::strchr (buffer+1, '"'); - if (!end) // no closing quote, not a value so just skip it - continue; - - // null terminate the name - *end = 0; - ACE_TCHAR* name = buffer + 1; - end+=2; - // determine the type - if (*end == '\"') + // if there is some error opening the section in this object + rc = false; + } + else + { + // Well the sections match + int valueIndex = 0; + ACE_TString valueName; + VALUETYPE valueType; + VALUETYPE rhsType; + + // Enumerate each value in this section + while((rc) && + (!const_cast<ACE_Configuration*>(this)->enumerate_values(thisSection, + valueIndex, + valueName, + valueType))) { - // string type - // truncate trailing " - ++end; - ACE_TCHAR* trailing = ACE_OS::strrchr (end, '"'); - if (trailing) - *trailing = 0; - if (set_string_value (section, name, end)) + // look for the same value in the rhs section + if(const_cast<ACE_Configuration&>(rhs).find_value(rhsSection, + valueName.c_str(), + rhsType) != 0) { - ACE_OS::fclose (in); - return -4; + // We're not equal if the same value cannot + // be found in the rhs object. + rc = false; } - } - else if (ACE_OS::strncmp (end, ACE_LIB_TEXT ("dword:"), 6) == 0) - { - // number type - ACE_TCHAR* endptr = 0; - u_int value = ACE_OS::strtoul (end + 6, &endptr, 16); - if (set_integer_value (section, name, value)) + else if (valueType != rhsType) { - ACE_OS::fclose (in); - return -4; + // we're not equal if the types do not match. + rc = false; } - } - else if (ACE_OS::strncmp (end, ACE_LIB_TEXT ("hex:"), 4) == 0) - { - // binary type - u_int string_length = ACE_OS::strlen (end + 4); - // divide by 3 to get the actual buffer length - u_int length = string_length / 3; - u_int remaining = length; - u_char* data = new u_char[length]; - u_char* out = data; - ACE_TCHAR* inb = end + 4; - ACE_TCHAR* endptr = 0; - while (remaining) + else { - u_char charin = (u_char) ACE_OS::strtoul (inb, &endptr, 16); - *out = charin; - ++out; - --remaining; - inb += 3; - } - if (set_binary_value (section, name, data, length)) + // finally compare values. + if(valueType == STRING) + { + ACE_TString thisString, rhsString; + if(const_cast<ACE_Configuration*>(this)->get_string_value(thisSection, + valueName.c_str(), + thisString) != 0) + { + // we're not equal if we cannot get this string + rc = false; + } + else if(const_cast<ACE_Configuration&>(rhs).get_string_value(rhsSection, + valueName.c_str(), + rhsString) != 0) + { + // we're not equal if we cannot get rhs string + rc = false; + } + rc = thisString == rhsString; + } + else if (valueType == INTEGER) + { + u_int thisInt, rhsInt; + if(const_cast<ACE_Configuration*>(this)->get_integer_value(thisSection, + valueName.c_str(), + thisInt) != 0) + { + // we're not equal if we cannot get this int + rc = false; + } + else if(const_cast<ACE_Configuration&>(rhs).get_integer_value(rhsSection, + valueName.c_str(), + rhsInt) != 0) + { + // we're not equal if we cannot get rhs int + rc = false; + } + rc = thisInt == rhsInt; + } + else if(valueType == BINARY) + { + + void* thisData; + void* rhsData; + u_int thisLength, rhsLength; + if(const_cast<ACE_Configuration*>(this)->get_binary_value(thisSection, + valueName.c_str(), + thisData, + thisLength) != 0) + { + // we're not equal if we cannot get this data + rc = false; + } + else if(const_cast<ACE_Configuration&>(rhs).get_binary_value(rhsSection, + valueName.c_str(), + rhsData, + rhsLength) != 0) + { + // we're not equal if we cannot get this data + rc = false; + } + + // are the length's the same? + if(rc = (thisLength == rhsLength)) + { + unsigned char* thisCharData = (unsigned char*)thisData; + unsigned char* rhsCharData = (unsigned char*)rhsData; + // yes, then check each element + for(u_int count = 0; (rc) && (count < thisLength); count++) + { + rc = (*(thisCharData + count) == *(rhsCharData + count)); + } + }// end if the length's match + } + // We should never have valueTypes of INVALID, therefore + // we're not comparing them. How would we since we have + // no get operation for invalid types. + // So, if we have them, we guess they are equal. + + }// end else if values match. + + valueIndex++; + + }// end value while loop + + // look in the rhs for values not in this + valueIndex = 0; + while((rc) && + (!const_cast<ACE_Configuration&>(rhs).enumerate_values(rhsSection, + valueIndex, + valueName, + rhsType))) + { + // look for the same value in this section + if(const_cast<ACE_Configuration*>(this)->find_value(thisSection, + valueName.c_str(), + valueType) != 0) { - ACE_OS::fclose (in); - return -4; + // We're not equal if the same value cannot + // be found in the rhs object. + rc = false; } - } - else - // invalid type, ignore - continue; - } - } + valueIndex++; + }// end while for rhs values not in this. + + }// end else if sections match. + + sectionIndex++; - if (ferror (in)) + }// end section while loop + + // Finally, make sure that there are no sections in rhs that do not exist in this + sectionIndex = 0; + while( (rc) && + (!const_cast<ACE_Configuration&>(rhs).enumerate_sections(rhsRoot, + sectionIndex, + sectionName)) ) { - ACE_OS::fclose (in); - return -1; + // find the section in this + if(const_cast<ACE_Configuration*>(this)->open_section(this->root_, + sectionName.c_str(), + 0, + thisSection) != 0) + { + // if there is some error opening the section in this object + rc = false; + } + else if(const_cast<ACE_Configuration&>(rhs).open_section(rhsRoot, + sectionName.c_str(), + 0, + rhsSection) != 0) + { + // If the rhs object does not contain the section then we are not equal. + rc = false; + } + sectionIndex++; } - - ACE_OS::fclose (in); - return 0; + return rc; } -const ACE_Configuration_Section_Key& -ACE_Configuration::root_section (void) -{ - return root_; -} ////////////////////////////////////////////////////////////////////////////// #if defined (WIN32) -static const int ACE_DEFAULT_BUFSIZE = ACE_Configuration::MAX_NAME_LEN + 1; +static const int ACE_DEFAULT_BUFSIZE = 256; ACE_Section_Key_Win32::ACE_Section_Key_Win32 (HKEY hKey) : hKey_ (hKey) @@ -666,7 +650,7 @@ ACE_Configuration_Win32Registry::set_string_value (const ACE_Configuration_Secti name, 0, REG_SZ, - (BYTE *) value.fast_rep (), + (BYTE *) value.fast_rep (), value.length () + 1) != ERROR_SUCCESS) return -2; @@ -689,7 +673,7 @@ ACE_Configuration_Win32Registry::set_integer_value (const ACE_Configuration_Sect name, 0, REG_DWORD, - (BYTE *) &value, + (BYTE *) &value, sizeof (value)) != ERROR_SUCCESS) return -2; @@ -713,7 +697,7 @@ ACE_Configuration_Win32Registry::set_binary_value (const ACE_Configuration_Secti name, 0, REG_BINARY, - (BYTE*)data, + (BYTE*)data, length) != ERROR_SUCCESS) return -2; @@ -732,36 +716,21 @@ ACE_Configuration_Win32Registry::get_string_value (const ACE_Configuration_Secti if (load_key (key, base_key)) return -1; - // Get the size of the binary data from windows - DWORD buffer_length = 0; + ACE_TCHAR buffer[ACE_DEFAULT_BUFSIZE]; + DWORD length = ACE_DEFAULT_BUFSIZE; DWORD type; if (ACE_TEXT_RegQueryValueEx (base_key, - name, - NULL, - &type, - (BYTE*)0, - &buffer_length) != ERROR_SUCCESS) + name, + NULL, + &type, + (BYTE*)buffer, + &length) != ERROR_SUCCESS) return -2; if (type != REG_SZ) return -3; - ACE_TCHAR* buffer; - ACE_NEW_RETURN (buffer, ACE_TCHAR[buffer_length], -4); - - if (ACE_TEXT_RegQueryValueEx (base_key, - name, - NULL, - &type, - (BYTE*)buffer, - &buffer_length) != ERROR_SUCCESS) - { - delete[] buffer; - return -5; - } - value = buffer; - delete[] buffer; return 0; } @@ -783,7 +752,7 @@ ACE_Configuration_Win32Registry::get_integer_value (const ACE_Configuration_Sect name, NULL, &type, - (BYTE*)&value, + (BYTE*)&value, &length) != ERROR_SUCCESS) return -2; @@ -813,7 +782,7 @@ ACE_Configuration_Win32Registry::get_binary_value (const ACE_Configuration_Secti name, NULL, &type, - (BYTE*)0, + (BYTE*)0, &buffer_length) != ERROR_SUCCESS) return -2; @@ -822,16 +791,16 @@ ACE_Configuration_Win32Registry::get_binary_value (const ACE_Configuration_Secti length = buffer_length; - ACE_NEW_RETURN (data, u_char[length], -4); + ACE_NEW_RETURN (data, unsigned char[length], -4); if (ACE_TEXT_RegQueryValueEx (base_key, name, NULL, &type, - (BYTE*)data, + (BYTE*)data, &buffer_length) != ERROR_SUCCESS) { - delete[] data; + delete data; data = 0; return -5; } @@ -839,7 +808,7 @@ ACE_Configuration_Win32Registry::get_binary_value (const ACE_Configuration_Secti return 0; } -int ACE_Configuration_Win32Registry::find_value (const ACE_Configuration_Section_Key& key, +int ACE_Configuration_Win32Registry::find_value(const ACE_Configuration_Section_Key& key, const ACE_TCHAR* name, VALUETYPE& type_out) { @@ -850,20 +819,18 @@ int ACE_Configuration_Win32Registry::find_value (const ACE_Configuration_Section if (load_key (key, base_key)) return -1; - DWORD buffer_length=0; + unsigned char buffer[ACE_DEFAULT_BUFSIZE]; + DWORD buffer_length = ACE_DEFAULT_BUFSIZE; DWORD type; - int result=ACE_TEXT_RegQueryValueEx (base_key, + if (ACE_TEXT_RegQueryValueEx (base_key, name, NULL, &type, - NULL, - &buffer_length); - if (result != ERROR_SUCCESS) - { + (BYTE*)&buffer, + &buffer_length) != ERROR_SUCCESS) return -1; - } - switch (type) + switch(type) { case REG_SZ: type_out = STRING; @@ -930,7 +897,7 @@ ACE_Configuration_Win32Registry::resolve_key (HKEY hKey, { // Detmine the begin/ending of the key name end = ACE_OS::strchr (begin, ACE_LIB_TEXT ('\\')); - size_t length = end ? (size_t) (end-begin) : ACE_OS::strlen (begin); + size_t length = end ? (size_t)(end-begin) : ACE_OS::strlen (begin); // Make sure length is not 0 if (!length) @@ -969,13 +936,17 @@ ACE_Configuration_Win32Registry::resolve_key (HKEY hKey, begin = end + 1; } -#if !defined (ghs) + return 0; -#endif // ghs } + + #endif // WIN_32 + + + /////////////////////////////////////////////////////////////// ACE_Configuration_Value_IntId::ACE_Configuration_Value_IntId (void) @@ -1139,8 +1110,8 @@ ACE_Configuration_Section_IntId::operator= (const ACE_Configuration_Section_IntI void ACE_Configuration_Section_IntId::free (ACE_Allocator* allocator) { - allocator->free ((void *) (value_hash_map_)); - allocator->free ((void *) (section_hash_map_)); + allocator->free ((void *)(value_hash_map_)); + allocator->free ((void *)(section_hash_map_)); } ACE_Configuration_Section_Key_Heap::ACE_Configuration_Section_Key_Heap (const ACE_TCHAR* path) @@ -1163,8 +1134,7 @@ ACE_Configuration_Section_Key_Heap::~ACE_Configuration_Section_Key_Heap () ACE_Configuration_Heap::ACE_Configuration_Heap (void) : allocator_ (0), index_ (0), - default_map_size_ (0), - persistent_ (0) + default_map_size_ (0) { ACE_Configuration_Section_Key_Heap *temp = 0; @@ -1175,11 +1145,8 @@ ACE_Configuration_Heap::ACE_Configuration_Heap (void) ACE_Configuration_Heap::~ACE_Configuration_Heap (void) { if (allocator_) - { allocator_->sync (); - if (!persistent_) - allocator_->remove (); - } + delete allocator_; } @@ -1193,7 +1160,6 @@ ACE_Configuration_Heap::open (int default_map_size) ACE_NEW_RETURN (this->allocator_, HEAP_ALLOCATOR (), -1); - persistent_ = 0; return create_index (); } @@ -1203,7 +1169,6 @@ ACE_Configuration_Heap::open (const ACE_TCHAR* file_name, void* base_address, int default_map_size) { - persistent_ = 1; default_map_size_ = default_map_size; // Make sure that the file name is of the legal length. @@ -1280,7 +1245,7 @@ int ACE_Configuration_Heap::create_index_helper (void *buffer) { ACE_NEW_RETURN (this->index_, - (buffer) SECTION_MAP (this->allocator_), + (buffer) SECTION_MAP (this->allocator_), -1); return 0; } @@ -1351,7 +1316,7 @@ ACE_Configuration_Heap::new_section (const ACE_TString& section, // Allocate memory for items to be stored in the table. size_t section_len = section.length () + 1; - ACE_TCHAR *ptr = (ACE_TCHAR*) this->allocator_->malloc (section_len * sizeof (ACE_TCHAR)); + ACE_TCHAR *ptr = (ACE_TCHAR*) this->allocator_->malloc (section_len * sizeof(ACE_TCHAR)); int return_value = -1; @@ -1396,7 +1361,7 @@ ACE_Configuration_Heap::new_section (const ACE_TString& section, ACE_Configuration_ExtId name (ptr); ACE_Configuration_Section_IntId entry ((VALUE_MAP*)value_hash_map , - (SUBSECTION_MAP*)section_hash_map); + (SUBSECTION_MAP*)section_hash_map); // Do a normal bind. This will fail if there's already an // entry with the same name. @@ -1414,7 +1379,7 @@ ACE_Configuration_Heap::new_section (const ACE_TString& section, // Free our dynamically allocated memory. this->allocator_->free ((void *) ptr); else - // If bind () succeed, it will automatically sync + // If bind() succeed, it will automatically sync // up the map manager entry. However, we must sync up our // name/value memory. this->allocator_->sync (ptr, section_len); @@ -1433,7 +1398,7 @@ ACE_Configuration_Heap::value_open_helper (size_t hash_table_size, void *buffer) { ACE_NEW_RETURN (buffer, - (buffer) VALUE_MAP (hash_table_size, this->allocator_), + (buffer) VALUE_MAP (hash_table_size, this->allocator_), -1); return 0; } @@ -1443,7 +1408,7 @@ ACE_Configuration_Heap::section_open_helper (size_t hash_table_size, void *buffer) { ACE_NEW_RETURN (buffer, - (buffer) SUBSECTION_MAP (hash_table_size, this->allocator_), + (buffer) SUBSECTION_MAP (hash_table_size, this->allocator_), -1); return 0; } @@ -1539,7 +1504,7 @@ ACE_Configuration_Heap::remove_section (const ACE_Configuration_Section_Key& key // Now remove subkey from parent key ACE_Configuration_ExtId SubSExtId (sub_section); SUBSECTION_ENTRY* subsection_entry; - if (( (SUBSECTION_HASH*)ParentIntId.section_hash_map_)-> + if (((SUBSECTION_HASH*)ParentIntId.section_hash_map_)-> find (SubSExtId, subsection_entry)) return -4; @@ -1555,7 +1520,6 @@ ACE_Configuration_Heap::remove_section (const ACE_Configuration_Section_Key& key // iterate over all values and free memory VALUE_HASH* value_hash_map = section_entry->int_id_.value_hash_map_; VALUE_HASH::ITERATOR value_iter = value_hash_map->begin (); - while (!value_iter.done ()) { VALUE_ENTRY* value_entry; @@ -1602,14 +1566,12 @@ ACE_Configuration_Heap::enumerate_values (const ACE_Configuration_Section_Key& k // Handle iterator resets if (index == 0) { - ACE_Hash_Map_Manager_Ex<ACE_Configuration_ExtId , - ACE_Configuration_Value_IntId, - ACE_Hash<ACE_Configuration_ExtId>, - ACE_Equal_To<ACE_Configuration_ExtId>, - ACE_Null_Mutex>* hash_map = IntId.value_hash_map_; + ACE_Hash_Map_Manager_Ex<ACE_Configuration_ExtId , ACE_Configuration_Value_IntId, ACE_Hash<ACE_Configuration_ExtId>, ACE_Equal_To<ACE_Configuration_ExtId>, ACE_Null_Mutex>* hash_map = IntId.value_hash_map_; + // @@ This zero pointer check is redundant -Ossama + // if (pKey->value_iter_) delete pKey->value_iter_; - ACE_NEW_RETURN (pKey->value_iter_, VALUE_HASH::ITERATOR (hash_map->begin ()), -3); + ACE_NEW_RETURN (pKey->value_iter_, VALUE_HASH::ITERATOR(hash_map->begin()), -3); } // Get the next entry @@ -1646,11 +1608,10 @@ ACE_Configuration_Heap::enumerate_sections (const ACE_Configuration_Section_Key& // Handle iterator resets if (index == 0) { - delete pKey->section_iter_; + if (pKey->section_iter_) + delete pKey->section_iter_; - ACE_NEW_RETURN (pKey->section_iter_, - SUBSECTION_HASH::ITERATOR (IntId.section_hash_map_->begin ()), - -3); + ACE_NEW_RETURN (pKey->section_iter_, SUBSECTION_HASH::ITERATOR (IntId.section_hash_map_->begin ()), -3); } // Get the next entry @@ -1684,30 +1645,27 @@ ACE_Configuration_Heap::set_string_value (const ACE_Configuration_Section_Key& k // Get the entry for this item (if it exists) VALUE_ENTRY* entry; - ACE_Configuration_ExtId item_name (name); - if (section_int.value_hash_map_->VALUE_HASH::find (item_name, entry) == 0) + ACE_Configuration_ExtId item_name(name); + if(section_int.value_hash_map_->VALUE_HASH::find(item_name, entry) == 0) { // found item, replace it // Free the old value - entry->int_id_.free (allocator_); + entry->int_id_.free(allocator_); // Allocate the new value in this heap - ACE_TCHAR* pers_value = - (ACE_TCHAR*) allocator_->malloc ((value.length () + 1) * sizeof (ACE_TCHAR)); - ACE_OS::strcpy (pers_value, value.fast_rep ()); - ACE_Configuration_Value_IntId new_value_int (pers_value); + ACE_TCHAR* pers_value = (ACE_TCHAR*)allocator_->malloc ((value.length () + 1) * sizeof (ACE_TCHAR)); + ACE_OS::strcpy (pers_value, value.fast_rep()); + ACE_Configuration_Value_IntId new_value_int(pers_value); entry->int_id_ = new_value_int; } else { // it doesn't exist, bind it - ACE_TCHAR* pers_name = - (ACE_TCHAR*) allocator_->malloc ((ACE_OS::strlen (name) + 1) * sizeof (ACE_TCHAR)); + ACE_TCHAR* pers_name = (ACE_TCHAR*)allocator_->malloc ((ACE_OS::strlen (name) + 1) * sizeof (ACE_TCHAR)); ACE_OS::strcpy (pers_name, name); - ACE_TCHAR* pers_value = - (ACE_TCHAR*) allocator_->malloc ((value.length () + 1) * sizeof (ACE_TCHAR)); + ACE_TCHAR* pers_value = (ACE_TCHAR*)allocator_->malloc ((value.length () + 1) * sizeof (ACE_TCHAR)); ACE_OS::strcpy (pers_value, value.fast_rep ()); - ACE_Configuration_ExtId item_name (pers_name); - ACE_Configuration_Value_IntId item_value (pers_value); + ACE_Configuration_ExtId item_name(pers_name); + ACE_Configuration_Value_IntId item_value(pers_value); if (section_int.value_hash_map_->bind (item_name, item_value, allocator_)) { allocator_->free (pers_value); @@ -1734,28 +1692,27 @@ ACE_Configuration_Heap::set_integer_value (const ACE_Configuration_Section_Key& return -1; // Find this section - ACE_Configuration_ExtId section_ext (section.fast_rep ()); + ACE_Configuration_ExtId section_ext(section.fast_rep ()); ACE_Configuration_Section_IntId section_int; if (index_->find (section_ext, section_int, allocator_)) return -2; // section does not exist // Get the entry for this item (if it exists) VALUE_ENTRY* entry; - ACE_Configuration_ExtId item_name (name); - if (section_int.value_hash_map_->VALUE_HASH::find (item_name, entry) == 0) + ACE_Configuration_ExtId item_name(name); + if(section_int.value_hash_map_->VALUE_HASH::find(item_name, entry) == 0) { // found item, replace it - ACE_Configuration_Value_IntId new_value_int (value); + ACE_Configuration_Value_IntId new_value_int(value); entry->int_id_ = new_value_int; } else { // it doesn't exist, bind it - ACE_TCHAR* pers_name = - (ACE_TCHAR*) allocator_->malloc ((ACE_OS::strlen (name) + 1) * sizeof (ACE_TCHAR)); + ACE_TCHAR* pers_name = (ACE_TCHAR*)allocator_->malloc ((ACE_OS::strlen (name) + 1) * sizeof (ACE_TCHAR)); ACE_OS::strcpy (pers_name, name); - ACE_Configuration_ExtId item_name (pers_name); - ACE_Configuration_Value_IntId item_value (value); + ACE_Configuration_ExtId item_name(pers_name); + ACE_Configuration_Value_IntId item_value(value); if (section_int.value_hash_map_->bind (item_name, item_value, allocator_)) { allocator_->free (pers_name); @@ -1789,28 +1746,27 @@ ACE_Configuration_Heap::set_binary_value (const ACE_Configuration_Section_Key& k // Get the entry for this item (if it exists) VALUE_ENTRY* entry; - ACE_Configuration_ExtId item_name (name); - if (section_int.value_hash_map_->VALUE_HASH::find (item_name, entry) == 0) + ACE_Configuration_ExtId item_name(name); + if(section_int.value_hash_map_->VALUE_HASH::find(item_name, entry) == 0) { // found item, replace it // Free the old value - entry->int_id_.free (allocator_); + entry->int_id_.free(allocator_); // Allocate the new value in this heap - ACE_TCHAR* pers_value = (ACE_TCHAR*)allocator_->malloc (length); + ACE_TCHAR* pers_value = (ACE_TCHAR*)allocator_->malloc (length); ACE_OS::memcpy (pers_value, data, length); - ACE_Configuration_Value_IntId new_value_int (pers_value, length); + ACE_Configuration_Value_IntId new_value_int(pers_value, length); entry->int_id_ = new_value_int; } else { // it doesn't exist, bind it - ACE_TCHAR* pers_name = - (ACE_TCHAR*) allocator_->malloc ((ACE_OS::strlen (name) + 1) * sizeof (ACE_TCHAR)); + ACE_TCHAR* pers_name = (ACE_TCHAR*)allocator_->malloc ((ACE_OS::strlen (name) + 1) * sizeof (ACE_TCHAR)); ACE_OS::strcpy (pers_name, name); - ACE_TCHAR* pers_value = (ACE_TCHAR*)allocator_->malloc (length); + ACE_TCHAR* pers_value = (ACE_TCHAR*)allocator_->malloc (length); ACE_OS::memcpy (pers_value, data, length); - ACE_Configuration_ExtId item_name (pers_name); - ACE_Configuration_Value_IntId item_value (pers_value, length); + ACE_Configuration_ExtId item_name(pers_name); + ACE_Configuration_Value_IntId item_value(pers_value, length); if (section_int.value_hash_map_->bind (item_name, item_value, allocator_)) { allocator_->free (pers_value); @@ -1833,10 +1789,9 @@ ACE_Configuration_Heap::set_binary_value (const ACE_Configuration_Section_Key& k if (IntId.value_hash_map_->find (VExtIdFind, VIntIdFind, allocator_)) { // it doesn't exist, bind it - ACE_TCHAR* pers_name = - (ACE_TCHAR*) allocator_->malloc ((ACE_OS::strlen (name) + 1) * sizeof (ACE_TCHAR)); + ACE_TCHAR* pers_name = (ACE_TCHAR*)allocator_->malloc ((ACE_OS::strlen (name) + 1) * sizeof (ACE_TCHAR)); ACE_OS::strcpy (pers_name, name); - ACE_TCHAR* pers_value = (ACE_TCHAR*)allocator_->malloc (length); + ACE_TCHAR* pers_value = (ACE_TCHAR*)allocator_->malloc (length); ACE_OS::memcpy (pers_value, data, length); ACE_Configuration_ExtId VExtId (pers_name); ACE_Configuration_Value_IntId VIntId (pers_value, length); @@ -1853,7 +1808,7 @@ ACE_Configuration_Heap::set_binary_value (const ACE_Configuration_Section_Key& k // it does exist, free the old value memory VIntIdFind.free (allocator_); // Assign a new value - ACE_TCHAR* pers_value = (ACE_TCHAR*)allocator_->malloc (length); + ACE_TCHAR* pers_value = (ACE_TCHAR*)allocator_->malloc (length); ACE_OS::memcpy (pers_value, data, length); VIntIdFind = ACE_Configuration_Value_IntId (pers_value, length); } @@ -1926,7 +1881,7 @@ ACE_Configuration_Heap::get_integer_value (const ACE_Configuration_Section_Key& return -4; // Everythings ok, return the data - value = (u_int) ((long)VIntId.data_); + value = (u_int)((long)VIntId.data_); return 0; } @@ -1968,7 +1923,7 @@ ACE_Configuration_Heap::get_binary_value (const ACE_Configuration_Section_Key& k } int -ACE_Configuration_Heap::find_value (const ACE_Configuration_Section_Key& key, +ACE_Configuration_Heap::find_value(const ACE_Configuration_Section_Key& key, const ACE_TCHAR* name, VALUETYPE& type_out) { @@ -1989,7 +1944,7 @@ ACE_Configuration_Heap::find_value (const ACE_Configuration_Section_Key& key, // Find it ACE_Configuration_ExtId ValueExtId (name); VALUE_ENTRY* value_entry; - if (( (VALUE_HASH*)IntId.value_hash_map_)->find (ValueExtId, value_entry)) + if (((VALUE_HASH*)IntId.value_hash_map_)->find (ValueExtId, value_entry)) return -1; // value does not exist type_out = value_entry->int_id_.type_; @@ -2018,7 +1973,7 @@ ACE_Configuration_Heap::remove_value (const ACE_Configuration_Section_Key& key, // Find it ACE_Configuration_ExtId ValueExtId (name); VALUE_ENTRY* value_entry; - if (( (VALUE_HASH*)IntId.value_hash_map_)->find (ValueExtId, value_entry)) + if (((VALUE_HASH*)IntId.value_hash_map_)->find (ValueExtId, value_entry)) return -4; // free it @@ -2031,103 +1986,3 @@ ACE_Configuration_Heap::remove_value (const ACE_Configuration_Section_Key& key, return 0; } - -int -ACE_Configuration::import_config_as_strings (const ACE_TCHAR* filename) -{ - FILE* in = ACE_OS::fopen (filename, ACE_LIB_TEXT ("r")); - if (!in) - return -1; - - // @@ Make this a dynamic size! - ACE_TCHAR buffer[4096]; - ACE_Configuration_Section_Key section; - while (ACE_OS::fgets (buffer, sizeof buffer, in)) - { - // Check for a comment and blank line - if (buffer[0] == ACE_LIB_TEXT (';') - || buffer[0] == ACE_LIB_TEXT ('#') - || buffer[0] == ACE_LIB_TEXT ('\r') - || buffer[0] == ACE_LIB_TEXT ('\n')) - continue; - - if (buffer[0] == ACE_LIB_TEXT ('[')) - { - // We have a new section here, strip out the section name - ACE_TCHAR* end = ACE_OS::strrchr (buffer, ACE_LIB_TEXT (']')); - if (!end) - { - ACE_OS::fclose (in); - return -3; - } - *end = 0; - - if (expand_path (root_, buffer + 1, section, 1)) - { - ACE_OS::fclose (in); - return -3; - } - - continue; - } - - // we have a line - const ACE_TCHAR *name = this->skip_whitespace (buffer); - if (name) - { - ACE_TCHAR *end = (ACE_TCHAR *) ACE_OS::strpbrk (name, ACE_LIB_TEXT ("= \t\n\r")); - - // locate equal sign after name and retrieve value - const ACE_TCHAR *value = ACE_OS::strrchr (name, ACE_LIB_TEXT ('=')); - if (value) - { - value++; // jump over equal sign - value = this->skip_whitespace (value); - ACE_TCHAR *value_end; - if (value[0] != ACE_LIB_TEXT ('"')) - value_end = (ACE_TCHAR *) ACE_OS::strpbrk (value, ACE_LIB_TEXT (" \t\n\r")); - else - { - // double quote delimited allows spaces and tabs in string - value++; - value_end = (ACE_TCHAR *) ACE_OS::strpbrk (value, ACE_LIB_TEXT ("\"\n\r")); - } - if (value_end) - *value_end = '\0'; // terminate value - } - else - value = ACE_LIB_TEXT (""); - - if (end) - *end = '\0'; // terminate name now - - if (set_string_value (section, name, value)) - { - ACE_OS::fclose (in); - return -4; - } - } - } - - if (ferror (in)) - { - ACE_OS::fclose (in); - return -1; - } - - ACE_OS::fclose (in); - return 0; -} - -const ACE_TCHAR * -ACE_Configuration::skip_whitespace (const ACE_TCHAR *src) -{ - const ACE_TCHAR *cp; - - for (cp = src; - (*cp != '\0') && ((*cp == ' ') || (*cp == '\t')); - cp++) - continue; - - return cp; -} diff --git a/ace/Configuration.h b/ace/Configuration.h index ce57eb228c3..f08dc87b96a 100644 --- a/ace/Configuration.h +++ b/ace/Configuration.h @@ -6,7 +6,7 @@ * * $Id$ * - * @author Chris Hafey <chafey@stentor.com> + * @author Chris Hafey <chris@stentorsoft.com> * * The ACE configuration API provides a portable abstraction for * program configuration. The API supports a tree based hierarchy @@ -14,15 +14,6 @@ * or values. Values may contain string, unsigned integer and * binary data. * - * @todo - * - Redo the import/export mechanism to support different file formats - * - Add locking for thread safety. - * - Need to investigate what happens if memory mapped file gets mapped to - * a location different than it was created with. - * - Add dynamic buffer when importing. currently it will not allow - * importing of values greater than a fixed ammount (4096 bytes) - * - Replace unsigned int with a type that is fixed accross platforms. - * */ //============================================================================= @@ -59,6 +50,11 @@ * Implementations subclass this base class to represent a * section key. * + * @todo + * - Add locking for thread safety. + * - Need to investigate what happens if memory mapped file gets mapped to + * a location different than it was created with. + * - Replace unsigned int with a type that is fixed accross platforms. * */ class ACE_Export ACE_Section_Key_Internal @@ -80,15 +76,15 @@ protected: u_int ref_count_; }; - /** - * @class ACE_Configuration_Section_Key - * - * @brief Referenced counted wrapper for <ACE_Section_Key_Internal>. - * - * Reference counted wrapper class for the abstract internal - * section key. A user gets one of these to represent a section - * in the configuration database. - */ +/** + * @class ACE_Configuration_Section_Key + * + * @brief Referenced counted wrapper for <ACE_Section_Key_Internal>. + * + * Reference counted wrapper class for the abstract internal + * section key. A user gets one of these to represent a section + * in the configuration database. + */ class ACE_Export ACE_Configuration_Section_Key { friend class ACE_Configuration; @@ -133,11 +129,6 @@ public: INVALID }; - enum { - /// Max size of name. - MAX_NAME_LEN = 255 - }; - /// destructor virtual ~ACE_Configuration (void); @@ -233,9 +224,10 @@ public: * data type in <type>. Returns 0 on success (entry is found), * -1 on error */ - virtual int find_value (const ACE_Configuration_Section_Key& key, - const ACE_TCHAR* name, - VALUETYPE& type) = 0; + virtual int find_value(const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + VALUETYPE& type) = 0; + /// Removes the the value <name> from <key>. returns non zero on /// error. @@ -253,76 +245,41 @@ public: ACE_Configuration_Section_Key& key_out, int create = 1); + /** + * Determine if the contents of this object is the same as the + * contents of the object on the right hand side. + * Returns 1 (True) if they are equal and 0 (False) if they are not equal + */ + int operator==(const ACE_Configuration& rhs) const; - /// Exports the configuration database to filename. If <filename> is - /// alredy present, it is overwritten. * See note below - virtual int export_config (const ACE_TCHAR* filename); - - /// Imports the configuration database from filename. Any existing - /// data is not removed. * See note below - virtual int import_config (const ACE_TCHAR* filename); - - /// Imports the configuration database from filename as strings. - /// Allows non-typed values. (no #, dword: hex:, etc. prefixes) and - /// skips whitespace (tabs and spaces) as in standard .ini and .conf - /// files. Values (to right of equal sign) can be double quote - /// delimited to embed tabs and spaces in the string. - /// Caller must convert string to type. - /// A corresponding export_config is not supported. - /// - /// This method allows for lines in the .ini or .conf file like this: - /// - /// TimeToLive = 100 - /// Delay = FALSE - /// Flags = FF34 - /// Heading = "ACE - Adaptive Communication Environment" - /// - /// (note leading whitespace (tabs) in examples below) - /// - /// SeekIndex = 14 - /// TraceLevel = 6 # Can comment lines like this - /// Justification = left_justified - /// - /// The caller can then retrieve the string with the regular - /// <get_string_value> function and convert the string to the - /// desired data type. - - virtual int import_config_as_strings (const ACE_TCHAR *filename); - - // Note - The above import/export routines have the following bugs/limitations - // 1) Strings with embedded newlines cause the import to fail - // 2) Strings with embedded quotes " cause the import to fail - // 3) Importing/exporting for values in the root section does not work - // If you are interested in working on this, please let me know and we can - // discuss the details. chafey@stentor.com + /** + * Determine if the contents of this object are different from the + * contents of the object on the right hand side. + * Returns 0 (False) if they are equal and 1 (True) if they are not equal + */ + int operator!=(const ACE_Configuration& rhs) const {return !(*this == rhs);} protected: /// Default ctor ACE_Configuration (void); - /// Skips whitespace - const ACE_TCHAR *skip_whitespace (const ACE_TCHAR *src); - /// resolves the internal key from a section key ACE_Section_Key_Internal* get_internal_key (const ACE_Configuration_Section_Key& key); /** - * tests to see if <name> is valid. <name> must be < MAX_NAME_LEN characters + * tests to see if <name> is valid. <name> must be < 255 characters * and not contain the path separator '\', brackets [] or = (maybe * just restrict to alphanumeric?) returns non zero if name is not * valid */ int validate_name (const ACE_TCHAR* name); - /// Used when exporting a configuration to a file - int export_section (const ACE_Configuration_Section_Key& section, - const ACE_TString& path, - FILE* out); - // Not used ACE_Configuration (const ACE_Configuration& rhs); ACE_Configuration& operator= (const ACE_Configuration& rhs); + + ACE_Configuration_Section_Key root_; }; @@ -439,6 +396,9 @@ public: const ACE_TCHAR* path, int create = 1); + virtual int operator==(const ACE_Configuration_Win32Registry& rhs) const{return true;} + virtual int operator!=(const ACE_Configuration_Win32Registry& rhs) const{return true;} + protected: /// Gets the HKEY for a configuration section @@ -766,7 +726,6 @@ private: ACE_Allocator *allocator_; SECTION_MAP *index_; int default_map_size_; - int persistent_; }; #include "ace/post.h" diff --git a/ace/Configuration_Import_Export.cpp b/ace/Configuration_Import_Export.cpp new file mode 100644 index 00000000000..dd0329e3108 --- /dev/null +++ b/ace/Configuration_Import_Export.cpp @@ -0,0 +1,552 @@ +// $Id$ + +#include "ConfigImpExpFiles.h" + +ACE_Config_ImpExp_Base::ACE_Config_ImpExp_Base (ACE_Configuration& config) + : config_ (config) +{ +} + +ACE_Config_ImpExp_Base::~ACE_Config_ImpExp_Base () +{ +} + +ACE_Registry_ImpExp::ACE_Registry_ImpExp (ACE_Configuration& config) + : ACE_Config_ImpExp_Base (config) +{ +} + +ACE_Registry_ImpExp::~ACE_Registry_ImpExp () +{ +} + +// Imports the configuration database from filename. +// No existing data is removed. +// Since the open method relies on this method, this method +// acts as open if an open has not already occurred. + +int +ACE_Registry_ImpExp::import_config (const ACE_TCHAR* filename) +{ + FILE* in = ACE_OS::fopen (filename, ACE_LIB_TEXT ("r")); + if (!in) + return -1; + + // @@ XXX - change this to a dynamic buffer + ACE_TCHAR buffer[4096]; + ACE_Configuration_Section_Key section; + while (ACE_OS::fgets (buffer, 4096, in)) + { + // Check for a comment + if (buffer[0] == ACE_LIB_TEXT (';') || buffer[0] == ACE_LIB_TEXT ('#')) + continue; + + if (buffer[0] == ACE_LIB_TEXT ('[')) + { + // We have a new section here, strip out the section name + ACE_TCHAR* end = ACE_OS::strrchr (buffer, ACE_LIB_TEXT (']')); + if (!end) + { + ACE_OS::fclose (in); + return -3; + } + *end = 0; + + if (config_.expand_path (config_.root_section (), buffer + 1, section, 1)) + { + ACE_OS::fclose (in); + return -3; + } + continue; + } + + if (buffer[0] == ACE_LIB_TEXT ('"')) + { + // we have a value + ACE_TCHAR* end = ACE_OS::strchr (buffer+1, '"'); + if (!end) // no closing quote, not a value so just skip it + continue; + + // null terminate the name + *end = 0; + ACE_TCHAR* name = buffer + 1; + end+=2; + // determine the type + if (*end == '\"') + { + // string type + // truncate trailing " + ++end; + ACE_TCHAR* trailing = ACE_OS::strrchr (end, '"'); + if (trailing) + *trailing = 0; + if (config_.set_string_value (section, name, end)) + { + ACE_OS::fclose (in); + return -4; + } + } + else if (ACE_OS::strncmp (end, ACE_LIB_TEXT ("dword:"), 6) == 0) + { + // number type + ACE_TCHAR* endptr = 0; + u_int value = ACE_OS::strtoul (end + 6, &endptr, 16); + if (config_.set_integer_value (section, name, value)) + { + ACE_OS::fclose (in); + return -4; + } + } + else if (ACE_OS::strncmp (end, ACE_LIB_TEXT ("hex:"), 4) == 0) + { + // binary type + u_int string_length = ACE_OS::strlen (end + 4); + // divide by 3 to get the actual buffer length + u_int length = string_length / 3; + u_int remaining = length; + u_char* data = new u_char[length]; + u_char* out = data; + ACE_TCHAR* inb = end + 4; + ACE_TCHAR* endptr = 0; + while (remaining) + { + u_char charin = (u_char) ACE_OS::strtoul (inb, &endptr, 16); + *out = charin; + ++out; + --remaining; + inb += 3; + } + if (config_.set_binary_value (section, name, data, length)) + { + ACE_OS::fclose (in); + return -4; + } + } + else + { + // invalid type, ignore + continue; + } + } + } + + if (ferror (in)) + { + ACE_OS::fclose (in); + return -1; + } + + ACE_OS::fclose (in); + return 0; +} + +// This method exports the entire configuration database to <filename>. If +// <filename> is NULL (the default), data is persisted to the <filename> +// provided to 'open'. If the internal filename is empty this method +// returns -1. Once the file is opened this method calls 'export_section' +// passing the root section. + +int +ACE_Registry_ImpExp::export_config (const ACE_TCHAR* filename) +{ + int result = -1; + + FILE* out = ACE_OS::fopen (filename, ACE_LIB_TEXT ("w")); + if (out) + { + result = this->export_section (config_.root_section (), + ACE_LIB_TEXT (""), + out); + ACE_OS::fclose (out); + } + return result; +} + +// Method provided by derived classes in order to write one section +// to the file specified. Called by export_config when exporting +// the entire configuration object. + +int +ACE_Registry_ImpExp::export_section (const ACE_Configuration_Section_Key& section, + const ACE_TString& path, + FILE* out) +{ + // don't export the root + if (path.length ()) + { + // Write out the section header + ACE_TString header = ACE_LIB_TEXT ("["); + header += path; + header += ACE_LIB_TEXT ("]"); + header += ACE_LIB_TEXT (" \n"); + if (ACE_OS::fputs (header.fast_rep (), out) < 0) + return -1; + // Write out each value + int index = 0; + ACE_TString name; + ACE_Configuration::VALUETYPE type; + ACE_TString line; + ACE_TCHAR int_value[32]; + ACE_TCHAR bin_value[3]; + void* binary_data; + u_int binary_length; + ACE_TString string_value; + while (!config_.enumerate_values (section, index, name, type)) + { + line = ACE_LIB_TEXT ("\"") + name + ACE_LIB_TEXT ("\"="); + switch (type) + { + case ACE_Configuration::INTEGER: + { + u_int value; + if (config_.get_integer_value (section, name.fast_rep (), value)) + return -2; + ACE_OS::sprintf (int_value, ACE_LIB_TEXT ("%08x"), value); + line += ACE_LIB_TEXT ("dword:"); + line += int_value; + break; + } + case ACE_Configuration::STRING: + { + if (config_.get_string_value (section, + name.fast_rep (), + string_value)) + return -2; + line += ACE_LIB_TEXT ("\""); + line += string_value + ACE_LIB_TEXT ("\""); + break; + } +#ifdef _WIN32 + case ACE_Configuration::INVALID: + break; // JDO added break. Otherwise INVALID is processed + // like BINARY. If that's correct, please remove the + // break and these comments +#endif + case ACE_Configuration::BINARY: + { + // not supported yet - maybe use BASE64 codeing? + if (config_.get_binary_value (section, + name.fast_rep (), + binary_data, + binary_length)) + return -2; + line += ACE_LIB_TEXT ("hex:"); + unsigned char* ptr = (unsigned char*)binary_data; + while (binary_length) + { + if (ptr != binary_data) + { + line += ACE_LIB_TEXT (","); + } + ACE_OS::sprintf (bin_value, ACE_LIB_TEXT ("%02x"), *ptr); + line += bin_value; + --binary_length; + ++ptr; + } + delete (char *)binary_data; + break; + } + default: + return -3; + } + line += ACE_LIB_TEXT ("\n"); + if (ACE_OS::fputs (line.fast_rep (), out) < 0) + return -4; + index++; + } + } + // Export all sub sections + int index = 0; + ACE_TString name; + ACE_Configuration_Section_Key sub_key; + ACE_TString sub_section; + while (!config_.enumerate_sections (section, index, name)) + { + ACE_TString sub_section (path); + if (path.length ()) + sub_section += ACE_LIB_TEXT ("\\"); + sub_section += name; + if (config_.open_section (section, name.fast_rep (), 0, sub_key)) + return -5; + if (export_section (sub_key, sub_section.fast_rep (), out)) + return -6; + index++; + } + return 0; +} + +ACE_Ini_ImpExp::ACE_Ini_ImpExp (ACE_Configuration& config) + : ACE_Config_ImpExp_Base (config) +{ +} + +ACE_Ini_ImpExp::~ACE_Ini_ImpExp (void) +{ +} + +// Method to read file and populate object. +int +ACE_Ini_ImpExp::import_config (const ACE_TCHAR* fileName) +{ + FILE* in = ACE_OS::fopen (fileName, ACE_LIB_TEXT ("r")); + if (!in) + return -1; + + // @@ Make this a dynamic size! + ACE_TCHAR buffer[4096]; + ACE_Configuration_Section_Key section; + while (ACE_OS::fgets (buffer, sizeof buffer, in)) + { + // Check for a comment and blank line + if (buffer[0] == ACE_LIB_TEXT (';') || + buffer[0] == ACE_LIB_TEXT ('#') || + buffer[0] == ACE_LIB_TEXT ('\r') || + buffer[0] == ACE_LIB_TEXT ('\n')) + continue; + + if (buffer[0] == ACE_LIB_TEXT ('[')) + { + // We have a new section here, strip out the section name + ACE_TCHAR* end = ACE_OS::strrchr (buffer, ACE_LIB_TEXT (']')); + if (!end) + { + ACE_OS::fclose (in); + return -3; + } + *end = 0; + + if (config_.expand_path (config_.root_section (), buffer + 1, section, 1)) + { + ACE_OS::fclose (in); + return -3; + } + + continue; + } + + // we have a line + const ACE_TCHAR *name = this->skip_whitespace (buffer); + if (name) + { + ACE_TCHAR *end = (ACE_TCHAR *) ACE_OS::strpbrk (name, ACE_LIB_TEXT ("= \t\n\r")); + + // locate equal sign after name and retrieve value + const ACE_TCHAR *value = ACE_OS::strrchr (name, ACE_LIB_TEXT ('=')); + if (value) + { + value++; // jump over equal sign + value = this->skip_whitespace (value); + ACE_TCHAR *value_end; + if (value[0] != ACE_LIB_TEXT ('"')) + value_end = (ACE_TCHAR *) ACE_OS::strpbrk (value, ACE_LIB_TEXT (" \t\n\r")); + else + { + // double quote delimited allows spaces and tabs in string + value++; + value_end = (ACE_TCHAR *) ACE_OS::strpbrk (value, ACE_LIB_TEXT ("\"\n\r")); + } + if (value_end) + *value_end = '\0'; // terminate value + } + else + value = ACE_LIB_TEXT (""); + + if (end) + *end = '\0'; // terminate name now + + if (config_.set_string_value (section, name, value)) + { + ACE_OS::fclose (in); + return -4; + } + } + } + + if (ferror (in)) + { + ACE_OS::fclose (in); + return -1; + } + + ACE_OS::fclose (in); + return 0; +} + +// This method exports the entire configuration database to +// <filename>. If <filename> is NULL (the default), data is persisted +// to the <filename> provided to 'open'. If the internal filename is +// empty this method returns -1. Once the file is opened this method +// calls 'export_section' passing the root section. + +int +ACE_Ini_ImpExp::export_config (const ACE_TCHAR* filename) +{ + int result = -1; + + FILE* out = ACE_OS::fopen (filename, ACE_LIB_TEXT ("w")); + if (out) + { + result = this->export_section (config_.root_section (), ACE_LIB_TEXT (""), out); + ACE_OS::fclose (out); + } + return result; +} + +// Method provided by derived classes in order to write one section to the +// file specified. Called by export_config when exporting the entire +// configuration objet + +int +ACE_Ini_ImpExp::export_section (const ACE_Configuration_Section_Key& section, + const ACE_TString& path, + FILE* out) +{ + // don't export the root + if (path.length ()) + { + // Write out the section header + ACE_TString header = ACE_LIB_TEXT ("["); + header += path; + header += ACE_LIB_TEXT ("]"); + header += ACE_LIB_TEXT (" \n"); + if (ACE_OS::fputs (header.fast_rep (), out) < 0) + return -1; + // Write out each value + int index = 0; + ACE_TString name; + ACE_Configuration::VALUETYPE type; + ACE_TString line; + ACE_TCHAR int_value[32]; + ACE_TCHAR bin_value[3]; + void* binary_data; + u_int binary_length; + ACE_TString string_value; + while (!config_.enumerate_values (section, index, name, type)) + { + line = name + ACE_LIB_TEXT ("="); + switch (type) + { + case ACE_Configuration::INTEGER: + { + u_int value; + if (config_.get_integer_value (section, name.fast_rep (), value)) + return -2; + ACE_OS::sprintf (int_value, ACE_LIB_TEXT ("%08x"), value); + line += int_value; + break; + } + case ACE_Configuration::STRING: + { + if (config_.get_string_value (section, + name.fast_rep (), + string_value)) + return -2; + if (string_has_white_space (string_value.c_str ())) + { + line += ACE_LIB_TEXT ("\""); + line += string_value + ACE_LIB_TEXT ("\""); + } + else + { + line += string_value; + } + break; + } +#ifdef _WIN32 + case ACE_Configuration::INVALID: + break; // JDO added break. Otherwise INVALID is processed + // like BINARY. If that's correct, please remove the + // break and these comments +#endif + case ACE_Configuration::BINARY: + { + // not supported yet - maybe use BASE64 codeing? + if (config_.get_binary_value (section, + name.fast_rep (), + binary_data, + binary_length)) + return -2; + line += ACE_LIB_TEXT ("\""); + unsigned char* ptr = (unsigned char*)binary_data; + while (binary_length) + { + if (ptr != binary_data) + { + line += ACE_LIB_TEXT (","); + } + ACE_OS::sprintf (bin_value, ACE_LIB_TEXT ("%02x"), *ptr); + line += bin_value; + --binary_length; + ++ptr; + } + line += ACE_LIB_TEXT ("\""); + delete (char *)binary_data; + break; + } + default: + return -3; + + }// end switch on type + + line += ACE_LIB_TEXT ("\n"); + if (ACE_OS::fputs (line.fast_rep (), out) < 0) + return -4; + index++; + }// end while enumerating values + } + // Export all sub sections + int index = 0; + ACE_TString name; + ACE_Configuration_Section_Key sub_key; + ACE_TString sub_section; + while (!config_.enumerate_sections (section, index, name)) + { + ACE_TString sub_section (path); + if (path.length ()) + sub_section += ACE_LIB_TEXT ("\\"); + sub_section += name; + if (config_.open_section (section, name.fast_rep (), 0, sub_key)) + return -5; + if (export_section (sub_key, sub_section.fast_rep (), out)) + return -6; + index++; + } + return 0; + +} + +// Method to skip whitespaces in a string. Whitespace is defined as: +// spaces (' ') and tabs ('\t'). Returns a pointer to the first +// non-whitespace character in the buffer provided. It does return +// null ('\0') if it is reached + +const ACE_TCHAR * +ACE_Ini_ImpExp::skip_whitespace (const ACE_TCHAR *src) +{ + const ACE_TCHAR *cp; + + for (cp = src; + (*cp != '\0') && ((*cp == ' ') || (*cp == '\t')); + cp++) + continue; + + return cp; +} + +// Looks in provided string for whitespace. Whitespace is defined as +// spaces (' ') and tabs ('\t'). Returns true if found and false if +// not found + +int +ACE_Ini_ImpExp::string_has_white_space (const ACE_TCHAR *string_value) +{ + bool rc = false; + while ((!rc) && (*string_value != '\0')) + { + if ((*string_value == ' ') || (*string_value == '\t')) + rc = true; + + string_value++; + } + return rc; +} diff --git a/ace/Configuration_Import_Export.h b/ace/Configuration_Import_Export.h new file mode 100644 index 00000000000..460bb2bc30c --- /dev/null +++ b/ace/Configuration_Import_Export.h @@ -0,0 +1,225 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file: Configuration_Import_Export.h + * + * $Id$ + * + * @author Jerry D. Odenwelder Jr. <jerry.o@mindspring.com> + * Chris Hafey <chris@stentorsoft.com> + * + * Classes defined in this file provide the ability to import and export + * ACE Configuration objects to/from disk files. The base class + * ACE_Config_ImpExp_Base provides the common functionality and the derived + * classes implement the import/export functionality for the specific format. + * + * @todo + * - Add locking for thread safety. + * - Provide ability to read file in one format and write in another. + * - See todo's in each class + */ +//============================================================================= + +#ifndef ACE_CONFIGURATION_IMPORT_EXPORT_H +#define ACE_CONFIGURATION_IMPORT_EXPORT_H +#include "ace/pre.h" + +#include "ace/Configuration.h" +#include "ace/SString.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +/** + * @class ACE_Config_ImpExp_Base + * + * @brief Base class for file import/export configuration. + * + * This class provides base functionality for configuration objects + * that are persisted in files. It takes an ACE_Configuration + * object that it populates with the data read. + * + */ +class ACE_Export ACE_Config_ImpExp_Base +{ +public: + /// ctor taking the ACE_Configuration to import/export to + ACE_Config_ImpExp_Base(ACE_Configuration& config); + + /** + * Destructor + */ + virtual ~ACE_Config_ImpExp_Base(); + + /** + * Imports the configuration database from filename. + * No existing data is removed. + * Since the open method relies on this method, this method + * acts as open if an open has not already occurred. + */ + virtual int import_config(const ACE_TCHAR* filename) = 0; + + /** + * This method exports the entire configuration database to <filename>. + * If <filename> is NULL (the default), data is persisted to the + * <filename> provided to 'open'. If the internal filename is empty + * this method returns -1. Once the file is opened this method calls + * 'export_section' passing the root section. + */ + virtual int export_config (const ACE_TCHAR* filename) = 0; + +protected: + ACE_Configuration& config_; + +private: + ACE_Config_ImpExp_Base (const ACE_Config_ImpExp_Base&); + ACE_Config_ImpExp_Base& operator= (const ACE_Config_ImpExp_Base&); +}; + +/** + * @class ACE_Registry_ImpExp + * + * @brief Configuration object that imports/exports data to a file formatted + * using the Win32 Registry file export format. This format looks like + * [Section] + * "key"="String Data" + * "key"=dword: numeric data + * "key"=hex: binary data + * + * @todo + * - Add dynamic buffer when importing. currently it will not allow + * importing of values greater than a fixed ammount (4096 bytes) + * + */ +class ACE_Export ACE_Registry_ImpExp : public ACE_Config_ImpExp_Base +{ +public: + /// Construction + ACE_Registry_ImpExp(ACE_Configuration&); + + /// Destruction. + virtual ~ACE_Registry_ImpExp(void); + + /** + * Imports the configuration database from filename. + * No existing data is removed. + * Since the open method relies on this method, this method + * acts as open if an open has not already occurred. + */ + virtual int import_config(const ACE_TCHAR* filename); + + /** + * This method exports the entire configuration database to <filename>. + * If <filename> is NULL (the default), data is persisted to the + * <filename> provided to 'open'. If the internal filename is empty + * this method returns -1. Once the file is opened this method calls + * 'export_section' passing the root section. + */ + virtual int export_config (const ACE_TCHAR* filename); + +private: + int export_section (const ACE_Configuration_Section_Key& section, + const ACE_TString& path, + FILE* out); + + ACE_Registry_ImpExp( const ACE_Registry_ImpExp&); + ACE_Registry_ImpExp& operator=( const ACE_Registry_ImpExp&); +}; + +/** + * @class ACE_Ini_ImpExp + * + * @brief Imports the configuration database from filename as strings. + * Allows non-typed values. (no #, dword: hex:, etc. prefixes) and + * skips whitespace (tabs and spaces) as in standard .ini and .conf + * files. Values (to right of equal sign) can be double quote + * delimited to embed tabs and spaces in the string. + * Caller must convert string to type. + * + * This method allows for lines in the .ini or .conf file like this: + * + * TimeToLive = 100 + * Delay = FALSE + * Flags = FF34 + * Heading = "ACE - Adaptive Communication Environment" + * + * (note leading whitespace (tabs) in examples below) + * + * SeekIndex = 14 + * TraceLevel = 6 # Can comment lines like this + * Justification = left_justified + * + * The caller can then retrieve the string with the regular + * <get_string_value> function and convert the string to the + * desired data type. + * + * @todo + * - Strings with embedded newlines cause the import to fail + * - Strings with embedded quotes " cause the import to fail + * - Importing/exporting for values in the root section does not work + * - Add dynamic buffer when importing. currently it will not allow + * importing of values greater than a fixed ammount (4096 bytes) +*/ +class ACE_Export ACE_Ini_ImpExp : public ACE_Config_ImpExp_Base +{ +public: + /** + * Construction + */ + ACE_Ini_ImpExp(ACE_Configuration&); + + /** + * Destructor + */ + virtual ~ACE_Ini_ImpExp(void); + + /** + * Imports the configuration database from filename. + * No existing data is removed. + * Since the open method relies on this method, this method + * acts as open if an open has not already occurred. + */ + virtual int import_config(const ACE_TCHAR* filename); + + /** + * This method exports the entire configuration database to <filename>. + * If <filename> is NULL (the default), data is persisted to the + * <filename> provided to 'open'. If the internal filename is empty + * this method returns -1. Once the file is opened this method calls + * 'export_section' passing the root section. + */ + virtual int export_config (const ACE_TCHAR* filename); + +private: + /** + * Method provided by derived classes in order to write one section + * to the file specified. Called by export_config when exporting + * the entire configuration object. + */ + int export_section (const ACE_Configuration_Section_Key& section, + const ACE_TString& path, + FILE* out); + + /** + * Method to skip whitespaces in a string. Whitespace is defined as: + * spaces(' ') and tabs('\t'). + * Returns a pointer to the first non-whitespace character in the + * buffer provided. It does return null ('\0') if it is reached + */ + const ACE_TCHAR *skip_whitespace (const ACE_TCHAR *src); + + /** + * Looks in provided string for whitespace. Whitespace is defined as + * spaces(' ') and tabs('\t'). + * Returns true if found and false if not found + */ + int string_has_white_space (const ACE_TCHAR *string_value); + + ACE_Ini_ImpExp (const ACE_Ini_ImpExp&); + ACE_Ini_ImpExp& operator= (const ACE_Ini_ImpExp&); +}; + +#include "ace/post.h" +#endif /* ACE_CONFIGURATION_IMPORT_EXPORT_H */ diff --git a/ace/Makefile b/ace/Makefile index 6a7b3692ea1..9532a44f509 100644 --- a/ace/Makefile +++ b/ace/Makefile @@ -35,6 +35,7 @@ UTILS_FILES = \ Capabilities \ Containers \ Configuration \ + Configuration_Import_Export \ Dirent \ Dynamic \ Dynamic_Service_Base \ diff --git a/tests/Config_Test.cpp b/tests/Config_Test.cpp index 8d0b2ece0c5..a57c241555f 100644 --- a/tests/Config_Test.cpp +++ b/tests/Config_Test.cpp @@ -13,12 +13,15 @@ // <ACE_Configuration> work correctly. // // = AUTHOR -// Michael Searles <msearles@base16.com> and Chris Hafey <chafey@stentor.com> +// Michael Searles <msearles@base16.com>, +// Chris Hafey <chafey@stentor.com>, and +// Jerry D. Odenwelder Jr. <jerry.o@mindspring.com> // // ============================================================================ -#include "tests/test_config.h" +#include "test_config.h" #include "Config_Test.h" +#include "ace/Configuration_Import_Export.h" ACE_RCSID(tests, Config_Test, "$Id$") @@ -59,7 +62,7 @@ test (ACE_Configuration *config) u_char data[80]; - for(int i = 0; i < 80; i++) + for (int i = 0; i < 80; i++) data[i] = i + 128; if (config->set_binary_value (testsection, @@ -92,12 +95,12 @@ test (ACE_Configuration *config) if (config->get_binary_value (testsection, ACE_TEXT ("binvalue"), - (void*&) data_out, + (void*&) data_out, length)) return -10; // compare em - for(int j = 0; j < 80; j++) + for (int j = 0; j < 80; j++) if (data_out[j] != data[j]) return -11; @@ -231,7 +234,7 @@ test_io (ACE_Configuration *config) config->root_section (); ACE_Configuration_Section_Key test; - if (config->open_section(root, + if (config->open_section (root, ACE_TEXT ("test"), 1, test)) @@ -272,14 +275,6 @@ test_io (ACE_Configuration *config) 42)) return -8; - // Export it to a file - if(config->export_config (ACE_TEXT ("config.ini"))) - return -9; - // reimport - - if (config->import_config (ACE_TEXT ("config.ini"))) - return -10; - return 0; } @@ -334,107 +329,815 @@ run_tests (void) -1); } - // Test file i/o using a transient heap - ACE_Configuration_Heap io_config; - if (io_config.open ()) + ACE_DEBUG ((LM_DEBUG, "Test passed\n")); + return 0; +} + +static int +build_config_object (ACE_Configuration& cfg) +{ + ACE_Configuration_Section_Key root = cfg.root_section (); + ACE_Configuration_Section_Key NetworkSection; + ACE_Configuration_Section_Key LoggerSection; + ACE_Configuration_Section_Key BinarySection; + + if (cfg.open_section (root, + ACE_TEXT ("network"), + 1, + NetworkSection)) + return -1; + + if (cfg.set_integer_value (NetworkSection, + ACE_TEXT ("TimeToLive"), + 100)) return -2; + else if (cfg.set_string_value (NetworkSection, + ACE_TEXT ("Delay"), + ACE_TString ("FALSE"))) + return -3; + else if (cfg.set_string_value (NetworkSection, + ACE_TEXT ("DestIPAddress"), + ACE_TString ("localhost"))) + return -4; + else if (cfg.set_integer_value (NetworkSection, + ACE_TEXT ("DestPort"), + 12670)) + return -5; + else if (cfg.set_integer_value (NetworkSection, + ACE_TEXT ("ReconnectInterval"), + 3)) + return -6; - int result = test_io (&io_config); - if (result) - ACE_ERROR_RETURN ((LM_ERROR, - "IO Test Failed (%d)\n", - result), - -3); + if (cfg.open_section (root, + ACE_TEXT ("logger"), + 1, + LoggerSection)) + return -7; + + + if (cfg.set_string_value (LoggerSection, + ACE_TEXT ("Heading"), + ACE_TString ("ACE - Adaptive Communication Environment"))) + return -8; + else if (cfg.set_integer_value (LoggerSection, + ACE_TEXT ("SeekIndex"), + 14)) + return -9; + else if (cfg.set_integer_value (LoggerSection, + ACE_TEXT ("TraceLevel"), + 6)) + return -10; + else if (cfg.set_string_value (LoggerSection, + ACE_TEXT ("Justification"), + ACE_TString ("left_justified"))) + return -11; + else if (cfg.set_string_value (LoggerSection, + ACE_TEXT ("LogFilePath"), + ACE_TString ("log/"))) + return -12; + else if (cfg.set_string_value (LoggerSection, + ACE_TEXT ("TransactionFilePath"), + ACE_TString ("data/"))) + return -13; + + if (cfg.open_section (root, + ACE_TEXT ("binary"), + 1, + BinarySection)) + return -14; + + u_char data[80]; + + for (int i = 0; i < 80; i++) + data[i] = i + 128; + + if (cfg.set_binary_value (BinarySection, + ACE_TEXT ("data"), + data, + 80)) + return -15; - ACE_DEBUG ((LM_DEBUG, - "Test passed\n")); return 0; } -void -Config_Test::read_config (void) +/* + * Test ACE_Configuration::operator== + */ +int +Config_Test::testEquality () { - if (m_ConfigurationHeap.open () == 0) + // create and open 2 ACE_Configuration objects. + ACE_Configuration_Heap heap1; + ACE_Configuration_Heap heap2; + if ((heap1.open ()) != 0) { - if (m_ConfigurationHeap.import_config_as_strings (ACE_TEXT ("Config_Test.ini")) == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Cannot open heap1\n"), + -1); + + } + else if ((heap2.open ()) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Cannot open heap2\n"), + -1); + } + + // populate them equally + build_config_object (heap1); + build_config_object (heap2); + + // test equality + ACE_DEBUG ((LM_DEBUG, "The objects should equal...\n")); + if (heap1 == heap2) + { + ACE_DEBUG ((LM_DEBUG, "And they do ;-)\n")); + } + else + { + ACE_ERROR_RETURN ((LM_ERROR, + "And they do not :- (\nThe Equality Operator Failed when objects equal\n"), + -1); + } + + // add a section and value to heap1 + ACE_Configuration_Section_Key root1 = heap1.root_section (); + ACE_Configuration_Section_Key NewSection; + if (heap1.open_section (root1, + ACE_TEXT ("NewSection"), + 1, + NewSection)) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error adding section to heap1\n"), + -1); + } + else if (heap1.set_integer_value (NewSection, + ACE_TEXT ("TestIntValue"), + 100)) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error adding value to heap1\n"), + -2); + } + + // test equality + ACE_DEBUG ((LM_DEBUG, "The objects should NOT equal...\n")); + if (heap1 == heap2) + { + ACE_ERROR_RETURN ((LM_ERROR, + "They Do :- (\nThe Equality Operator Failed when lhs contains data not in rhs\n"), + -1); + } + else + { + ACE_DEBUG ((LM_DEBUG, "And they do not ;-)\n")); + } + + // + // add same section to heap2 + // + ACE_Configuration_Section_Key root2 = heap2.root_section (); + ACE_Configuration_Section_Key NewSection2; + if (heap2.open_section (root2, + ACE_TEXT ("NewSection"), + 1, + NewSection2)) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error adding section to heap2\n"), + -1); + } + else if (heap2.set_integer_value (NewSection2, + ACE_TEXT ("TestIntValue"), + 100)) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error adding value to heap2\n"), + -2); + } + else if (heap2.set_integer_value (NewSection2, + ACE_TEXT ("TestIntValue2"), + 100)) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error adding second value to heap2\n"), + -2); + + } + // test equality + ACE_DEBUG ((LM_DEBUG, "The objects should NOT equal...\n")); + if (heap1 == heap2) + { + ACE_ERROR_RETURN ((LM_ERROR, + "And They Do :- (\nThe Equality Operator Failed when rhs contains value not in lhs\n"), + -1); + } + else + { + ACE_DEBUG ((LM_DEBUG, "And they do not ;-)\n")); + } + + // add new value in heap 1 + if (heap1.set_integer_value (NewSection, + ACE_TEXT ("TestIntValue2"), + 100)) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error adding second value to heap1\n"), + -2); + } + + // test equality + ACE_DEBUG ((LM_DEBUG, "The objects should be equal...\n")); + if (heap1 == heap2) + { + ACE_DEBUG ((LM_DEBUG, "And they are ;-)\n")); + } + else + { + ACE_ERROR_RETURN ((LM_ERROR, + "And they are not :- (\nThe Equality Operator Failed\n"), + -1); + } + + // Add a new section to heap2 + ACE_Configuration_Section_Key AnotherNewSection2; + if (heap2.open_section (root2, + ACE_TEXT ("AnotherNewSection"), + 1, + AnotherNewSection2)) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error adding second section to heap2\n"), + -1); + } + else if (heap2.set_integer_value (AnotherNewSection2, + ACE_TEXT ("TestIntValue"), + 100)) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error adding value in second section to heap2\n"), + -2); + } + + // test equality + ACE_DEBUG ((LM_DEBUG, "The objects should NOT equal...\n")); + if (heap1 == heap2) + { + ACE_ERROR_RETURN ((LM_ERROR, + "And they do :- (\nThe Equality Operator Failed when rhs contains data not in lhs\n"), + -1); + } + else + { + ACE_DEBUG ((LM_DEBUG, "And they do not :-)\n")); + } + + // add section back to heap1 + ACE_Configuration_Section_Key AnotherNewSection1; + if (heap1.open_section (root1, + ACE_TEXT ("AnotherNewSection"), + 1, + AnotherNewSection1)) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error adding second section to heap1\n"), + -1); + } + else if (heap1.set_integer_value (AnotherNewSection1, + ACE_TEXT ("TestIntValue"), + 100)) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error adding second value to second section in heap1\n"), + -2); + } + + // test equality + ACE_DEBUG ((LM_DEBUG, "The objects should be equal...\n")); + if (heap1 == heap2) + { + ACE_DEBUG ((LM_DEBUG, "And they are ;-)\n")); + } + else + { + ACE_ERROR_RETURN ((LM_ERROR, + "And they are not :-)\nThe Equality Operator Failed\n"), + -1); + } + + this->equality_tested_ = 1; + return 0; +} + +/* + * Compare INI import data in fromFile to origional data exported (in origional) + * + * This compare is destructive to the origional object. + * I realize that normally you would not do such an obscene thing but + * this funciton has a special purpose and I know my origional is not needed + * after calling this routine. + * This is done because configuration objects that are imported using the INI + * import store all data as strings. My origional has type information and I need to + * know if the import worked. +*/ +static int +iniCompare (ACE_Configuration_Heap& fromFile, ACE_Configuration_Heap& original) +{ + int rc = 1; // start by guessing they are equal + + int sectionIndex = 0; + ACE_TString sectionName; + + const ACE_Configuration_Section_Key& fromFileRoot = fromFile.root_section (); + const ACE_Configuration_Section_Key& originalRoot = original.root_section (); + ACE_Configuration_Section_Key originalSection; + ACE_Configuration_Section_Key fromFileSection; + + // loop through each section in the fromFile object + while ((rc) && + (!fromFile.enumerate_sections (fromFileRoot, + sectionIndex, + sectionName)) ) + { + // find that section in the original object + if (original.open_section (originalRoot, + sectionName.c_str (), + 0, + originalSection) != 0) + { + // If the original object does not contain the section then we are not equal. + rc = 0; + } + else if (fromFile.open_section (fromFileRoot, + sectionName.c_str (), + 0, + fromFileSection) != 0) { - ACE_Configuration_Section_Key root = m_ConfigurationHeap.root_section (); - // Process [network] section - ACE_Configuration_Section_Key NetworkSection; - if (m_ConfigurationHeap.open_section (root, - ACE_TEXT ("network"), - 1, - NetworkSection) == 0) + // if there is some error opening the section in the fromFile + rc = 0; + } + else + { + // Well the sections match + int valueIndex = 0; + ACE_TString valueName; + ACE_Configuration::VALUETYPE valueType; + ACE_Configuration::VALUETYPE originalType; + + // Enumerate each value in the fromFile section + while ((rc) && + (!fromFile.enumerate_values (fromFileSection, + valueIndex, + valueName, + valueType))) { - this->get_section_integer (NetworkSection, - ACE_TEXT ("TimeToLive"), - &m_nTimeToLive, - 1, - 20); - this->get_section_boolean (NetworkSection, - ACE_TEXT ("Delay"), - &m_bDelay); - this->get_section_string (NetworkSection, - ACE_TEXT ("DestIPAddress"), - m_pszDestIPAddress, - TEST_MAX_STRING); - this->get_section_integer (NetworkSection, - ACE_TEXT ("DestPort"), - &m_nDestPort, - 0, - 65535); - this->get_section_integer (NetworkSection, - ACE_TEXT ("ReconnectInterval"), - &m_nReconnectInterval, - 0, - 65535); - } - - // Process [logger] section - ACE_Configuration_Section_Key LoggerSection; - - if (m_ConfigurationHeap.open_section (root, - ACE_TEXT ("logger"), - 1, - LoggerSection) == 0) + // look for the same value in the original section + if (original.find_value (originalSection, + valueName.c_str (), + originalType) != 0) + { + // We're not equal if the same value cannot + // be found in the original object. + rc = 0; + } + else + { + ACE_TString fromFileString, originalString; + + + if (fromFile.get_string_value (fromFileSection, + valueName.c_str (), + fromFileString) != 0) + { + // we're not equal if we cannot get this string + rc = 0; + } + else if (originalType != ACE_Configuration::STRING) // If the original type is not a string + { + // convert original data to a string. + + if (originalType == ACE_Configuration::INTEGER) + { + u_int intValue; + ACE_TCHAR int_value[32]; + + if (original.get_integer_value (originalSection, + valueName.c_str (), + intValue) != 0) + { + // we're not equal if we cannot get rhs int + rc = 0; + } + ACE_OS::sprintf (int_value, ACE_LIB_TEXT ("%08x"), intValue); + originalString = int_value; + } + else if (originalType == ACE_Configuration::BINARY) + { + + void* binary_data; + u_int binary_length; + + if (original.get_binary_value (originalSection, + valueName.c_str (), + binary_data, + binary_length)) + { + // we're not equal if we cannot get this string + rc = 0; + } + else + { + ACE_TCHAR bin_value[3]; + + unsigned char* ptr = (unsigned char*)binary_data; + while (binary_length) + { + if (ptr != binary_data) + { + originalString += ACE_LIB_TEXT (","); + } + ACE_OS::sprintf (bin_value, ACE_LIB_TEXT ("%02x"), *ptr); + originalString += bin_value; + --binary_length; + ++ptr; + } + delete (char *)binary_data; + }// end successful binary read + }// end if originalType was binary + else + { + // if the type is invalid, then go ahead and fail it. + rc = 0; + } + + }// end if the original type was not a string. + else + { + if (original.get_string_value (originalSection, + valueName.c_str (), + originalString) != 0) + { + // we're not equal if we cannot get rhs string + rc = 0; + } + + } + + rc &= fromFileString == originalString; + + if (rc) + { + // before we move on remove this value from the original. + original.remove_value (originalSection, + valueName.c_str ()); + } + + }// end else if values match. + + valueIndex++; + + }// end value while loop + + // at this point the original should have no values. + // look for values in the original section + valueIndex = 0; + while ((rc) && + (!original.enumerate_values (originalSection, + valueIndex, + valueName, + originalType))) { - this->get_section_string (LoggerSection, - ACE_TEXT ("Heading"), - m_pszHeading, - TEST_MAX_STRING); - this->get_section_integer (LoggerSection, - ACE_TEXT ("TraceLevel"), - &m_nTraceLevel, - 1, - 20); - this->get_section_string (LoggerSection, - ACE_TEXT ("Justification"), - m_pszJustification, - TEST_MAX_STRING); - this->get_section_string (LoggerSection, - ACE_TEXT ("LogFilePath"), - m_pszLogFilePath, - TEST_MAX_STRING); - this->get_section_string (LoggerSection, - ACE_TEXT ("TransactionFilePath"), - m_pszTransactionFilePath, - TEST_MAX_STRING); - } + valueIndex++; + }// end while for rhs values not in this. + + // having a value indicates a mismatch + rc = valueIndex == 0; + + }// end else if sections match. + + if (rc) + { + // before we move on remove the section from the original. + original.remove_section (originalRoot, + sectionName.c_str (), + 0); // do not remove subsections. + } + + sectionIndex++; + + }// end section while loop + + // Finally, if the original has any sections, then we're not equal + sectionIndex = 0; + while ((rc) && + (!original.enumerate_sections (originalRoot, + sectionIndex, + sectionName)) ) + { + sectionIndex++; + } + + rc = sectionIndex == 0; + + return rc; +} + +// Used to test INI Import Export class + +int +Config_Test::testIniFormat () +{ + int rc = 0; + if (!this->equality_tested_) + { + if ((rc = this->testEquality ()) != 0) + { + ACE_DEBUG ((LM_DEBUG, "Equality Test Failed\n")); + return rc; + } + } + ACE_DEBUG ((LM_DEBUG, "Testing INI Format Import/Export\n")); + ACE_Configuration_Heap fromFile; + + // 1. Creates an ACE_Configuration_Heap object + ACE_Configuration_Heap original; + + if ((rc = original.open ()) == 0) + { + // 2. Calls build_config_object to populate + if ((rc = build_config_object (original)) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error populating original config object (%d)\n", + rc), + -1); + } + + // 3. Export + ACE_Ini_ImpExp importExport (original); + + if ((rc = importExport.export_config ("testConfig.ini")) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error Exporting (%d)\n", + rc), + -1); + } + + } + else + { + ACE_ERROR_RETURN ((LM_ERROR, + "Could not open original object (%d)\n", + rc), + -1); + } + + + // At this point we've successfully created, populated and written + // the configuration object + // 5. Creates a new ACE_Configuration_Heap object + if ((rc = fromFile.open ()) == 0) + { + // 6. Imports + ACE_Ini_ImpExp importExport (fromFile); + + if ((rc = importExport.import_config ("testConfig.ini")) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error Exporting (%d)\n", + rc), + -1); + } + + // 7. Compares to original. + // This is a special compare since files imported using the + // INI file import do not contain type information + // + // NOTE: After this call the original object will be invalid!!! + // + if (!iniCompare (fromFile, original)) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Object read from file does not equal original (%d)\n", + rc), + -1); + + } + }// end if heap could not be opened. + else + { + ACE_ERROR_RETURN ((LM_ERROR, + "Could not open fromFile object (%d)\n", + rc), + -1); + } + + // 8. Calls old "read_config" methods on the new object + + int nTimeToLive; + int bDelay; + int nDestPort; + int nReconnectInterval; + int nTraceLevel; + + ACE_TCHAR pszDestIPAddress[TEST_MAX_STRING]; + ACE_TCHAR pszLogFilePath[TEST_MAX_STRING]; + ACE_TCHAR pszTransactionFilePath[TEST_MAX_STRING]; + ACE_TCHAR pszHeading[TEST_MAX_STRING]; + ACE_TCHAR pszJustification[TEST_MAX_STRING]; + + ACE_Configuration_Section_Key root = fromFile.root_section (); + + // Process [network] section + ACE_Configuration_Section_Key NetworkSection; + if (fromFile.open_section (root, + ACE_TEXT ("network"), + 1, + NetworkSection) == 0) + { + this->get_section_integer (fromFile, + NetworkSection, + ACE_TEXT ("TimeToLive"), + &nTimeToLive, + 1, + 20); + + this->get_section_boolean (fromFile, + NetworkSection, + ACE_TEXT ("Delay"), + &bDelay); + + this->get_section_string (fromFile, + NetworkSection, + ACE_TEXT ("DestIPAddress"), + pszDestIPAddress, + TEST_MAX_STRING); + + this->get_section_integer (fromFile, + NetworkSection, + ACE_TEXT ("DestPort"), + &nDestPort, + 0, + 65535); + + this->get_section_integer (fromFile, + NetworkSection, + ACE_TEXT ("ReconnectInterval"), + &nReconnectInterval, + 0, + 65535); + }// end of "network" section + + // Process [logger] section + ACE_Configuration_Section_Key LoggerSection; + if (fromFile.open_section (root, + ACE_TEXT ("logger"), + 1, + LoggerSection) == 0) + { + this->get_section_string (fromFile, + LoggerSection, + ACE_TEXT ("Heading"), + pszHeading, + TEST_MAX_STRING); + this->get_section_integer (fromFile, + LoggerSection, + ACE_TEXT ("TraceLevel"), + &nTraceLevel, + 1, + 20); + this->get_section_string (fromFile, + LoggerSection, + ACE_TEXT ("Justification"), + pszJustification, + TEST_MAX_STRING); + this->get_section_string (fromFile, + LoggerSection, + ACE_TEXT ("LogFilePath"), + pszLogFilePath, + TEST_MAX_STRING); + this->get_section_string (fromFile, + LoggerSection, + ACE_TEXT ("TransactionFilePath"), + pszTransactionFilePath, + TEST_MAX_STRING); + }// end of "logger" section + + if (!rc) + ACE_DEBUG ((LM_DEBUG, "INI Format Import/Export Works ;-)\n")); + return rc; +} + +// Used to test registry Import Export class + +int +Config_Test::testRegFormat () +{ + int rc = 0; + if (!this->equality_tested_) + { + if ((rc = this->testEquality ()) != 0) + { + ACE_DEBUG ((LM_DEBUG, "Equality Test Failed\n")); + return rc; + } + + } + ACE_DEBUG ((LM_DEBUG, "Testing Registry Format Import/Export\n")); + ACE_Configuration_Heap fromFile; + + // 1. Creates an ACE_Configuration_Heap object + ACE_Configuration_Heap original; + + if ((rc = original.open ()) == 0) + { + // 2. Calls build_config_object to populate + if ((rc = build_config_object (original)) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error populating original config object (%d)\n", + rc), + -1); + } + + // 3. Export + ACE_Registry_ImpExp importExport (original); + + if ((rc = importExport.export_config ("testConfig.ini")) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error Exporting (%d)\n", + rc), + -1); } + + } + else + { + ACE_ERROR_RETURN ((LM_ERROR, + "Could not open original object (%d)\n", + rc), + -1); } + + + // At this point we've successfully created, populated and written + // the configuration object + // 5. Creates a new ACE_Configuration_Heap object + if ((rc = fromFile.open ()) == 0) + { + // 6. Imports + ACE_Registry_ImpExp importExport (fromFile); + + if ((rc = importExport.import_config ("testConfig.ini")) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Error Exporting (%d)\n", + rc), + -1); + } + + // 7. Compares to original. + if (fromFile != original) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Object read from file does not equal original (%d)\n", + rc), + -1); + + } + }// end if heap could not be opened. + else + { + ACE_ERROR_RETURN ((LM_ERROR, + "Could not open fromFile object (%d)\n", + rc), + -1); + } + + if (!rc) + ACE_DEBUG ((LM_DEBUG, "Registry Format Import/Export Works ;-)\n")); + return rc; } + +// Reads a string value from a configuration object. + void -Config_Test::get_section_string (ACE_Configuration_Section_Key& SectionKey, - const ACE_TCHAR *pszName, - ACE_TCHAR *pszVariable, - int nMaxLength) +Config_Test::get_section_string (ACE_Configuration& config, + ACE_Configuration_Section_Key& SectionKey, + const ACE_TCHAR* pszName, + ACE_TCHAR* pszVariable, + int nMaxLength) { ACE_TString StringValue; - if (m_ConfigurationHeap.get_string_value (SectionKey, - pszName, - StringValue) == 0) + if (config.get_string_value (SectionKey, + pszName, + StringValue) == 0) { ACE_OS::strncpy (pszVariable, StringValue.c_str (), @@ -446,21 +1149,23 @@ Config_Test::get_section_string (ACE_Configuration_Section_Key& SectionKey, } } +// Reads an integer value from a congifuration object (when it's stored as a string) void -Config_Test::get_section_integer (ACE_Configuration_Section_Key& SectionKey, - const ACE_TCHAR *pszName, - int *nVariable, - int nMinValue, - int nMaxValue) +Config_Test::get_section_integer (ACE_Configuration& config, + ACE_Configuration_Section_Key& SectionKey, + const ACE_TCHAR* pszName, + int* nVariable, + int nMinValue, + int nMaxValue) { ACE_TString StringValue; ACE_TCHAR pszString[30]; - ACE_OS::strcpy(pszString, ACE_TEXT ("0")); + ACE_OS::strcpy (pszString, ACE_TEXT ("0")); int IntegerValue = 0; - if (m_ConfigurationHeap.get_string_value (SectionKey, - pszName, - StringValue) == 0) + if (config.get_string_value (SectionKey, + pszName, + StringValue) == 0) { ACE_OS::strncpy (pszString, StringValue.c_str (), @@ -473,25 +1178,26 @@ Config_Test::get_section_integer (ACE_Configuration_Section_Key& SectionKey, // convert to integer IntegerValue = ACE_OS::atoi (pszString); - IntegerValue = (IntegerValue < nMinValue) ? nMinValue : IntegerValue; IntegerValue = (IntegerValue > nMaxValue) ? nMaxValue : IntegerValue; - *nVariable = IntegerValue; } +// Reads a boolean value from a configuration object (when it's stored as a string). + void -Config_Test::get_section_boolean (ACE_Configuration_Section_Key& SectionKey, - const ACE_TCHAR* pszName, - int* pVariable) +Config_Test::get_section_boolean (ACE_Configuration& config, + ACE_Configuration_Section_Key& SectionKey, + const ACE_TCHAR* pszName, + int* pVariable) { ACE_TString StringValue; ACE_TCHAR pszString[10]; ACE_OS::strcpy (pszString, ACE_TEXT ("0")); - if (m_ConfigurationHeap.get_string_value (SectionKey, - pszName, - StringValue) == 0) + if (config.get_string_value (SectionKey, + pszName, + StringValue) == 0) { ACE_OS::strncpy (pszString, StringValue.c_str (), @@ -523,8 +1229,16 @@ main (int, ACE_TCHAR *[]) ACE_START_TEST (ACE_TEXT ("Config_Test")); Config_Test manager; - manager.read_config (); + if (manager.testEquality () != 0) + ACE_DEBUG ((LM_DEBUG, "Failed the equality Test\n")); + + if (manager.testRegFormat () != 0) + ACE_DEBUG ((LM_DEBUG, "Failed the REG Format Test\n")); + + if (manager.testIniFormat () != 0) + ACE_DEBUG ((LM_DEBUG, "Failed the INI Format Test\n")); + run_tests (); ACE_END_TEST; diff --git a/tests/Config_Test.h b/tests/Config_Test.h index c46d141b21f..4736d93575e 100644 --- a/tests/Config_Test.h +++ b/tests/Config_Test.h @@ -13,7 +13,8 @@ // <ACE_Configuration_Heap> class works correctly. // // = AUTHOR -// Michael Searles <msearles@base16.com> +// Michael Searles <msearles@base16.com> and +// Jerry D. Odenwelder Jr. <jerry.o@mindspring.com> // // ============================================================================ @@ -26,38 +27,47 @@ const int TEST_MAX_STRING = 256; class Config_Test { - ACE_Configuration_Heap m_ConfigurationHeap; +public: + Config_Test (void): equality_tested_ (0) { } + ~Config_Test (void) { } - int m_nTimeToLive; - int m_bDelay; - ACE_TCHAR m_pszDestIPAddress[TEST_MAX_STRING]; - int m_nDestPort; - int m_nReconnectInterval; + // Used to test the equality and inequality operations. + int testEquality (); - ACE_TCHAR m_pszLogFilePath[TEST_MAX_STRING]; - ACE_TCHAR m_pszTransactionFilePath[TEST_MAX_STRING]; - ACE_TCHAR m_pszHeading[TEST_MAX_STRING]; - int m_nTraceLevel; - ACE_TCHAR m_pszJustification[TEST_MAX_STRING]; + // Used to test INI Import Export class + int testIniFormat (); -public: - Config_Test (void) { } - ~Config_Test (void) { } - void read_config (void); + // Used to test Regiastry Import Export class + // 1. Creates an ACE_Configuration_Heap object + // 2. Calls buildConfigObject to populate + // 3. Exports + // 5. Creates a new ACE_Configuration_Heap object + // 6. Imports + // 7. Compares to origional. + // 8. Clean-up + int testRegFormat (); + +private: + void get_section_string (ACE_Configuration& config, + ACE_Configuration_Section_Key& SectionKey, + const ACE_TCHAR* pszName, + ACE_TCHAR* pszVariable, + int nMaxLength); + + void get_section_integer (ACE_Configuration& config, + ACE_Configuration_Section_Key& SectionKey, + const ACE_TCHAR* pszName, + int* nVariable, + int nMinValue, + int nMaxValue); + + void get_section_boolean (ACE_Configuration& config, + ACE_Configuration_Section_Key& SectionKey, + const ACE_TCHAR* pszName, + int* pVariable); private: - void get_section_string (ACE_Configuration_Section_Key& SectionKey, - const ACE_TCHAR *pszName, - ACE_TCHAR *pszVariable, - int nMaxLength); - void get_section_integer (ACE_Configuration_Section_Key& SectionKey, - const ACE_TCHAR *pszName, - int *nVariable, - int nMinValue, - int nMaxValue); - void get_section_boolean (ACE_Configuration_Section_Key& SectionKey, - const ACE_TCHAR *pszName, - int *pVariable); + int equality_tested_; // make sure the equality operator works before proceeding. }; #endif /* __CONFIG_TEST_H */ |