Source: misc.h


Annotated List
Files
Globals
Hierarchy
Index
// Copyright (C) 1999-2001 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_CONFIG_H_
#include 
#endif

#ifndef __CCXX_THREAD_H__
#include 
#endif

#include 
#include 

#define	KEYDATA_INDEX_SIZE	97
#define	KEYDATA_PAGER_SIZE	512
#define KEYDATA_PATH_SIZE	256

#ifdef	CCXX_NAMESPACES
namespace ost {
#endif

#if defined(__GNUC__) || !defined(__hpux)
#pragma pack(1)
#endif

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;

#if defined(__GNUC__) || !defined(__hpux)
#pragma pack()
#endif

#ifdef WIN32
class CCXX_CLASS_EXPORT MemPager;
class CCXX_CLASS_EXPORT SharedMemPager;
#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.
 * 
 * There are a number of odd and specialized utility classes found in Common
 * C++.  The most common of these is the "MemPager" class.  This is basically
 * a class to enable page-grouped "cumulative" memory allocation; all
 * accumulated allocations are dropped during the destructor.  This class has
 * found it's way in a lot of other utility classes in Common C++.
 *
 * @author David Sugar 
 * @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 
 * @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(size_t size);

	/**
	 * Get the last memory page after locking.
	 *
	 * @return allocated memory space.
	 * @param size of request.
	 */
	void* alloc(size_t size);
};

/**
 * Keydata objects are used to load and hold "configuration" data for
 * a given application.
 *
 * This class is used to load and then hold "keyword = value" pairs parsed from a text
 * based "config" file that has been divided into "[sections]". The syntax is: 
 *
 * 
 * [section_name]
 * key1=value1
 * key2=value2
* * Essentially, the "path" is a "keypath" into a theoretical namespace of key * pairs, hence one does not use "real" filepaths that may be OS dependent. The "/" path refers * to "/etc" prefixed (on UNIX) directories and this is processed within the constructor. It * could refer to the /config prefix on QNX, or even, gasp, a "C:\WINDOWS". Hence, a keypath of * "/bayonne.d/vmhost/smtp" actually resolves to a "/etc/bayonne.d/vmhost.conf" and loads key * value pairs from the [smtp] section of that .conf file. * * Similarly, something like "~bayonne/smtp" path refers to a "~/.bayonnerc" and loads key pairs * from the [smtp] section. This coercion occurs before the name is passed to the open call. * * I actually use derived keydata based classes as global initialized objects, and they hence * automatically load and parse config file entries even before "main" has started. * * 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. * * Keydata can * also load a table of "initialization" values for keyword pairs that were * not found in the external file. * * One typically derives an application specific keydata class to load a * specific portion of a known config file and initialize it's values. One * can then declare a global instance of these objects and have * configuration data initialized automatically as the executable is loaded. * * Hence, if I have a "[paths]" section in a "/etc/server.conf?" file, I might * define something like: * *
 * class KeyPaths : public Keydata
 * {
 *   public:
 *     KeyPaths() : Keydata("/server/paths")
 *     {
 *       static KEYDEF *defvalues = {
 * 	  {"datafiles", "/var/server"},
 * 	  {NULL, NULL}};
 * 
 *       // override with [paths] from "~/.serverrc" if avail.
 * 
 *       Load("~server/paths");
 *       Load(defvalues);
 *     }
 * };
 * 
 * KeyPaths keypaths;
 * 
* * @author David Sugar * @short load text configuration files into keyword pairs. */ class Keydata : protected MemPager { private: static std::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: CCXX_MEMBER_EXPORT(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) */ CCXX_MEMBER_EXPORT(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. */ CCXX_MEMBER_EXPORT(void) Load(KEYDEF *pairs); public: /** * Create an empty key data object. */ CCXX_MEMBER_EXPORT(CCXX_EMPTY) Keydata(); /** * Create a new key data object and use "Load" method to load an * initial config file section into it. * * @param keypath (filepath/section) */ CCXX_MEMBER_EXPORT(CCXX_EMPTY) 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. */ CCXX_MEMBER_EXPORT(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(). */ CCXX_MEMBER_EXPORT(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. */ CCXX_MEMBER_EXPORT(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. */ CCXX_MEMBER_EXPORT(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. */ CCXX_MEMBER_EXPORT(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. */ CCXX_MEMBER_EXPORT(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. */ CCXX_MEMBER_EXPORT(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. */ CCXX_MEMBER_EXPORT(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. */ CCXX_MEMBER_EXPORT(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 CCXX_EXPORT(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: *
 *  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;
 *  }
 *  
* * @author Henner Zeller * @license LGPL */ class CCXX_CLASS_EXPORT 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 CCXX_CLASS_EXPORT iterator { friend class 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++ virtual ~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 class StringTokenizer::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_NAMESPACES }; #endif #endif /** EMACS ** * Local variables: * mode: c++ * c-basic-offset: 8 * End: */

Generated by: dyfet on home on Wed Dec 5 07:05:45 2001, using kdoc 2.0a53.