DYT/Tool/3rdParty_x64/include/dcmtk/ofstd/ofconfig.h
2024-11-22 23:19:31 +08:00

552 lines
17 KiB
C++

/*
*
* Copyright (C) 1997-2011, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
*
* OFFIS e.V.
* R&D Division Health
* Escherweg 2
* D-26121 Oldenburg, Germany
*
*
* Module: ofstd
*
* Author: Marco Eichelberg
*
* Purpose:
* classes: OFConfigFile
*
*/
#ifndef OFCONFIG_H
#define OFCONFIG_H
#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
#include "dcmtk/ofstd/ofstring.h"
#include "dcmtk/ofstd/ofstack.h"
#include "dcmtk/ofstd/ofstream.h"
#define INCLUDE_CSTDIO
#include "dcmtk/ofstd/ofstdinc.h"
/*
* Short description of configuration file structure:
* - The data in a configuration file have a tree structure.
* The tree has a depth defined at instantiation time (by default, OFConfigFile_MaxLevel),
* not including the (imaginary) root node.
* - A level 0 entry (a leaf) has the form: KEYWORD = VALUE,
* where the keyword starts on row one of a line.
* - A level 1 entry has the form [KEYWORD]
* - A level 2 entry has the form [[KEYWORD]] (and so on).
* - Keywords may consist of:
* A..Z, a..z (which are converted to uppercase),
* 0..9,
* '-'
* - Values can be any kind of ASCII text. Values may span multiple lines.
* To continue a value in the next line, the next line MUST start with
* (any amount of) whitespace, which is discarded when reading the value.
* linefeeds (converted to ASCII 10 if necessary) are kept in the
* value string. Empty lines are discarded (and also their linefeed).
* - The data must have a "clean" tree structure. This means that there
* MUST be a level 2 keyword before any level 1 keyword etc.
* - lines starting with the comment char (default is "#") are interpreted
* as comment lines.
*
*/
#define OFConfigFile_MaxLevel 2
#define OFConfigFile_CommentChar '#'
class OFConfigFile;
class OFConfigFileNode;
typedef OFConfigFileNode *OFPConfigFileNode;
/** this class maintains one configuration file entry (key-value pair)
* and the links that comprise the configuration file tree structure.
* Internal use only.
*/
class DCMTK_OFSTD_EXPORT OFConfigFileNode
{
public:
/** constructor.
* @param keyword configuration keyword, copied into this object
*/
OFConfigFileNode(const char *keyword);
/// destructor, recursively deletes whole tree
~OFConfigFileNode();
/** return keyword as C string
*/
const char *getKeyword() const
{
return keyword_.c_str();
}
/** return current value as C string
*/
const char *getValue() const
{
return value_.c_str();
}
/** set value from C string
* @param c C string, must not be NULL
*/
void setValue(const char *c)
{
value_ = c;
}
/** check if keyword matches given string
* @param c C string, must not be NULL
* @return true if equal, false otherwise
*/
OFBool match(const char *c) const
{
return (keyword_ == c);
}
/** check if keyword compares "<" to given string
* @param c C string, must not be NULL
* @return true if equal, false otherwise
*/
OFBool less(const char *c) const
{
return (keyword_ < c);
}
/** return pointer to next object in tree on same level
* @return pointer to next object, NULL if empty
*/
OFConfigFileNode *getBrother() const
{
return brother_;
}
/** return pointer to next object in tree on lower level
* @return pointer to lower object, NULL if empty
*/
OFConfigFileNode *getSon() const
{
return son_;
}
/** set pointer to next object in tree on same level
* @param brother pointer to next object in tree
*/
void setBrother(OFConfigFileNode *brother)
{
brother_ = brother;
}
/** set pointer to next object in tree on lower level
* @param son pointer to next object in tree
*/
void setSon(OFConfigFileNode *son)
{
son_ = son;
}
/** print the content of this node to an output stream
* @param out output stream to print to
* @param level tree depth (level)
*/
void print(STD_NAMESPACE ostream& out, unsigned int level);
private:
/// private undefined copy constructor
OFConfigFileNode(const OFConfigFileNode& arg);
/// private undefined copy assignment operator
OFConfigFileNode &operator=(const OFConfigFileNode& arg);
/// pointer to next object in tree on same level
OFConfigFileNode *brother_;
/// pointer to next object in tree on lower level
OFConfigFileNode *son_;
/// configuration keyword
OFString keyword_;
/// configuration value
OFString value_;
};
/// pointer to a OFConfigFileNode object
typedef OFConfigFileNode *OFConfigFileNodePtr;
/** structure used by class OFConfigFile to store a cursor pointing
* to the currently selected section and entry in the config data
*/
class DCMTK_OFSTD_EXPORT OFConfigFileCursor
{
public:
/** default constructor
*/
OFConfigFileCursor(unsigned int maxLevel)
: array_(NULL)
, maxLevel_(maxLevel)
{
clear();
}
/** copy constructor
*/
OFConfigFileCursor(const OFConfigFileCursor& source);
/** destructor
*/
~OFConfigFileCursor()
{
delete[] array_;
}
/** assignment operator
*/
OFConfigFileCursor& operator=(const OFConfigFileCursor& source);
/// return object to default constructed state (invalid cursor)
void clear();
/** return keyword as C string.
* Precondition is that section_valid(level) return true.
* @param level cursor level
*/
const char *getKeyword(unsigned int level) const
{
if ((level <= maxLevel_) && array_ && array_[level]) return array_[level]->getKeyword(); else return NULL;
}
/** return value as C string
* Precondition is that section_valid(level) return true.
* @param level cursor level
*/
const char *getValue(unsigned int level) const
{
if ((level <= maxLevel_) && array_ && array_[level]) return array_[level]->getValue(); else return NULL;
}
/** checks if the cursor points to a valid location up to
* the given level
* @param level cursor level
* @return true if valid, false otherwise
*/
OFBool section_valid(unsigned int level) const;
/** sets cursor to the entry with keyword "key" at the given level.
* Cursor must be valid at the level higher than the one specified.
* If the keyword exists more than once, the first occurance is found.
* If the keyword does not exist, the cursor becomes invalid at the
* specified level. The cursor always becomes invalid at all levels
* lower than specified.
* @param level cursor level
* @param key key value
* @param anchor pointer to anchor node in config tree
*/
void set_section(
unsigned int level,
const char *key,
OFConfigFileNode *anchor);
/** sets cursor to the first entry at the given level (without
* changing the cursor position at higher levels).
* Cursor must be valid at the level higher than the one specified.
* If no section is found the cursor becomes invalid at the
* specified level. The cursor always becomes invalid at all levels
* lower than specified.
* @param level cursor level
* @param anchor pointer to anchor node in config tree
*/
void first_section(
unsigned int level,
OFConfigFileNode *anchor);
/** sets cursor to the next entry at the given level (without
* changing the cursor position at higher levels).
* Cursor must be valid at the level specified.
* If no section is found the cursor becomes invalid at the
* specified level. The cursor always becomes invalid at all levels
* lower than specified.
* @param level cursor level
*/
void next_section(unsigned int level);
/** inserts a new node into the tree at the current cursor position
* @param level level of insertion
* @param newnode node to be inserted, must not be NULL
* @param anchor pointer to anchor node of tree, may be modified
* @param orderedMode mode flag for processing configuration files.
* See documentation of OFConfigFile::orderedMode_
*/
void insert(
unsigned int level,
OFConfigFileNode *& newnode,
OFConfigFileNode *& anchor,
OFBool orderedMode);
/** dummy comparison operator, needed by MSVC5 with STL.
* @return always false
*/
OFBool operator<(const OFConfigFileCursor& /* arg */) const
{
return OFFalse;
}
/** dummy comparison operator, needed by MSVC5 with STL.
* @return always true
*/
OFBool operator==(const OFConfigFileCursor& /* arg */) const
{
return OFTrue;
}
private:
/** helper method that is called by insert() in ordered mode
* to insert a new node at a given tree level (i.e. within a list
* of nodes that share the same parent node) in alphabetical order,
* replacing any older node with identical keyword.
* @param parent parent node of new new to be inserted
* @param newnode pointer to new node to be inserted
*/
void orderedInsert(
OFConfigFileNode *parent,
OFConfigFileNode *&newnode);
/// the cursor is an array of pointers to OFConfigFileNode objects
OFConfigFileNodePtr *array_;
/// depth of tree, i.e. number of entries in array_
unsigned int maxLevel_;
};
/** class for reading and evaluating configuration files.
* An object of this class reads upon construction a text
* config file and offers methods allowing to browse the
* configuration data
*/
class DCMTK_OFSTD_EXPORT OFConfigFile
{
public:
/** constructor.
* @param infile file from which the configuration data is to be read.
* @param maxLevel depth of the tree maintained in this config file, default 2
* @param commentChar character to start comment lines, default '#'
* @param orderedMode mode flag for processing configuration files.
* See documentation of member variable orderedMode_
*/
OFConfigFile(
FILE *infile,
unsigned int maxLevel = OFConfigFile_MaxLevel,
char commentChar = OFConfigFile_CommentChar,
OFBool orderedMode = OFFalse);
/** destructor
*/
virtual ~OFConfigFile();
/** load configuration file
* @param infile configuration file, must already be open for reading.
*/
void loadFile(FILE *infile);
/** gets the name of the keyword at the specified level
* in the cursor path. Cursor must be valid at the specified level.
* @param level cursor level
* @return keyword if valid, NULL otherwise.
*/
const char *get_keyword(unsigned int level);
/** gets the value for the current entry (level 0 keyword).
* Cursor must point to a valid entry (i.e. be valid at level 0)
* @return value if valid, NULL otherwise.
*/
const char *get_value();
/** gets the value for the current entry and interprets it as
* a boolean value. The keywords "yes", "no", "on", "off", "1", "0",
* "true" and false" are recognised in upper, lower and mixed case.
* If the value is different from any recognised keyword, the specified
* default is returned
* Cursor must point to a valid entry (i.e. be valid at level 0)
* @param defaultvalue default to be returned if no keyword is recognised
* of if the cursor is invalid.
* @return boolean value.
*/
OFBool get_bool_value(OFBool defaultvalue);
/** checks if the cursor points to a valid entry in the
* config data tree up to the the specified level.
* @param level tree level (0 for leaf)
* @return OFTrue if valid at the specified level.
*/
OFBool section_valid(unsigned int level) const
{
return cursor_.section_valid(level);
}
/** sets cursor to the entry with keyword "key" at the given level.
* Cursor must be valid at the level higher than the one specified.
* If the keyword exists more than once, the first occurance is found.
* If the keyword does not exist, the cursor becomes invalid at the
* specified level. The cursor always becomes invalid at all levels
* lower than specified.
* @param level cursor level
* @param key key value
*/
void set_section(unsigned int level, const char *key)
{
cursor_.set_section(level, key, anchor_);
}
/** sets cursor to the first entry at the given level (without
* changing the cursor position at higher levels).
* Cursor must be valid at the level higher than the one specified.
* If no section is found the cursor becomes invalid at the
* specified level. The cursor always becomes invalid at all levels
* lower than specified.
* @param level cursor level
*/
void first_section(unsigned int level)
{
cursor_.first_section(level, anchor_);
}
/** sets cursor to the next entry at the given level (without
* changing the cursor position at higher levels).
* Cursor must be valid at the level specified.
* If no section is found the cursor becomes invalid at the
* specified level. The cursor always becomes invalid at all levels
* lower than specified.
* @param level cursor level
*/
void next_section(unsigned int level)
{
cursor_.next_section(level);
}
/** puts the current cursor position on a cursor stack.
*/
void save_cursor();
/** restores a previously stored cursor position from the cursor stack.
*/
void restore_cursor();
/** sets the cursor to a different section. This "shortcut" method allows
* to specify multiple section levels at the same time.
* The cursor becomes invalid when the section is not found or if parameters
* for more level then present in the tree are specified.
* @param key1 level 1 section key, i.e. [KEY]
* @param key2 level 2 section key, i.e. [[KEY]]. If omitted, section 2 remains unchanged.
* @param key2 level 3 section key, i.e. [[[KEY]]]. If omitted, section 3 remains unchanged.
*/
void select_section(
const char *key1,
const char *key2=NULL,
const char *key3=NULL);
/** sets the cursor to the given level 0 keyword and returns
* the string value assigned to this keyword.
* @param key0 level 0 keyword
* @return value string if found, NULL otherwise
*/
const char *get_entry(const char *key0);
/** print the content of the configuration to an output stream
* @param out output stream to print to
*/
void print(STD_NAMESPACE ostream& out);
private:
/** reads the next character from the input file,
* maintains the current line number and filters out
* comments.
* @param infile the file to be read
* @return next character
*/
char read_char(FILE *infile);
/** reads the next non-whitespace character from
* the input file and returns as uppercase character.
* @param infile the file to be read
* @return next non-whitespace character
*/
char read_keywordchar(FILE *infile);
/** reads a complete entry from the config file.
* An entry can either be a section heading or
* an entry of the form key=value. The entry is inserted
* into the config data tree managed by this object.
* @param infile the file to be read
*/
void read_entry(FILE *infile);
/** writes a character to the string buffer maintained in
* "buffer". Automatically resizes buffer if necessary.
* @param c character to be stored
*/
void store_char(char c);
/** private undefined copy constructor
*/
OFConfigFile(const OFConfigFile&);
/** private undefined assignment operator
*/
OFConfigFile& operator=(const OFConfigFile&);
/// stack of cursor positions that can be saved and restored
OFStack<OFConfigFileCursor> stack_;
/// current cursor position
OFConfigFileCursor cursor_;
/// anchor to data tree
OFConfigFileNode *anchor_;
/// flag indicating whether newline during file read
int isnewline_;
/// flag indicating whether CR was read during file read
int crfound_;
/// buffer during file read
char *buffer_;
/// index into buffer during file read
size_t bufptr_;
/// buffer size during file read
long bufsize_;
/// depth of tree, i.e. number of entries in array_
unsigned int maxLevel_;
/// character starting comment lines
char commentChar_;
/** mode flag for reading configuration file. If false, new entries to the
* tree containing the configuration file are just appended and not sorted.
* This allows multiple entries with the same keyword to be present, only the
* first of which will be found by search-by-keyword methods such as set_section,
* select_section or get_entry. In ordered mode, the tree is maintained in sorted
* order and a new entry will replace an older entry with identical keyword.
* This permits multiple configuration files to "overlay" each other but is
* somewhat slower when reading the configuration file.
*/
OFBool orderedMode_;
};
#endif