|
|
// Copyright (C) 1999-2000 Open Source Telecom Corporation. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception to the GNU General Public License, permission is // granted for additional uses of the text contained in its release // of Common C++. // // The exception is that, if you link the Common C++ library with other // files to produce an executable, this does not by itself cause the // resulting executable to be covered by the GNU General Public License. // Your use of that executable is in no way restricted on account of // linking the Common C++ library code into it. // // This exception does not however invalidate any other reasons why // the executable file might be covered by the GNU General Public License. // // This exception applies only to the code released under the // name Common C++. If you copy code from other releases into a copy of // Common C++, as the General Public License permits, the exception does // not apply to the code that you add in this way. To avoid misleading // anyone as to the status of such modified files, you must delete // this exception notice from them. // // If you write modifications of your own for Common C++, it is your choice // whether to permit this exception to apply to your modifications. // If you do not wish that, delete this exception notice. #ifndef __CCXX_MISC_H__ #define __CCXX_MISC_H__ #ifndef __CCXX_THREAD_H__ #include <cc++/thread.h> #else #ifdef __CCXX_NAMESPACE_H__ #include <cc++/macros.h> #endif #endif #include <fstream.h> #define KEYDATA_INDEX_SIZE 97 #define KEYDATA_PAGER_SIZE 512 #define KEYDATA_PATH_SIZE 256 #pragma pack(1) typedef struct _keyval { struct _keyval *next; char val[1]; } keyval_t; typedef struct _keysym { struct _keysym *next; struct _keyval *data; const char **list; short count; char sym[1]; } keysym_t; typedef struct { char *keyword; char *value; } KEYDEF; #pragma pack() #ifdef __WIN32__ class __EXPORT MemPager; class __EXPORT SharedMemPager; class __EXPORT Keydata; #endif /** * The memory pager is used to allocate cumulative memory pages for * storing object specific "persistant" data that is presumed to persist * during the life of a given derived object. When the object is * destroyed, all accumulated data is automatically purged. * * @author David Sugar <dyfet@ostel.com> * @short Accumulative object memory allocator. */ class MemPager { private: unsigned int pagesize; unsigned int pages; struct _page { struct _page *next; int used; } *page; protected: /** * Allocate first workspace from paged memory. This method * scans all currently allocated blocks for available space * before adding new pages and hence is both slower and more * efficient. * * @param size of memory to allocate. * @return pointer to allocated memory. */ virtual void *first(size_t size); /** * Allocate memory from either the currently active page, or * allocate a new page for the object. * * @param size of memory to allocate. * @return pointer to allocated memory. */ virtual void *alloc(size_t size); /** * Allocate a string from the memory pager pool and copy the * string into it's new memory area. This method allocates * memory by first searching for an available page, and then * allocating a new page if no space is found. * * @param str to allocate and copy into paged memory pool. * @return copy of string from allocated memory. */ char *first(char *str); /** * Allocate a string from the memory pager pool and copy the * string inti it's new memory area. This checks only the * last active page for available space before allocating a * new page. * * @param str to allocate and copy into paged memory pool. * @return copy of string from allocated memory. */ char *alloc(char *str); /** * Create a paged memory pool for cumulative storage. This * pool allocates memory in fixed "pagesize" chunks. Ideal * performance is achived when the pool size matches the * system page size. This pool can only exist in derived * objects. * * @param pagesize to allocate chunks. */ MemPager(int pagesize = 4096); /** * purge the current memory pool. */ void purge(void); /** * Delete the memory pool and all allocated memory. */ virtual ~MemPager(); public: /** * Return the total number of pages that have been allocated * for this memory pool. * * @return number of pages allocated. */ inline int getPages(void) {return pages;}; }; /** * The shared mempager uses a mutex to protect key access methods. * This class is used when a mempager will be shared by multiple * threads. * * @author David Sugar <dyfet@ostel.com> * @short mutex protected memory pager. */ class SharedMemPager : public MemPager, public Mutex { protected: /** * Create a mempager mutex pool. * * @param pagesize for allocation. */ SharedMemPager(int pg = 4096); /** * Purge the memory pool while locked. */ void purge(void); /** * Get the first memory page after locking. * * @return allocated memory space. * @param size of request. */ void *first(int size); /** * Get the last memory page after locking. * * @return allocated memory space. * @param size of request. */ void *alloc(int size); }; /** * Keydata objects are used to load and hold "configuration" data for * a given application. Each "keydata" object holds the key pairs from * a [section] of a text readable config file. The /etc directory is * presumed to hold the referenced file key set unless a ~ is used. * * Keydata can hold multiple values for the same key pair. This can * occur either from storing a "list" of data items in a config file, * or when overlaying multiple config sources (such as /etc/....conf and * ~/.confrc segments) into a single object. The keys are stored as * cumulative (read-only/replacable) config values under a hash index * system for quick retrieval. * * @author David Sugar <dyfet@ostel.com> * @short load text configuration files into keyword pairs. */ class Keydata : protected MemPager { private: static ifstream cfgFile; static char lastpath[KEYDATA_PATH_SIZE + 1]; static int count, sequence; int link; keysym_t *keys[KEYDATA_INDEX_SIZE]; /** * Compute a hash key signature id for a symbol name. * * @return key signature index path. * @param symbol name. */ unsigned getIndex(const char *sym); protected: keysym_t *getSymbol(const char *sym, bool create); /** * Load additional key values into the currrent object from * the specfied config source (a config file/section pair). * These values will overlay the current keywords when matches * are found. This can be used typically in a derived config * object class constructor to first load a /etc section, and * then load a matching user specific entry from ~/. to override * default system values with user specific keyword values. * * @param keypath (filepath/section) */ void Load(const char *keypath, const char *environment = "CONFIG_KEYDATA"); /** * Load default keywords into the current object. This only * loads keyword entries which have not already been defined * to reduce memory usage. This form of Load is also commonly * used in the constructor of a derived Keydata class. * * @param list of NULL terminated default keyword/value pairs. */ void Load(KEYDEF *pairs); public: /** * Create an empty key data object. */ Keydata(); /** * Create a new key data object and use "Load" method to load an * initial config file section into it. * * @param keypath (filepath/section) */ Keydata(const char *keypath, const char *environment="CONFIG_KEYDATA"); /** * Destroy the keydata object and all allocated memory. This * may also clear the "cache" file stream if no other keydata * objects currently reference it. */ virtual ~Keydata(); /** * Unlink the keydata object from the cache file stream. This * should be used if you plan to keepa Keydata object after it * is loaded once all keydata objects have been loaded, otherwise * the cfgFile stream will remain open. You can also use * endKeydata(). */ void Unlink(void); /** * Get a count of the number of data "values" that is associated * with a specific keyword. Each value is from an accumulation of * "load()" requests. * * @param keyword symbol name. * @return count of values associated with keyword. */ int getCount(const char *sym); /** * Get the first data value for a given keyword. This will * typically be the /etc set global default. * * @param keyword symbol name. * @return first set value for this symbol. */ const char *getFirst(const char *sym); /** * Get the last (most recently set) value for a given keyword. * This is typically the value actually used. * * @param keywork symbol name. * @return last set value for this symbol. */ const char *getLast(const char *sym); /** * Get an index array of ALL keywords that are stored by the * current keydata object. * * @return number of keywords found. * @param data pointer of array to hold keyword strings. * @param max number of entries the array can hold. */ int getIndex(char **data, int max); /** * Set (replace) the value of a given keyword. This new value * will become the value returned from getLast(), while the * prior value will still be stored and found from getList(). * * @param keyword name to set. * @param data string to store for the keyword. */ void setValue(const char *sym, const char *data); /** * Return a list of all values set for the given keyword * returned in order. * * @return list pointer of array holding all keyword values. * @param keyword name to fetch. */ const char * const *getList(const char *sym); /** * Clear all values associated with a given keyword. This does * not de-allocate the keyword from memory, however. * * @return keyword name to clear. */ void clrValue(const char *sym); /** * A convient notation for accessing the keydata as an associative * array of keyword/value pairs through the [] operator. */ inline const char *operator[](const char *keyword) {return getLast(keyword);}; /** * Shutdown the file stream cache. This should be used before * detaching a deamon, exec(), fork(), etc. */ friend void endKeydata(void); }; /** * Splits delimited string into tokens. * * The StringTokenizer takes a pointer to a string and a pointer * to a string containing a number of possible delimiters. * The StringTokenizer provides an input forward iterator which allows * to iterate through all tokens. An iterator behaves like a logical * pointer to the tokens, i.e. to shift to the next token, you've * to increment the iterator, you get the token by dereferencing the * iterator. * * Memory consumption: * This class operates on the original string and only allocates memory * for the individual tokens actually requested, so this class * allocates at maximum the space required for the longest token in the * given string. * Since for each iteration, memory is reclaimed for the last token, * you MAY NOT store pointers to them; if you need them afterwards, * copy them. You may not modify the original string while you operate * on it with the StringTokenizer; the behaviour is undefined in that * case. * * The iterator has one special method 'nextDelimiter()' which returns * a character containing the next delimiter following this * tokenization process or '\0', if there are no following delimiters. In * case of skipAllDelim, it returns the FIRST delimiter. * * With the method 'setDelimiters(const char*)' you may change the * set of delimiters. It affects all running iterators. * * Example: * <pre> * StringTokenizer st("mary had a little lamb;its fleece was..", " ;"); * StringTokenizer::iterator i; * for (i = st.begin() ; i != st.end() ; ++i) { * cout << "Token: '" << *i << "'\t"; * cout << " next Delim: '" << i.nextDelimiter() << "'" << endl; * } * </pre> * * @author Henner Zeller <foobar@to.com> * @license LGPL */ class StringTokenizer { public: /** * a delimiter string containing all usual whitespace delimiters. * These are space, tab, newline, carriage return, * formfeed and vertical tab. (see isspace() manpage). */ static const char * const SPACE; /** * Exception thrown, if someone tried to read beyond the * end of the tokens. * Will not happen if you use it the 'clean' way with comparison * against end(), but if you skip some tokens, because you 'know' * they are there. Simplifies error handling a lot, since you can * just read your tokens the way you expect it, and if there is some * error in the input this Exception will be thrown. */ // maybe move more global ? class NoSuchElementException { }; /** * The input forward iterator for tokens. * @author Henner Zeller */ class iterator { friend StringTokenizer; // access our private constructors private: const StringTokenizer *myTok; // my StringTokenizer const char *start; // start of current token const char *tokEnd; // end of current token (->nxDelimiter) const char *endp; // one before next token char *token; // allocated token, if requested // for initialization of the itEnd iterator iterator(const StringTokenizer &tok, const char *end) : myTok(&tok),tokEnd(0),endp(end),token(0) {} iterator(const StringTokenizer &tok) : myTok(&tok),tokEnd(0),endp(myTok->str-1),token(0) { ++(*this); // init first token. } public: iterator() : myTok(0),start(0),tokEnd(0),endp(0),token(0) {} // see also: comment in implementation of operator++ ~iterator() { if (token) *token='\0'; delete token; } /** * copy constructor. */ // everything, but not responsible for the allocated token. iterator(const iterator& i) : myTok(i.myTok),start(i.start),tokEnd(i.tokEnd), endp(i.endp),token(0) {} /** * assignment operator. */ // everything, but not responsible for the allocated token. iterator &operator = (const iterator &i) { myTok = i.myTok; start = i.start; endp = i.endp; tokEnd = i.tokEnd; token = 0; return *this; } /** * shifts this iterator to the next token in the string. */ iterator &operator ++ () THROWS (NoSuchElementException); /** * returns the immutable string this iterator * points to or '0' if no token is available (i.e. * i == end()). * Do not store pointers to this token, since it is * invalidated for each iteration. If you need the token, * copy it (e.g. with strdup()); */ const char* operator * () THROWS (NoSuchElementException); /** * returns the next delimiter after the current token or * '\0', if there are no following delimiters. * It returns the very next delimiter (even if * skipAllDelim=true). */ inline char nextDelimiter() const { return (tokEnd) ? *tokEnd : '\0'; } /** * compares to other iterator. Usually used to * compare against the end() iterator. */ // only compare the end-position. speed. inline bool operator == (const iterator &other) const { return (endp == other.endp); } /** * compares to other iterator. Usually used to * compare against the end() iterator. */ // only compare the end position. speed. inline bool operator != (const iterator &other) const { return (endp != other.endp); } }; private: friend iterator; const char *str; const char *delim; bool skipAll, trim; iterator itEnd; public: /** * creates a new StringTokenizer for a string * and a given set of delimiters. * * @param str String to be split up. This string will * not be modified by this StringTokenizer, * but you may as well not modfiy this string * while tokenizing is in process, which may * lead to undefined behaviour. * * @param delim String containing the characters * which should be regarded as delimiters. * * @param skipAllDelim OPTIONAL. * true, if subsequent * delimiters should be skipped at once * or false, if empty tokens should * be returned for two delimiters with * no other text inbetween. The first * behaviour may be desirable for whitespace * skipping, the second for input with * delimited entry e.g. /etc/passwd like files * or CSV input. * NOTE, that 'true' here resembles the * ANSI-C strtok(char *s,char *d) behaviour. * DEFAULT = false * * @param trim OPTIONAL. * true, if the tokens returned * should be trimmed, so that they don't have * any whitespaces at the beginning or end. * Whitespaces are any of the characters * defined in StringTokenizer::SPACE. * If delim itself is StringTokenizer::SPACE, * this will result in a behaviour with * skipAllDelim = true. * DEFAULT = false */ StringTokenizer (const char *str, const char *delim, bool skipAllDelim = false, bool trim = false); /** * create a new StringTokenizer which splits the input * string at whitespaces. The tokens are stripped from * whitespaces. This means, if you change the set of * delimiters in either the 'begin(const char *delim)' method * or in 'setDelimiters()', you then get whitespace * trimmed tokens, delimited by the new set. * Behaves like StringTokenizer(s, StringTokenizer::SPACE,false,true); */ StringTokenizer (const char *s); /** * returns the begin iterator */ iterator begin() const { return iterator(*this); } /** * changes the set of delimiters used in subsequent * iterations. */ void setDelimiters (const char *d) { delim = d; } /** * returns a begin iterator with an alternate set of * delimiters. */ iterator begin(const char *d) { delim = d; return iterator(*this); } /** * the iterator marking the end. */ const iterator& end() const { return itEnd; } }; #ifdef __CCXX_NAMESPACE_H__ #undef __CCXX_NAMESPACE_H__ #include <cc++/namespace.h> #endif #endif /** EMACS ** * Local variables: * mode: c++ * c-basic-offset: 8 * End: */
Generated by: dyfet@home.sys on Fri Aug 11 16:43:58 200. |