1 // $Id: Configuration_Import_Export.cpp 80826 2008-03-04 14:51:23Z wotte $
3 #include "ace/Configuration_Import_Export.h"
4 #include "ace/OS_Errno.h"
5 #include "ace/OS_NS_stdio.h"
6 #include "ace/OS_NS_ctype.h"
7 #include "ace/OS_NS_string.h"
9 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
11 ACE_Config_ImpExp_Base::ACE_Config_ImpExp_Base (ACE_Configuration
& config
)
16 ACE_Config_ImpExp_Base::~ACE_Config_ImpExp_Base (void)
20 ACE_Registry_ImpExp::ACE_Registry_ImpExp (ACE_Configuration
& config
)
21 : ACE_Config_ImpExp_Base (config
)
25 ACE_Registry_ImpExp::~ACE_Registry_ImpExp (void)
29 // Imports the configuration database from filename.
30 // No existing data is removed.
32 ACE_Registry_ImpExp::import_config (const ACE_TCHAR
* filename
)
39 FILE* in
= ACE_OS::fopen (filename
, ACE_TEXT ("r"));
43 u_int buffer_size
= 4096;
45 ACE_TCHAR
*buffer
= 0;
46 ACE_NEW_NORETURN (buffer
, ACE_TCHAR
[buffer_size
]);
49 ACE_Errno_Guard
guard (errno
);
50 (void) ACE_OS::fclose (in
);
53 ACE_Configuration_Section_Key section
;
56 while (ACE_OS::fgets (buffer
+read_pos
, buffer_size
- read_pos
, in
))
58 // Check if we got all the line.
59 end
= ACE_OS::strrchr (buffer
+ read_pos
,
60 ACE_TEXT ('\n')); // look for end of line
61 if (!end
) // we havn't reach the end of the line yet
63 // allocate a new buffer - double size the previous one
64 ACE_TCHAR
*temp_buffer
;
65 ACE_NEW_NORETURN (temp_buffer
, ACE_TCHAR
[buffer_size
* 2]);
68 ACE_Errno_Guard
guard (errno
);
70 (void) ACE_OS::fclose (in
);
74 // copy the beginnning of the line
75 ACE_OS::memcpy (temp_buffer
, buffer
, buffer_size
);
76 read_pos
= buffer_size
- 1;
84 // Check for a comment
85 if (buffer
[0] == ACE_TEXT (';') || buffer
[0] == ACE_TEXT ('#'))
88 if (buffer
[0] == ACE_TEXT ('['))
90 // We have a new section here, strip out the section name
91 end
= ACE_OS::strrchr (buffer
, ACE_TEXT (']'));
100 if (config_
.expand_path (config_
.root_section (), buffer
+ 1, section
, 1))
107 } // end if firs char is a [
109 if (buffer
[0] == ACE_TEXT ('"'))
112 end
= ACE_OS::strchr (buffer
+1, '"');
113 if (!end
) // no closing quote, not a value so just skip it
116 // null terminate the name
118 ACE_TCHAR
* name
= buffer
+ 1;
120 // determine the type
124 // truncate trailing "
126 ACE_TCHAR
* trailing
= ACE_OS::strrchr (end
, '"');
129 if (config_
.set_string_value (section
, name
, end
))
136 else if (ACE_OS::strncmp (end
, ACE_TEXT ("dword:"), 6) == 0)
139 ACE_TCHAR
* endptr
= 0;
140 unsigned long value
= ACE_OS::strtoul (end
+ 6, &endptr
, 16);
141 if (config_
.set_integer_value (section
, name
, value
))
148 else if (ACE_OS::strncmp (end
, ACE_TEXT ("hex:"), 4) == 0)
151 size_t string_length
= ACE_OS::strlen (end
+ 4);
152 // divide by 3 to get the actual buffer length
153 size_t length
= string_length
/ 3;
154 size_t remaining
= length
;
156 ACE_NEW_RETURN (data
,
160 ACE_TCHAR
* inb
= end
+ 4;
161 ACE_TCHAR
* endptr
= 0;
164 u_char charin
= (u_char
) ACE_OS::strtoul (inb
, &endptr
, 16);
170 if (config_
.set_binary_value (section
, name
, data
, length
))
182 // invalid type, ignore
185 }// end if first char is a "
188 // if the first character is not a ", [, ;, or # we may be
189 // processing a file in the old format.
190 // Try and process the line as such and if it fails,
192 int rc
= process_previous_line_format (buffer
, section
);
199 } // end if maybe old format
214 // This method exports the entire configuration database to <filename>.
215 // Once the file is opened this method calls 'export_section' passing
218 ACE_Registry_ImpExp::export_config (const ACE_TCHAR
* filename
)
227 FILE* out
= ACE_OS::fopen (filename
, ACE_TEXT ("w"));
230 result
= this->export_section (config_
.root_section (),
233 // The data may have been buffered and will be flush on close,
234 // so we need to check that the close succeeds.
235 if (ACE_OS::fclose (out
) < 0)
241 // Method provided by derived classes in order to write one section
242 // to the file specified. Called by export_config when exporting
243 // the entire configuration object.
246 ACE_Registry_ImpExp::export_section (const ACE_Configuration_Section_Key
& section
,
247 const ACE_TString
& path
,
250 // don't export the root
253 // Write out the section header
254 ACE_TString header
= ACE_TEXT ("[");
256 header
+= ACE_TEXT ("]");
257 header
+= ACE_TEXT (" \n");
258 if (ACE_OS::fputs (header
.fast_rep (), out
) < 0)
260 // Write out each value
263 ACE_Configuration::VALUETYPE type
;
265 ACE_TCHAR int_value
[32];
266 ACE_TCHAR bin_value
[3];
268 size_t binary_length
;
269 ACE_TString string_value
;
270 while (!config_
.enumerate_values (section
, index
, name
, type
))
272 line
= ACE_TEXT ("\"") + name
+ ACE_TEXT ("\"=");
275 case ACE_Configuration::INTEGER
:
278 if (config_
.get_integer_value (section
, name
.fast_rep (), value
))
280 ACE_OS::sprintf (int_value
, ACE_TEXT ("%08x"), value
);
281 line
+= ACE_TEXT ("dword:");
285 case ACE_Configuration::STRING
:
287 if (config_
.get_string_value (section
,
291 line
+= ACE_TEXT ("\"");
292 line
+= string_value
+ ACE_TEXT ("\"");
296 case ACE_Configuration::INVALID
:
297 break; // JDO added break. Otherwise INVALID is processed
298 // like BINARY. If that's correct, please remove the
299 // break and these comments
301 case ACE_Configuration::BINARY
:
303 // not supported yet - maybe use BASE64 codeing?
304 if (config_
.get_binary_value (section
,
309 line
+= ACE_TEXT ("hex:");
310 unsigned char* ptr
= (unsigned char*)binary_data
;
311 while (binary_length
)
313 if (ptr
!= binary_data
)
315 line
+= ACE_TEXT (",");
317 ACE_OS::sprintf (bin_value
, ACE_TEXT ("%02x"), *ptr
);
322 delete [] (char*) binary_data
;
328 line
+= ACE_TEXT ("\n");
329 if (ACE_OS::fputs (line
.fast_rep (), out
) < 0)
334 // Export all sub sections
337 ACE_Configuration_Section_Key sub_key
;
338 ACE_TString sub_section
;
339 while (!config_
.enumerate_sections (section
, index
, name
))
341 ACE_TString
sub_section (path
);
343 sub_section
+= ACE_TEXT ("\\");
345 if (config_
.open_section (section
, name
.fast_rep (), 0, sub_key
))
347 if (export_section (sub_key
, sub_section
.fast_rep (), out
))
355 // This method read the line format origionally used in ACE 5.1
358 ACE_Registry_ImpExp::process_previous_line_format (ACE_TCHAR
* buffer
,
359 ACE_Configuration_Section_Key
& section
)
361 // Chop any cr/lf at the end of the line.
362 ACE_TCHAR
*endp
= ACE_OS::strpbrk (buffer
, ACE_TEXT ("\r\n"));
366 // assume this is a value, read in the value name
367 ACE_TCHAR
* end
= ACE_OS::strchr (buffer
, '=');
368 if (end
) // no =, not a value so just skip it
370 // null terminate the name
373 // determine the type
377 if(config_
.set_string_value (section
, buffer
, end
+ 1))
380 else if (*end
== '#')
383 u_int value
= ACE_OS::atoi (end
+ 1);
384 if (config_
.set_integer_value (section
, buffer
, value
))
389 } // end read_previous_line_format
392 ACE_Ini_ImpExp::ACE_Ini_ImpExp (ACE_Configuration
& config
)
393 : ACE_Config_ImpExp_Base (config
)
397 ACE_Ini_ImpExp::~ACE_Ini_ImpExp (void)
401 // Method to read file and populate object.
403 ACE_Ini_ImpExp::import_config (const ACE_TCHAR
* filename
)
410 FILE* in
= ACE_OS::fopen (filename
, ACE_TEXT ("r"));
414 // @@ Make this a dynamic size!
415 ACE_TCHAR buffer
[4096];
416 ACE_Configuration_Section_Key section
;
417 while (ACE_OS::fgets (buffer
, sizeof buffer
, in
))
419 ACE_TCHAR
*line
= this->squish (buffer
);
420 // Check for a comment and blank line
421 if (line
[0] == ACE_TEXT (';') ||
422 line
[0] == ACE_TEXT ('#') ||
426 if (line
[0] == ACE_TEXT ('['))
428 // We have a new section here, strip out the section name
429 ACE_TCHAR
* end
= ACE_OS::strrchr (line
, ACE_TEXT (']'));
437 if (config_
.expand_path (config_
.root_section (),
449 // We have a line; name ends at equal sign.
450 ACE_TCHAR
*end
= ACE_OS::strchr (line
, ACE_TEXT ('='));
451 if (end
== 0) // No '='
457 ACE_TCHAR
*name
= this->squish (line
);
459 if (ACE_OS::strlen (name
) == 0) // No name; just an '='
465 // Now find the start of the value
466 ACE_TCHAR
*value
= this->squish (end
);
467 size_t value_len
= ACE_OS::strlen (value
);
470 // ACE 5.2 (and maybe earlier) exported strings may be enclosed
471 // in quotes. If string is quote-delimited, strip the quotes.
472 // Newer exported files don't have quote delimiters.
473 if (value
[0] == ACE_TEXT ('"') &&
474 value
[value_len
- 1] == ACE_TEXT ('"'))
476 // Strip quotes off both ends.
477 value
[value_len
- 1] = '\0';
482 if (config_
.set_string_value (section
, name
, value
))
499 // This method exports the entire configuration database to <filename>.
500 // Once the file is opened this method calls 'export_section' passing
503 ACE_Ini_ImpExp::export_config (const ACE_TCHAR
* filename
)
512 FILE* out
= ACE_OS::fopen (filename
, ACE_TEXT ("w"));
515 result
= this->export_section (config_
.root_section (),
518 // The data may have been buffered and will be flush on close,
519 // so we need to check that the close succeeds.
520 if (ACE_OS::fclose (out
) < 0)
526 // Method provided by derived classes in order to write one section to the
527 // file specified. Called by export_config when exporting the entire
528 // configuration objet
531 ACE_Ini_ImpExp::export_section (const ACE_Configuration_Section_Key
& section
,
532 const ACE_TString
& path
,
535 // don't export the root
538 // Write out the section header
539 ACE_TString header
= ACE_TEXT ("[");
541 header
+= ACE_TEXT ("]\n");
542 if (ACE_OS::fputs (header
.fast_rep (), out
) < 0)
544 // Write out each value
547 ACE_Configuration::VALUETYPE type
;
549 ACE_TCHAR int_value
[32];
550 ACE_TCHAR bin_value
[3];
552 size_t binary_length
;
553 ACE_TString string_value
;
554 while (!config_
.enumerate_values (section
, index
, name
, type
))
556 line
= name
+ ACE_TEXT ("=");
559 case ACE_Configuration::INTEGER
:
562 if (config_
.get_integer_value (section
, name
.fast_rep (), value
))
564 ACE_OS::sprintf (int_value
, ACE_TEXT ("%08x"), value
);
568 case ACE_Configuration::STRING
:
570 if (config_
.get_string_value (section
,
574 line
+= string_value
;
578 case ACE_Configuration::INVALID
:
579 break; // JDO added break. Otherwise INVALID is processed
580 // like BINARY. If that's correct, please remove the
581 // break and these comments
583 case ACE_Configuration::BINARY
:
585 // not supported yet - maybe use BASE64 codeing?
586 if (config_
.get_binary_value (section
,
591 line
+= ACE_TEXT ("\"");
592 unsigned char* ptr
= (unsigned char*)binary_data
;
593 while (binary_length
)
595 if (ptr
!= binary_data
)
597 line
+= ACE_TEXT (",");
599 ACE_OS::sprintf (bin_value
, ACE_TEXT ("%02x"), *ptr
);
604 line
+= ACE_TEXT ("\"");
605 delete [] (char *) binary_data
;
611 }// end switch on type
613 line
+= ACE_TEXT ("\n");
614 if (ACE_OS::fputs (line
.fast_rep (), out
) < 0)
617 }// end while enumerating values
619 // Export all sub sections
622 ACE_Configuration_Section_Key sub_key
;
623 ACE_TString sub_section
;
624 while (!config_
.enumerate_sections (section
, index
, name
))
626 ACE_TString
sub_section (path
);
628 sub_section
+= ACE_TEXT ("\\");
630 if (config_
.open_section (section
, name
.fast_rep (), 0, sub_key
))
632 if (export_section (sub_key
, sub_section
.fast_rep (), out
))
640 // Method to squish leading and trailing whitespaces from a string.
641 // Whitespace is defined as: spaces (' '), tabs ('\t') or end-of-line
642 // (cr/lf). The terminating nul is moved up to expunge trailing
643 // whitespace and the returned pointer points at the first
644 // non-whitespace character in the string, which may be the nul
645 // terminator if the string is all whitespace.
648 ACE_Ini_ImpExp::squish (ACE_TCHAR
*src
)
655 // Start at the end and work backwards over all whitespace.
656 for (cp
= src
+ ACE_OS::strlen (src
) - 1;
659 if (!ACE_OS::ace_isspace (*cp
))
661 cp
[1] = '\0'; // Chop trailing whitespace
663 // Now start at the beginning and move over all whitespace.
664 for (cp
= src
; ACE_OS::ace_isspace (*cp
); ++cp
)
670 ACE_END_VERSIONED_NAMESPACE_DECL