ucommon-6.4.4/0000775000175000017500000000000012557440653010220 500000000000000ucommon-6.4.4/cmake-abi.sh0000775000175000017500000000157112557017036012307 00000000000000#!/bin/sh # Copyright (C) 2013-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015 Cherokees of Idaho. # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ltver=`grep LT_VERSION= configure.ac | sed -e "s/^.*=//" | sed -e "s/\"//g"` release=`echo $ltver | sed -e "s/:.*//"` compat=`echo $ltver | sed -e "s/.*://"` abi=`echo $ltver | sed -e "s/^$release://" -e "s/:.*$//"` echo="echo" if test -x "/bin/echo" ; then echo="/bin/echo" elif test -x "/usr/bin/echo" ; then echo="/usr/bin/echo" fi $echo $release.$compat.$abi ucommon-6.4.4/PKGBUILD.in0000644000175000001440000000117612475206234011662 00000000000000# $Id: PKGBUILD 186288 2013-05-23 22:10:51Z eric $ # Maintainer: Sergej Pupykin pkgname=ucommon pkgver=@VERSION@ pkgrel=0 epoch=9 pkgdesc="A light-weight C++ library to facilitate using C++ design patterns" arch=('i686' 'x86_64') url="http://www.gnutelephony.org/index.php/GNU_uCommon_C++" license=('GPL3' 'LGPL3') depends=('openssl') options=('!libtool') source=("$pkgname-$pkgver.tar.gz") md5sums=('SKIP') build() { cd ${pkgname}-${pkgver} ./configure --prefix=/usr make } check() { cd ${pkgname}-${pkgver} make check } package() { cd ${pkgname}-${pkgver} make DESTDIR="${pkgdir}" install } ucommon-6.4.4/SUPPORT0000644000175000001440000000077112454506050011224 00000000000000uCommon has been accepted as part of the GNU Project for use as GNU Common C++ 2 "2.0" and is used in GNU Telephony. Web resources: http://www.gnu.org/software/commoncpp/ http://www.gnutelephony.org http://savannah.gnu.org/projects/gnucomm Mailing lists and email contacts: mailto:devel@gnutelephony.org mailto:bugs@gnutelephony.org mailto:bug-commoncpp@gnu.org http://lists.gnu.org/mailman/listinfo/bug-commoncpp Other contacts jabber:dyfet@gnutelephony.org irc:gnutelephony@freenode.net ucommon-6.4.4/ucommon-config.h.cmake0000664000175000017500000000703612540014023014272 00000000000000/* Copyright (C) 2009-2014 David Sugar, Tycho Softworks. Copyright (C) 2015 Cherokees of Idaho. This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without modifications, as long as this notice is preserved. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, to the extent permitted by law; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #define STDC_HEADERS 1 #cmakedefine PACKAGE ${PROJECT_NAME} #cmakedefine VERSION "${VERSION}" #cmakedefine HAVE_CLOCK_NANOSLEEP 1 #cmakedefine HAVE_DIRENT_H 1 #cmakedefine HAVE_DLFCN_H 1 #cmakedefine HAVE_ENDIAN_H 1 #cmakedefine HAVE_INTTYPES_H 1 #cmakedefine HAVE_LINUX_VERSION_H 1 #cmakedefine HAVE_STDINT_H 1 #cmakedefine HAVE_STDLIB_H 1 #cmakedefine HAVE_SYS_FILIO_H 1 #cmakedefine HAVE_SYS_MMAN_H 1 #cmakedefine HAVE_SYS_POLL_H 1 #cmakedefine HAVE_SYS_RESOURCE_H 1 #cmakedefine HAVE_SYS_SHM_H 1 #cmakedefine HAVE_SYS_STAT_H 1 #cmakedefine HAVE_SYS_TIMEB_H 1 #cmakedefine HAVE_SYS_TYPES_H 1 #cmakedefine HAVE_SYS_WAIT_H 1 #cmakedefine HAVE_UNISTD_H 1 #cmakedefine HAVE_WCHAR_H 1 #cmakedefine HAVE_REGEX_H 1 #cmakedefine HAVE_SYS_INOTIFY_H 1 #cmakedefine HAVE_SYS_EVENT_H 1 #cmakedefine HAVE_SYSLOG_H 1 #cmakedefine HAVE_LIBINTL_H 1 #cmakedefine HAVE_NETINET_IN_H 1 #cmakedefine HAVE_NET_IF_H 1 #cmakedefine HAVE_SYS_PARAM_H 1 #cmakedefine HAVE_SYS_FILE_H 1 #cmakedefine HAVE_SYS_LOCKF_H 1 #cmakedefine HAVE_REGEX_H 1 #cmakedefine HAVE_FTOK 1 #cmakedefine HAVE_GETADDRINFO 1 #cmakedefine HAVE_GETHOSTBYNAME2 1 #cmakedefine HAVE_INET_NTOP 1 #cmakedefine HAVE_GMTIME_R 1 #cmakedefine HAVE_LOCALTIME_R 1 #cmakedefine HAVE_STRERROR_R 1 #cmakedefine HAVE_MACH_CLOCK_H 1 #cmakedefine HAVE_MACH_O_DYLD_H 1} // namespace #cmakedefine HAVE_MEMORY_H 1 #cmakedefine HAVE_NANOSLEEP 1 #cmakedefine HAVE_POLL_H 1 #cmakedefine HAVE_CLOCK_GETTIME 1 #cmakedefine HAVE_POSIX_FADVISE 1 #cmakedefine HAVE_POSIX_MEMALIGN 1 #cmakedefine HAVE_ALIGNED_ALLOC 1 #cmakedefine HAVE_PTHREAD_CONDATTR_SETCLOCK 1 #cmakedefine HAVE_PTHREAD_DELAY 1 #cmakedefine HAVE_PTHREAD_DELAY_NP 1 #cmakedefine HAVE_PTHREAD_SETCONCURRENCY 1 #cmakedefine HAVE_PTHREAD_SETSCHEDPRIO 1 #cmakedefine HAVE_PTHREAD_YIELD 1 #cmakedefine HAVE_PTHREAD_YIELD_NP 1 #cmakedefine HAVE_SHL_LOAD 1 #cmakedefine HAVE_SHM_OPEN 1 #cmakedefine HAVE_SOCKETPAIR 1 #define HAVE_STDEXCEPT 1 /* cannot seem to test in cmake... */ #cmakedefine HAVE_STRLCPY 1 #cmakedefine HAVE_STRICMP 1 #cmakedefine HAVE_STRCOLL 1 #cmakedefine HAVE_STRINGS_H 1 #cmakedefine HAVE_STRISTR 1 #cmakedefine HAVE_SYSCONF 1 #cmakedefine HAVE_FTRUNCATE 1 #cmakedefine HAVE_PWRITE 1 #cmakedefine HAVE_SETPGRP 1 #cmakedefine HAVE_SETLOCALE 1 #cmakedefine HAVE_GETTEXT 1 #cmakedefine HAVE_EXECVP 1 #cmakedefine HAVE_ATEXIT 1 #cmakedefine HAVE_LSTAT 1 #cmakedefine HAVE_REALPATH 1 #cmakedefine HAVE_SYMLINK 1 #cmakedefine HAVE_READLINK 1 #cmakedefine HAVE_WAITPID 1 #cmakedefine HAVE_WAIT4 1 #cmakedefine HAVE_SETGROUPS 1 #cmakedefine HAVE_FCNTL_H 1 #cmakedefine HAVE_TERMIOS_H 1 #cmakedefine HAVE_TERMIO_H 1 #cmakedefine HAVE_OPENSSL_FIPS_H 1 #cmakedefine HAVE_STDATOMIC_H 1 #cmakedefine HAVE_STDALIGN_H 1 #cmakedefine POSIX_TIMERS 1 #cmakedefine HAVE_ATOMICS 1 #define UCOMMON_LOCALE "${CMAKE_INSTALL_FULL_LOCALEDIR}" #define UCOMMON_CFGPATH "${CMAKE_INSTALL_FULL_SYSCONFDIR}" #define UCOMMON_VARPATH "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}" #define UCOMMON_PREFIX "${CMAKE_INSTALL_PREFIX}" #ifdef GCC_ATOMICS #define HAVE_GCC_ATOMICS #endif #include ucommon-6.4.4/inc/0000775000175000017500000000000012557440653010771 500000000000000ucommon-6.4.4/inc/ucommon/0000775000175000017500000000000012557440653012446 500000000000000ucommon-6.4.4/inc/ucommon/persist.h0000664000175000017500000004213312504226647014230 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * The GNU Common C++ persistance engine by Daniel Silverstone. * @file ucommon/persist.h */ #ifndef UCOMMON_SYSRUNTIME #if !defined(_MSC_VER) || _MSC_VER >= 1400 #ifndef _UCOMMON_PERSIST_H_ #define _UCOMMON_PERSIST_H_ #ifndef _UCOMMON_PLATFORM_H_ #include #endif #include #include #include #include #include namespace ucommon { // This typedef allows us to declare NewPersistObjectFunction now typedef class PersistObject* (*NewPersistObjectFunction) (void); class __EXPORT PersistException { public: PersistException(const std::string& reason); const std::string& getString() const; virtual ~PersistException() throw(); protected: std::string _what; }; /** * Type manager for persistence engine. * This class manages the types for generation of the persistent objects. * Its data structures are managed automatically by the system. They are * implicitly filled by the constructors who declare classes to the system. * * @author Daniel Silverstone */ class __EXPORT TypeManager { public: /** * This manages a registration to the typemanager - attempting to * remove problems with the optimizers */ class registration { public: registration(const char* name, NewPersistObjectFunction func); virtual ~registration(); private: std::string myName; }; /** * This adds a new construction function to the type manager */ static void add(const char* name, NewPersistObjectFunction construction); /** * And this one removes a type from the managers lists */ static void remove(const char* name); /** * This function creates a new object of the required type and * returns a pointer to it. NULL is returned if we couldn't find * the type */ static PersistObject* createInstanceOf(const char* name); typedef std::map StringFunctionMap; }; /* * The following defines are used to declare and define the relevant code * to allow a class to use the Persistence::Engine code. */ #define DECLARE_PERSISTENCE(ClassType) \ public: \ friend ucommon::PersistEngine& operator>>( ucommon::PersistEngine& ar, ClassType *&ob); \ friend ucommon::PersistEngine& operator<<( ucommon::PersistEngine& ar, ClassType const &ob); \ friend ucommon::PersistObject *createNew##ClassType(); \ virtual const char* getPersistenceID() const; \ static ucommon::TypeManager::Registration registrationFor##ClassType; #define IMPLEMENT_PERSISTENCE(ClassType, FullyQualifiedName) \ ucommon::PersistObject *createNew##ClassType() { return new ClassType; } \ const char* ClassType::getPersistenceID() const {return FullyQualifiedName;} \ ucommon::PersistEngine& operator>>(ucommon::PersistEngine& ar, ClassType &ob) \ { ar >> (ucommon::PersistObject &) ob; return ar; } \ ucommon::PersistEngine& operator>>(ucommon::PersistEngine& ar, ClassType *&ob) \ { ar >> (ucommon::PersistObject *&) ob; return ar; } \ ucommon::PersistEngine& operator<<(ucommon::PersistEngine& ar, ClassType const &ob) \ { ar << (ucommon::PersistObject const *)&ob; return ar; } \ ucommon::TypeManager::Registration \ ClassType::registrationFor##ClassType(FullyQualifiedName, \ createNew##ClassType); class PersistEngine; /** * PersistObject * * Base class for classes that will be persistent. This object is the base * for all Persistent data which is not natively serialized by the * persistence::engine * * It registers itself with the persistence::TypeManager * using a global constructor function. A matching deregister call * is made in a global destructor, to allow DLL's to use the * persistence::engine in a main executable. * * Persistable objects must never maintain bad pointers. If a pointer * doesn't point to something valid, it must be NULL. This is so * the persistence engine knows whether to allocate memory for an object * or whether the memory has been pre-allocated. * * @author Daniel Silverstone */ class __EXPORT PersistObject { public: /** * This constructor is used in serialization processes. * It is called in CreateNewInstance in order to create * an instance of the class to have Read() called on it. */ PersistObject(); /** * Default destructor */ virtual ~PersistObject(); /** * This returns the ID of the persistent object (Its type) */ virtual const char* getPersistenceID() const; /** * This method is used to write to the Persistence::Engine * It is not equivalent to the << operator as it writes only the data * and not the object type etc. */ virtual bool write(PersistEngine& archive) const; /** * This method is used to read from a Persistence::Engine * It is not equivalent to the >> operator as it does no * typesafety or anything. */ virtual bool read(PersistEngine& archive); }; /** * Stream serialization of persistent classes. * This class constructs on a standard C++ STL stream and then * operates in the mode specified. The stream passed into the * constructor must be a binary mode to function properly. * * @author Daniel Silverstone */ class __EXPORT PersistEngine { public: /** * These are the modes the Persistence::Engine can work in */ enum EngineMode { modeRead, modeWrite }; /** * Constructs a Persistence::Engine with the specified stream in * the given mode. The stream must be initialized properly prior * to this call or problems will ensue. */ PersistEngine(std::iostream& stream, EngineMode mode) throw(PersistException); virtual ~PersistEngine(); // Write operations /** * writes a PersistObject from a reference. */ inline void write(const PersistObject &object) throw(PersistException) {write(&object);} /** * writes a PersistObject from a pointer. */ void write(const PersistObject *object) throw(PersistException); // writes supported primitive types // shortcut, to make the following more readable #define CCXX_ENGINEWRITE_REF(valref) writeBinary((const uint8_t*)&valref,sizeof(valref)) inline void write(int8_t i) throw(PersistException) { CCXX_ENGINEWRITE_REF(i); } inline void write(uint8_t i) throw(PersistException) { CCXX_ENGINEWRITE_REF(i); } inline void write(int16_t i) throw(PersistException) { CCXX_ENGINEWRITE_REF(i); } inline void write(uint16_t i) throw(PersistException) { CCXX_ENGINEWRITE_REF(i); } inline void write(int32_t i) throw(PersistException) { CCXX_ENGINEWRITE_REF(i); } inline void write(uint32_t i) throw(PersistException) { CCXX_ENGINEWRITE_REF(i); } inline void write(float i) throw(PersistException) { CCXX_ENGINEWRITE_REF(i); } inline void write(double i) throw(PersistException) { CCXX_ENGINEWRITE_REF(i); } inline void write(bool i) throw(PersistException) { CCXX_ENGINEWRITE_REF(i); } #undef CCXX_ENGINEWRITE_REF void write(const std::string& str) throw(PersistException); // Every write operation boils down to one or more of these void writeBinary(const uint8_t* data, const uint32_t size) throw(PersistException); // Read Operations /** * reads a PersistObject into a reference overwriting the object. */ void read(PersistObject &object) throw(PersistException); /** * reads a PersistObject into a pointer allocating memory for the object if necessary. */ void read(PersistObject *&object) throw(PersistException); // reads supported primitive types // shortcut, to make the following more readable #define CCXX_ENGINEREAD_REF(valref) readBinary((uint8_t*)&valref,sizeof(valref)) inline void read(int8_t& i) throw(PersistException) { CCXX_ENGINEREAD_REF(i); } inline void read(uint8_t& i) throw(PersistException) { CCXX_ENGINEREAD_REF(i); } inline void read(int16_t& i) throw(PersistException) { CCXX_ENGINEREAD_REF(i); } inline void read(uint16_t& i) throw(PersistException) { CCXX_ENGINEREAD_REF(i); } inline void read(int32_t& i) throw(PersistException) { CCXX_ENGINEREAD_REF(i); } inline void read(uint32_t& i) throw(PersistException) { CCXX_ENGINEREAD_REF(i); } inline void read(float& i) throw(PersistException) { CCXX_ENGINEREAD_REF(i); } inline void read(double& i) throw(PersistException) { CCXX_ENGINEREAD_REF(i); } inline void read(bool &i) throw(PersistException) { CCXX_ENGINEREAD_REF(i); } #undef CCXX_ENGINEREAD_REF void read(std::string& str) throw(PersistException); // Every read operation boiled down to one or more of these void readBinary(uint8_t* data, uint32_t size) throw(PersistException); private: /** * reads the actual object data into a pre-instantiated object pointer * by calling the read function of the derived class. */ void readObject(PersistObject* object) throw(PersistException); /** * reads in a class name, and caches it into the ClassMap. */ const std::string readClass() throw(PersistException); /** * The underlying stream */ std::iostream& myUnderlyingStream; /** * The mode of the engine. read or write */ EngineMode myOperationalMode; /** * Typedefs for the Persistence::PersistObject support */ typedef std::vector ArchiveVector; typedef std::map ArchiveMap; typedef std::vector ClassVector; typedef std::map ClassMap; ArchiveVector myArchiveVector; ArchiveMap myArchiveMap; ClassVector myClassVector; ClassMap myClassMap; }; #define CCXX_RE(ar,ob) ar.read(ob); return ar #define CCXX_WE(ar,ob) ar.write(ob); return ar // Standard >> and << stream operators for PersistObject /** @relates PersistEngine */ inline PersistEngine& operator >>( PersistEngine& ar, PersistObject &ob) throw(PersistException) {CCXX_RE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator >>( PersistEngine& ar, PersistObject *&ob) throw(PersistException) {CCXX_RE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator <<( PersistEngine& ar, PersistObject const &ob) throw(PersistException) {CCXX_WE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator <<( PersistEngine& ar, PersistObject const *ob) throw(PersistException) {CCXX_WE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator >>( PersistEngine& ar, int8_t& ob) throw(PersistException) {CCXX_RE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator <<( PersistEngine& ar, int8_t ob) throw(PersistException) {CCXX_WE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator >>( PersistEngine& ar, uint8_t& ob) throw(PersistException) {CCXX_RE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator <<( PersistEngine& ar, uint8_t ob) throw(PersistException) {CCXX_WE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator >>( PersistEngine& ar, int16_t& ob) throw(PersistException) {CCXX_RE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator <<( PersistEngine& ar, int16_t ob) throw(PersistException) {CCXX_WE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator >>( PersistEngine& ar, uint16_t& ob) throw(PersistException) {CCXX_RE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator <<( PersistEngine& ar, uint16_t ob) throw(PersistException) {CCXX_WE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator >>( PersistEngine& ar, int32_t& ob) throw(PersistException) {CCXX_RE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator <<( PersistEngine& ar, int32_t ob) throw(PersistException) {CCXX_WE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator >>( PersistEngine& ar, uint32_t& ob) throw(PersistException) {CCXX_RE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator <<( PersistEngine& ar, uint32_t ob) throw(PersistException) {CCXX_WE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator >>( PersistEngine& ar, float& ob) throw(PersistException) {CCXX_RE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator <<( PersistEngine& ar, float ob) throw(PersistException) {CCXX_WE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator >>( PersistEngine& ar, double& ob) throw(PersistException) {CCXX_RE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator <<( PersistEngine& ar, double ob) throw(PersistException) {CCXX_WE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator >>( PersistEngine& ar, std::string& ob) throw(PersistException) {CCXX_RE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator <<( PersistEngine& ar, std::string ob) throw(PersistException) {CCXX_WE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator >>( PersistEngine& ar, bool& ob) throw(PersistException) {CCXX_RE(ar,ob);} /** @relates PersistEngine */ inline PersistEngine& operator <<( PersistEngine& ar, bool ob) throw(PersistException) {CCXX_WE(ar,ob);} #undef CCXX_RE #undef CCXX_WE /** * The following are template classes */ /** * @relates PersistEngine * serialize a vector of some serializable content to * the engine */ template PersistEngine& operator <<( PersistEngine& ar, typename std::vector const& ob) throw(PersistException) { ar << (uint32_t)ob.size(); for(unsigned int i=0; i < ob.size(); ++i) ar << ob[i]; return ar; } /** * @relates PersistEngine * deserialize a vector of deserializable content from * an engine. */ template PersistEngine& operator >>( PersistEngine& ar, typename std::vector& ob) throw(PersistException) { ob.clear(); uint32_t siz; ar >> siz; ob.resize(siz); for(uint32_t i=0; i < siz; ++i) ar >> ob[i]; return ar; } /** * @relates PersistEngine * serialize a deque of some serializable content to * the engine */ template PersistEngine& operator <<( PersistEngine& ar, typename std::deque const& ob) throw(PersistException) { ar << (uint32_t)ob.size(); for(typename std::deque::const_iterator it=ob.begin(); it != ob.end(); ++it) ar << *it; return ar; } /** * @relates PersistEngine * deserialize a deque of deserializable content from * an engine. */ template PersistEngine& operator >>( PersistEngine& ar, typename std::deque& ob) throw(PersistException) { ob.clear(); uint32_t siz; ar >> siz; //ob.resize(siz); for(uint32_t i=0; i < siz; ++i) { T node; ar >> node; ob.push_back(node); //ar >> ob[i]; } return ar; } /** * @relates PersistEngine * serialize a map with keys/values which both are serializeable * to an engine. */ template PersistEngine& operator <<( PersistEngine& ar, typename std::map const & ob) throw(PersistException) { ar << (uint32_t)ob.size(); for(typename std::map::const_iterator it = ob.begin();it != ob.end();++it) ar << it->first << it->second; return ar; } /** * @relates PersistEngine * deserialize a map with keys/values which both are serializeable * from an engine. */ template PersistEngine& operator >>( PersistEngine& ar, typename std::map& ob) throw(PersistException) { ob.clear(); uint32_t siz; ar >> siz; for(uint32_t i=0; i < siz; ++i) { Key a; ar >> a; ar >> ob[a]; } return ar; } /** * @relates PersistEngine * serialize a pair of some serializable content to the engine. */ template PersistEngine& operator <<( PersistEngine& ar, std::pair &ob) throw(PersistException) { ar << ob.first << ob.second; return ar; } /** * @relates PersistEngine * deserialize a pair of some serializable content to the engine. */ template PersistEngine& operator >>(PersistEngine& ar, std::pair &ob) throw(PersistException) { ar >> ob.first >> ob.second; return ar; } } // namespace ucommon #endif #endif #endif ucommon-6.4.4/inc/ucommon/fsys.h0000664000175000017500000005016512555734251013530 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Thread-aware file system manipulation class. This is used to provide * generic file operations that are OS independent and thread-safe in * behavior. This is used in particular to wrap posix calls internally * to pth, and to create portable code between MSWINDOWS and Posix low-level * file I/O operations. * @file ucommon/fsys.h */ #ifndef _UCOMMON_FSYS_H_ #define _UCOMMON_FSYS_H_ #ifndef _UCOMMON_CONFIG_H_ #include #endif #ifndef _UCOMMON_PROTOCOLS_H_ #include #endif #ifndef _UCOMMON_THREAD_H_ #include #endif #ifndef _UCOMMON_STRING_H_ #include #endif #ifndef _UCOMMON_TYPEREF_H_ #include #endif #ifndef _UCOMMON_MEMORY_H_ #include #endif #ifndef _MSWINDOWS_ #include #else #include #ifndef R_OK #define F_OK 0 #define X_OK 1 #define W_OK 2 #define R_OK 4 #endif #endif #include #include #ifndef __S_ISTYPE #define __S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask)) #endif #if !defined(S_ISDIR) && defined(S_IFDIR) #define S_ISDIR(mode) __S_ISTYPE((mode), S_IFDIR) #endif #if !defined(S_ISCHR) && defined(S_IFCHR) #define S_ISCHR(mode) __S_ISTYPE((mode), S_IFCHR) #elif !defined(S_ISCHR) #define S_ISCHR(mode) 0 #endif #if !defined(S_ISBLK) && defined(S_IFBLK) #define S_ISBLK(mode) __S_ISTYPE((mode), S_IFBLK) #elif !defined(S_ISBLK) #define S_ISBLK(mode) 0 #endif #if !defined(S_ISREG) && defined(S_IFREG) #define S_ISREG(mode) __S_ISTYPE((mode), S_IFREG) #elif !defined(S_ISREG) #define S_ISREG(mode) 1 #endif #if !defined(S_ISSOCK) && defined(S_IFSOCK) #define S_ISSOCK(mode) __S_ISTYPE((mode), S_IFSOCK) #elif !defined(S_ISSOCK) #define S_ISSOCK(mode) (0) #endif #if !defined(S_ISFIFO) && defined(S_IFIFO) #define S_ISFIFO(mode) __S_ISTYPE((mode), S_IFIFO) #elif !defined(S_ISFIFO) #define S_ISFIFO(mode) (0) #endif #if !defined(S_ISLNK) && defined(S_IFLNK) #define S_ISLNK(mode) __S_ISTYPE((mode), S_IFLNK) #elif !defined(S_ISLNK) #define S_ISLNK(mode) (0) #endif namespace ucommon { /** * Convenience type for loader operations. */ typedef void *mem_t; /** * A container for generic and o/s portable threadsafe file system functions. * These are based roughly on their posix equivilents. For libpth, the * system calls are wrapped. The native file descriptor or handle may be * used, but it is best to use "class fsys" instead because it can capture * the errno of a file operation in a threadsafe and platform independent * manner, including for mswindows targets. */ class __EXPORT fsys { protected: fd_t fd; mutable int error; public: /** * Most of the common chmod values are predefined. */ enum { OWNER_READONLY = 0400, GROUP_READONLY = 0440, PUBLIC_READONLY = 0444, OWNER_PRIVATE = 0600, OWNER_PUBLIC = 0644, GROUP_PRIVATE = 0660, GROUP_PUBLIC = 0664, EVERYONE = 0666, DIR_TEMPORARY = 01777 }; typedef struct stat fileinfo_t; #ifdef _MSWINDOWS_ static int remapError(void); #else inline static int remapError(void) { return errno; } #endif /** * Enumerated file access modes. */ typedef enum { RDONLY, WRONLY, REWRITE, RDWR = REWRITE, APPEND, SHARED, EXCLUSIVE, DEVICE, STREAM, RANDOM } access_t; /** * File offset type. */ typedef long offset_t; /** * Used to mark "append" in set position operations. */ static const offset_t end; /** * Construct an unattached fsys descriptor. */ fsys(); /** * Contruct fsys from raw file handle. */ fsys(fd_t handle); /** * Copy (dup) an existing fsys descriptor. * @param descriptor to copy from. */ fsys(const fsys& descriptor); /** * Create a fsys descriptor by opening an existing file or directory. * @param path of file to open for created descriptor. * @param access mode of file. */ fsys(const char *path, access_t access); /** * Create a fsys descriptor by creating a file. * @param path of file to create for descriptor. * @param access mode of file access. * @param permission mode of file. */ fsys(const char *path, unsigned permission, access_t access); /** * Close and release a file descriptor. */ ~fsys(); /** * Get the descriptor from the object by pointer reference. * @return low level file handle. */ inline fd_t operator*() const { return fd; } /** * Get the descriptor from the object by casting reference. * @return low level file handle. */ inline operator fd_t() const { return fd; } /** * Reset error flag. */ inline void reset(void) { error = 0; } /** * Test if file descriptor is open. * @return true if open. */ inline operator bool() const { return fd != INVALID_HANDLE_VALUE; } /** * Test if file descriptor is closed. * @return true if closed. */ inline bool operator!() const { return fd == INVALID_HANDLE_VALUE; } /** * Assign file descriptor by duplicating another descriptor. * @param descriptor to dup from. */ void operator=(const fsys& descriptor); /** * Replace current file descriptor with an external descriptor. This * does not create a duplicate. The external descriptor object is * marked as invalid. */ void operator*=(fd_t& descriptor); /** * Assing file descriptor from system descriptor. * @param descriptor to dup from. */ void operator=(fd_t descriptor); /** * Get the native system descriptor handle of the file descriptor. * @return native os descriptor. */ inline fd_t handle(void) const { return fd; } /** * Set with external descriptor. Closes existing file if open. * @param descriptor of open file. */ void set(fd_t descriptor); /** * Release descriptor, do not close. * @return handle being released. */ fd_t release(void); /** * Set the position of a file descriptor. * @param offset from start of file or "end" to append. * @return error number or 0 on success. */ int seek(offset_t offset); /** * Drop cached data from start of file. * @param size of region to drop or until end of file. * @return error number or 0 on success. */ int drop(offset_t size = 0); /** * See if current file stream is a tty device. * @return true if device. */ bool is_tty(void) const; /** * See if the file handle is a tty device. * @return true if device. */ static bool is_tty(fd_t fd); /** * Read data from descriptor or scan directory. * @param buffer to read into. * @param count of bytes to read. * @return bytes transferred, -1 if error. */ ssize_t read(void *buffer, size_t count); /** * Write data to descriptor. * @param buffer to write from. * @param count of bytes to write. * @return bytes transferred, -1 if error. */ ssize_t write(const void *buffer, size_t count); /** * Get status of open descriptor. * @param buffer to save status info in. * @return error number or 0 on success. */ int info(fileinfo_t *buffer); /** * Truncate file to specified length. The file pointer is positioned * to the new end of file. * @param offset to truncate to. * @return true if truncate successful. */ int trunc(offset_t offset); /** * Commit changes to the filesystem. * @return error number or 0 on success. */ int sync(void); /** * Set directory prefix (chdir). * @param path to change to. * @return error number or 0 on success. */ static int prefix(const char *path); /** * Get current directory prefix (pwd). * @param path to save directory into. * @param size of path we can save. * @return error number or 0 on success. */ static int prefix(char *path, size_t size); // to be depricated... static string_t prefix(void); /** * Stat a file. * @param path of file to stat. * @param buffer to save stat info. * @return error number or 0 on success. */ static int info(const char *path, fileinfo_t *buffer); /** * Erase (remove) a file only. * @param path of file. * @return error number or 0 on success. */ static int erase(const char *path); /** * Copy a file. * @param source file. * @param target file. * @param size of buffer. * @return error number or 0 on success. */ static int copy(const char *source, const char *target, size_t size = 1024); /** * Rename a file. * @param oldpath to rename from. * @param newpath to rename to. * @return error number or 0 on success. */ static int rename(const char *oldpath, const char *newpath); /** * Change file access mode. * @param path to change. * @param value of mode to assign. * @return error number or 0 on success. */ static int mode(const char *path, unsigned value); /** * Test if path exists. * @param path to test. * @return if true. */ static bool is_exists(const char *path); /** * Test if path readable. * @param path to test. * @return if true. */ static bool is_readable(const char *path); /** * Test if path writable. * @param path to test. * @return if true. */ static bool is_writable(const char *path); /** * Test if path is executable. * @param path to test. * @return if true. */ static bool is_executable(const char *path); /** * Test if path is a file. * @param path to test. * @return true if exists and is file. */ static bool is_file(const char *path); /** * Test if path is a directory. * @param path to test. * @return true if exists and is directory. */ static bool is_dir(const char *path); /** * Test if path is a symlink. * @param path to test. * @return true if exists and is symlink. */ static bool is_link(const char *path); /** * Test if path is a device path. * @param path to test. * @return true of is a device path. */ static bool is_device(const char *path); /** * Test if path is a hidden file. * @param path to test. * @return true if exists and is hidden. */ static bool is_hidden(const char *path); /** * Open a file or directory. * @param path of file to open. * @param access mode of descriptor. */ void open(const char *path, access_t access); /** * Assign descriptor directly. * @param descriptor to assign. */ inline void assign(fd_t descriptor) { close(); fd = descriptor; } /** * Assign a descriptor directly. * @param object to assign descriptor to. * @param descriptor to assign. */ inline static void assign(fsys& object, fd_t descriptor) { object.close(); object.fd = descriptor; } /** * Open a file descriptor directly. * @param path of file to create. * @param access mode of descriptor. * @param mode of file if created. */ void open(const char *path, unsigned mode, access_t access); /** * Remove a symbolic link explicitly. Other kinds of files are also * deleted. This should be used when uncertain about symlinks requiring * special support. * @param path to remove. * @return error number or 0 on success. */ static int unlink(const char *path); /** * Create a symbolic link. * @param path to create. * @param target of link. * @return error number or 0 on success. */ static int link(const char *path, const char *target); /** * Create a hard link. * @param path to create link to. * @param target of link. * @return error number or 0 on success. */ static int hardlink(const char *path, const char *target); /** * Read a symbolic link to get it's target. * @param path of link. * @param buffer to save target into. * @param size of buffer. */ static int linkinfo(const char *path, char *buffer, size_t size); /** * Close a fsys resource. * @return error code as needed. */ int close(void); /** * Get last error. * @return error number. */ inline int err(void) const { return error; } /** * Direct means to open a read-only file path and return a descriptor. * @param path to open. * @return descriptor on success, invalid handle on failure. */ static fd_t input(const char *path); /** * Direct means to create or access a writable path and return descriptor. * @param path to create. * @return descriptor on success, invalid handle on failure. */ static fd_t output(const char *path); /** * Direct means to create or append a writable path and return descriptor. * @param path to create. * @return descriptor on success, invalid handle on failure. */ static fd_t append(const char *path); /** * Release a file descriptor. * @param descriptor to release. */ static void release(fd_t descriptor); /** * Create pipe. These are created inheritable by default. * @param input descriptor. * @param output descriptor. * @param size of buffer if supported. * @return 0 or error code. */ static int pipe(fd_t& input, fd_t& output, size_t size = 0); /** * Changle inheritable handle. On windows this is done by creating a * duplicate handle and then closing the original. Elsewhere this * is done simply by setting flags. * @param descriptor to modify. * @param enable child process inheritence. * @return 0 on success, error on failure. */ static int inherit(fd_t& descriptor, bool enable); /** * Create inheritable /dev/null handle. * @return null device handle. */ static fd_t null(void); /** * Load a library into memory. * @param path to plugin. * @return 0 on success, else error. */ static int load(const char *path); /** * Execute a process and get exit code. * @param path to execute. * @param argv list. * @param optional env. * @return exit code. */ static int exec(const char *path, char **argv, char **envp = NULL); static inline bool is_file(struct stat *inode) { return S_ISREG(inode->st_mode); } static inline bool is_dir(struct stat *inode) { return S_ISDIR(inode->st_mode); } static inline bool is_link(struct stat *inode) { return S_ISLNK(inode->st_mode); } static inline bool is_dev(struct stat *inode) { return S_ISBLK(inode->st_mode) || S_ISCHR(inode->st_mode); } static inline bool is_char(struct stat *inode) { return S_ISCHR(inode->st_mode); } static inline bool is_disk(struct stat *inode) { return S_ISBLK(inode->st_mode); } static inline bool is_sys(struct stat *inode) { return S_ISSOCK(inode->st_mode) || S_ISFIFO(inode->st_mode); } }; /** * Convenience class for library plugins. * @author David Sugar */ class __EXPORT dso { private: friend class fsys; #ifdef _MSWINDOWS_ HINSTANCE ptr; #else void *ptr; #endif int error; public: #ifdef _MSWINDOWS_ typedef int (FAR WINAPI *addr_t)(); #else typedef void *addr_t; #endif /** * Create dso object for use by load functions. */ dso(); /** * Create and map a dso object. * @param path of library to map. */ dso(const char *path); /** * Destroy dso and release library. */ ~dso(); /** * Map library object with library. * @param name of library to load. */ void map(const char *path); /** * Release loaded library. */ void release(void); /** * Find symbol in loaded module. * @param module to search. * @param symbol to search for. * @return address of symbol or NULL if not found. */ addr_t find(const char *symbol) const; inline int err(void) const { return error; } inline addr_t operator[](const char *symbol) const { return find(symbol); } inline addr_t operator()(const char *symbol) const { return find(symbol); } inline operator bool() const { return ptr != NULL; } inline bool operator!() const { return ptr == NULL; } }; /** * Convenience class for directories. * @author David Sugar */ class __EXPORT dir : private fsys { private: #ifdef _MSWINDOWS_ WIN32_FIND_DATA *ptr; HINSTANCE mem; #else void *ptr; #endif public: /** * Construct and open a directory path. * @param path of directory. */ dir(const char *path); /** * Construct an unopened directory. */ dir(); /** * Close and release directory. */ ~dir(); /** * Simple direct method to create a directory. * @param path of directory to create. * @param mode of directory. * @return error number or 0 on success. */ static int create(const char *path, unsigned mode); /** * Remove an empty directory. * @param path of directory. * @return error number or 0 on success. */ static int remove(const char *path); /** * Open a directory path for reading. * @param path to open. */ void open(const char *path); /** * Read data from directory. * @param buffer to read into. * @param count of bytes to read. * @return bytes transferred, -1 if error. */ ssize_t read(char *buffer, size_t count); /** * Close and release directory object. */ void close(void); inline int err(void) const { return fsys::err(); } inline void reset(void) { fsys::reset(); } /** * Test if file descriptor is open. * @return true if open. */ inline operator bool() const { return ptr != NULL; } /** * Test if file descriptor is closed. * @return true if closed. */ inline bool operator!() const { return ptr == NULL; } }; /** * Convience type for fsys. */ typedef fsys fsys_t; typedef dir dir_t; typedef dso dso_t; inline bool is_exists(const char *path) { return fsys::is_exists(path); } inline bool is_readable(const char *path) { return fsys::is_readable(path); } inline bool is_writable(const char *path) { return fsys::is_writable(path); } inline bool is_executable(const char *path) { return fsys::is_executable(path); } inline bool is_file(const char *path) { return fsys::is_file(path); } inline bool is_dir(const char *path) { return fsys::is_dir(path); } inline bool is_link(const char *path) { return fsys::is_link(path); } inline bool is_device(const char *path) { return fsys::is_device(path); } } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/thread.h0000664000175000017500000016361712544454312014015 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Thread classes and sychronization objects. * The theory behind ucommon thread classes is that they would be used * to create derived classes where thread-specific data can be stored as * member data of the derived class. The run method is called when the * context is executed. Since we use a pthread foundation, we support * both detached threads and joinable threads. Objects based on detached * threads should be created with new, and will automatically delete when * the thread context exits. Joinable threads will be joined with deleted. * * The theory behind ucommon sychronization objects is that all upper level * sychronization objects can be formed directly from a mutex and conditional. * This includes semaphores, barriers, rwlock, our own specialized conditional * lock, resource-bound locking, and recurive exclusive locks. Using only * conditionals means we are not dependent on platform specific pthread * implimentations that may not impliment some of these, and hence improves * portability and consistency. Given that our rwlocks are recursive access * locks, one can safely create read/write threading pairs where the read * threads need not worry about deadlocks and the writers need not either if * they only write-lock one instance at a time to change state. * @file ucommon/thread.h */ /** * An example of the thread queue class. This may be relevant to producer- * consumer scenarios and realtime applications where queued messages are * stored on a re-usable object pool. * @example queue.cpp */ /** * A simple example of threading and join operation. * @example thread.cpp */ #ifndef _UCOMMON_THREAD_H_ #define _UCOMMON_THREAD_H_ #ifndef _UCOMMON_CPR_H_ #include #endif #ifndef _UCOMMON_ACCESS_H_ #include #endif #ifndef _UCOMMON_TIMERS_H_ #include #endif #ifndef _UCOMMON_MEMORY_H_ #include #endif namespace ucommon { class SharedPointer; /** * The conditional is a common base for other thread synchronizing classes. * Many of the complex sychronization objects, including barriers, semaphores, * and various forms of read/write locks are all built from the conditional. * This assures that the minimum functionality to build higher order thread * synchronizing objects is a pure conditional, and removes dependencies on * what may be optional features or functions that may have different * behaviors on different pthread implimentations and platforms. * @author David Sugar */ class __EXPORT Conditional { private: friend class ConditionalAccess; #if defined(_MSCONDITIONAL_) mutable CRITICAL_SECTION mutex; mutable CONDITION_VARIABLE cond; #elif defined(_MSTHREADS_) enum {SIGNAL = 0, BROADCAST = 1}; HANDLE events[2]; unsigned waiting; mutable CRITICAL_SECTION mlock; mutable CRITICAL_SECTION mutex; #else #ifndef __PTH__ class __LOCAL attribute { public: pthread_condattr_t attr; attribute(); }; __LOCAL static attribute attr; #endif mutable pthread_cond_t cond; mutable pthread_mutex_t mutex; #endif protected: friend class TimedEvent; /** * Conditional wait for signal on millisecond timeout. * @param timeout in milliseconds. * @return true if signalled, false if timer expired. */ bool wait(timeout_t timeout); /** * Conditional wait for signal on timespec timeout. * @param timeout as a high resolution timespec. * @return true if signalled, false if timer expired. */ bool wait(struct timespec *timeout); #ifdef _MSTHREADS_ inline void lock(void) {EnterCriticalSection(&mutex);}; inline void unlock(void) {LeaveCriticalSection(&mutex);}; void wait(void); void signal(void); void broadcast(void); #else /** * Lock the conditional's supporting mutex. */ inline void lock(void) {pthread_mutex_lock(&mutex);} /** * Unlock the conditional's supporting mutex. */ inline void unlock(void) {pthread_mutex_unlock(&mutex);} /** * Wait (block) until signalled. */ inline void wait(void) {pthread_cond_wait(&cond, &mutex);} /** * Signal the conditional to release one waiting thread. */ inline void signal(void) {pthread_cond_signal(&cond);} /** * Signal the conditional to release all waiting threads. */ inline void broadcast(void) {pthread_cond_broadcast(&cond);} #endif /** * Initialize and construct conditional. */ Conditional(); /** * Destroy conditional, release any blocked threads. */ ~Conditional(); public: friend class autolock; class __EXPORT autolock { private: #ifdef _MSTHREADS_ CRITICAL_SECTION *mutex; #else pthread_mutex_t *mutex; #endif public: inline autolock(const Conditional* object) { mutex = &object->mutex; #ifdef _MSTHREADS_ EnterCriticalSection(mutex); #else pthread_mutex_lock(mutex); #endif } inline ~autolock() { #ifdef _MSTHREADS_ LeaveCriticalSection(mutex); #else pthread_mutex_unlock(mutex); #endif } }; #if !defined(_MSTHREADS_) && !defined(__PTH__) /** * Support function for getting conditional attributes for realtime * scheduling. * @return attributes to use for creating realtime conditionals. */ static inline pthread_condattr_t *initializer(void) {return &attr.attr;} #endif /** * Convert a millisecond timeout into use for high resolution * conditional timers. * @param hires timespec representation to set. * @param timeout to convert. */ static void set(struct timespec *hires, timeout_t timeout); }; /** * The conditional rw seperates scheduling for optizming behavior or rw locks. * This varient of conditonal seperates scheduling read (broadcast wakeup) and * write (signal wakeup) based threads. This is used to form generic rwlock's * as well as the specialized condlock. * @author David Sugar */ class __EXPORT ConditionalAccess : private Conditional { protected: #if defined _MSCONDITIONAL_ CONDITION_VARIABLE bcast; #elif !defined(_MSTHREADS_) mutable pthread_cond_t bcast; #endif unsigned pending, waiting, sharing; /** * Conditional wait for signal on millisecond timeout. * @param timeout in milliseconds. * @return true if signalled, false if timer expired. */ bool waitSignal(timeout_t timeout); /** * Conditional wait for broadcast on millisecond timeout. * @param timeout in milliseconds. * @return true if signalled, false if timer expired. */ bool waitBroadcast(timeout_t timeout); /** * Conditional wait for signal on timespec timeout. * @param timeout as a high resolution timespec. * @return true if signalled, false if timer expired. */ bool waitSignal(struct timespec *timeout); /** * Conditional wait for broadcast on timespec timeout. * @param timeout as a high resolution timespec. * @return true if signalled, false if timer expired. */ bool waitBroadcast(struct timespec *timeout); /** * Convert a millisecond timeout into use for high resolution * conditional timers. * @param hires timespec representation to set. * @param timeout to convert. */ inline static void set(struct timespec *hires, timeout_t timeout) {Conditional::set(hires, timeout);} #ifdef _MSTHREADS_ inline void lock(void) {EnterCriticalSection(&mutex);}; inline void unlock(void) {LeaveCriticalSection(&mutex);}; void waitSignal(void); void waitBroadcast(void); inline void signal(void) {Conditional::signal();}; inline void broadcast(void) {Conditional::broadcast();}; #else /** * Lock the conditional's supporting mutex. */ inline void lock(void) {pthread_mutex_lock(&mutex);} /** * Unlock the conditional's supporting mutex. */ inline void unlock(void) {pthread_mutex_unlock(&mutex);} /** * Wait (block) until signalled. */ inline void waitSignal(void) {pthread_cond_wait(&cond, &mutex);} /** * Wait (block) until broadcast. */ inline void waitBroadcast(void) {pthread_cond_wait(&bcast, &mutex);} /** * Signal the conditional to release one signalled thread. */ inline void signal(void) {pthread_cond_signal(&cond);} /** * Signal the conditional to release all broadcast threads. */ inline void broadcast(void) {pthread_cond_broadcast(&bcast);} #endif public: /** * Initialize and construct conditional. */ ConditionalAccess(); /** * Destroy conditional, release any blocked threads. */ ~ConditionalAccess(); /** * Access mode shared thread scheduling. */ void access(void); /** * Exclusive mode write thread scheduling. */ void modify(void); /** * Release access mode read scheduling. */ void release(void); /** * Complete exclusive mode write scheduling. */ void commit(void); /** * Specify a maximum sharing (access) limit. This can be used * to detect locking errors, such as when aquiring locks that are * not released. * @param max sharing level. */ void limit_sharing(unsigned max); }; /** * Event notification to manage scheduled realtime threads. The timer * is advanced to sleep threads which then wakeup either when the timer * has expired or they are notified through the signal handler. This can * be used to schedule and signal one-time completion handlers or for time * synchronized events signaled by an asychrononous I/O or event source. * @author David Sugar */ class __EXPORT TimedEvent : public Timer { private: #ifdef _MSTHREADS_ HANDLE event; #else mutable pthread_cond_t cond; bool signalled; #endif mutable pthread_mutex_t mutex; protected: /** * Lock the object for wait or to manipulate derived data. This is * relevant to manipulations in a derived class. */ void lock(void); /** * Release the object lock after waiting. This is relevent to * manipulations in a derived class. */ void release(void); /** * Wait while locked. This can be used in more complex derived * objects where we are concerned with synchronized access between * the signaling and event thread. This can be used in place of * wait, but lock and release methods must be used around it. * @return true if time expired. */ bool sync(void); public: /** * Create event handler and timer for timing of events. */ TimedEvent(void); /** * Create event handler and timer set to trigger a timeout. * @param timeout in milliseconds. */ TimedEvent(timeout_t timeout); /** * Create event handler and timer set to trigger a timeout. * @param timeout in seconds. */ TimedEvent(time_t timeout); /** * Destroy timer and release pending events. */ ~TimedEvent(); /** * Signal pending event. Object may be locked or unlocked. The * signalling thread may choose to lock and check a condition in * a derived class before signalling. */ void signal(void); /** * Wait to be signalled or until timer expires. This is a wrapper for * expire for simple completion events. * @param timeout to wait from last reset. * @return true if signaled, false if timeout. */ bool wait(timeout_t timeout); /** * A simple wait until triggered. */ void wait(void); /** * Reset triggered conditional. */ void reset(void); }; /** * Portable recursive exclusive lock. This class is built from the * conditional and hence does not require support for non-standard and * platform specific extensions to pthread mutex to support recrusive * style mutex locking. The exclusive protocol is implimented to support * exclusive_lock referencing. */ class __EXPORT RecursiveMutex : private Conditional, public ExclusiveAccess { protected: unsigned waiting; unsigned lockers; pthread_t locker; virtual void _lock(void); virtual void _unlock(void); public: /** * Create rexlock. */ RecursiveMutex(); /** * Acquire or increase locking. */ void lock(void); /** * Timed lock request. */ bool lock(timeout_t timeout); /** * Release or decrease locking. */ void release(void); }; /** * A generic and portable implimentation of Read/Write locking. This * class impliments classical read/write locking, including "timed" locks. * Support for scheduling threads to avoid writer starvation is also provided * for. By building read/write locks from a conditional, we make them * available on pthread implimetations and other platforms which do not * normally include optional pthread rwlock's. We also do not restrict * the number of threads that may use the lock. Finally, both the exclusive * and shared protocols are implimented to support exclusive_lock and * shared_lock referencing. * @author David Sugar */ class __EXPORT ThreadLock : private ConditionalAccess, public ExclusiveAccess, public SharedAccess { protected: unsigned writers; pthread_t writeid; virtual void _lock(void); virtual void _share(void); virtual void _unlock(void); public: /** * Guard class to apply scope based access locking to objects. The rwlock * is located from the rwlock pool rather than contained in the target * object, and the read lock is released when the guard object falls out of * scope. This is essentially an automation mechanism for mutex::reader. * @author David Sugar */ class __EXPORT guard_reader { private: const void *object; public: /** * Create an unitialized instance of guard. Usually used with a * guard = operator. */ guard_reader(); /** * Construct a guard for a specific object. * @param object to guard. */ guard_reader(const void *object); /** * Release mutex when guard falls out of scope. */ ~guard_reader(); /** * Set guard to mutex lock a new object. If a lock is currently * held, it is released. * @param object to guard. */ void set(const void *object); /** * Prematurely release a guard. */ void release(void); /** * Set guard to read lock a new object. If a lock is currently * held, it is released. * @param pointer to object to guard. */ inline void operator=(const void *pointer) {set(pointer);} }; /** * Guard class to apply scope based exclusive locking to objects. The rwlock * is located from the rwlock pool rather than contained in the target * object, and the write lock is released when the guard object falls out of * scope. This is essentially an automation mechanism for mutex::writer. * @author David Sugar */ class __EXPORT guard_writer { private: const void *object; public: /** * Create an unitialized instance of guard. Usually used with a * guard = operator. */ guard_writer(); /** * Construct a guard for a specific object. * @param object to guard. */ guard_writer(const void *object); /** * Release mutex when guard falls out of scope. */ ~guard_writer(); /** * Set guard to mutex lock a new object. If a lock is currently * held, it is released. * @param object to guard. */ void set(const void *object); /** * Prematurely release a guard. */ void release(void); /** * Set guard to read lock a new object. If a lock is currently * held, it is released. * @param pointer to object to guard. */ inline void operator=(const void *pointer) {set(pointer);} }; /** * Create an instance of a rwlock. */ ThreadLock(); /** * Request modify (write) access through the lock. * @param timeout in milliseconds to wait for lock. * @return true if locked, false if timeout. */ bool modify(timeout_t timeout = Timer::inf); /** * Request shared (read) access through the lock. * @param timeout in milliseconds to wait for lock. * @return true if locked, false if timeout. */ bool access(timeout_t timeout = Timer::inf); /** * Specify hash table size for guard protection. The default is 1. * This should be called at initialization time from the main thread * of the application before any other threads are created. * @param size of hash table used for guarding. */ static void indexing(unsigned size); /** * Write protect access to an arbitrary object. This is like the * protect function of mutex. * @param object to protect. * @param timeout in milliseconds to wait for lock. * @return true if locked, false if timeout. */ static bool writer(const void *object, timeout_t timeout = Timer::inf); /** * Shared access to an arbitrary object. This is based on the protect * function of mutex. * @param object to share. * @param timeout in milliseconds to wait for lock. * @return true if shared, false if timeout. */ static bool reader(const void *object, timeout_t timeout = Timer::inf); /** * Release an arbitrary object that has been protected by a rwlock. * @param object to release. */ static bool release(const void *object); /** * Release the lock. */ void release(void); }; /** * Class for resource bound memory pools between threads. This is used to * support a memory pool allocation scheme where a pool of reusable objects * may be allocated, and the pool renewed by releasing objects or back. * When the pool is used up, a pool consuming thread then must wait for * a resource to be freed by another consumer (or timeout). This class is * not meant to be used directly, but rather to build the synchronizing * control between consumers which might be forced to wait for a resource. * @author David Sugar */ class __EXPORT ReusableAllocator : protected Conditional { protected: ReusableObject *freelist; unsigned waiting; /** * Initialize reusable allocator through a conditional. Zero free list. */ ReusableAllocator(); /** * Get next reusable object in the pool. * @param object from list. * @return next object. */ inline ReusableObject *next(ReusableObject *object) {return object->getNext();} /** * Release resuable object * @param object being released. */ void release(ReusableObject *object); }; /** * An optimized and convertable shared lock. This is a form of read/write * lock that has been optimized, particularly for shared access. Support * for scheduling access around writer starvation is also included. The * other benefits over traditional read/write locks is that the code is * a little lighter, and read (shared) locks can be converted to exclusive * (write) locks to perform brief modify operations and then returned to read * locks, rather than having to release and re-aquire locks to change mode. * @author David Sugar */ class __EXPORT ConditionalLock : protected ConditionalAccess, public SharedAccess { protected: class Context : public LinkedObject { public: inline Context(LinkedObject **root) : LinkedObject(root) {} pthread_t thread; unsigned count; }; LinkedObject *contexts; virtual void _share(void); virtual void _unlock(void); Context *getContext(void); public: /** * Construct conditional lock for default concurrency. */ ConditionalLock(); /** * Destroy conditional lock. */ ~ConditionalLock(); /** * Acquire write (exclusive modify) lock. */ void modify(void); /** * Commit changes / release a modify lock. */ void commit(void); /** * Acquire access (shared read) lock. */ void access(void); /** * Release a shared lock. */ void release(void); /** * Convert read lock into exclusive (write/modify) access. Schedule * when other readers sharing. */ virtual void exclusive(void); /** * Return an exclusive access lock back to share mode. */ virtual void share(void); }; /** * A portable implimentation of "barrier" thread sychronization. A barrier * waits until a specified number of threads have all reached the barrier, * and then releases all the threads together. This implimentation works * regardless of whether the thread library supports barriers since it is * built from conditional. It also differs in that the number of threads * required can be changed dynamically at runtime, unlike pthread barriers * which, when supported, have a fixed limit defined at creation time. Since * we use conditionals, another feature we can add is optional support for a * wait with timeout. * @author David Sugar */ class __EXPORT barrier : private Conditional { private: unsigned count; unsigned waits; public: /** * Construct a barrier with an initial size. * @param count of threads required. */ barrier(unsigned count); /** * Destroy barrier and release pending threads. */ ~barrier(); /** * Dynamically alter the number of threads required. If the size is * set below the currently waiting threads, then the barrier releases. * @param count of threads required. */ void set(unsigned count); /** * Dynamically increment the number of threads required. */ void inc(void); /** * Reduce the number of threads required. */ void dec(void); /** * Alternative prefix form of the same increment operation. * @return the current amount of threads. */ unsigned operator++(void); unsigned operator--(void); /** * Wait at the barrier until the count of threads waiting is reached. */ void wait(void); /** * Wait at the barrier until either the count of threads waiting is * reached or a timeout has occurred. * @param timeout to wait in milliseconds. * @return true if barrier reached, false if timer expired. */ bool wait(timeout_t timeout); }; /** * A portable counting semaphore class. A semaphore will allow threads * to pass through it until the count is reached, and blocks further threads. * Unlike pthread semaphore, our semaphore class supports it's count limit * to be altered during runtime and the use of timed waits. This class also * implements the shared_lock protocol. * @author David Sugar */ class __EXPORT Semaphore : public SharedAccess, protected Conditional { protected: unsigned count, waits, used; virtual void _share(void); virtual void _unlock(void); public: /** * Construct a semaphore with an initial count of threads to permit. * @param count of threads to permit, or special case 0 group release. */ Semaphore(unsigned count = 0); /** * Alternate onstructor with ability to preset available slots. * @param count of threads to permit. * @param avail instances not pre-locked. */ Semaphore(unsigned count, unsigned avail); /** * Wait until the semphore usage count is less than the thread limit. * Increase used count for our thread when unblocked. */ void wait(void); /** * Wait until the semphore usage count is less than the thread limit. * Increase used count for our thread when unblocked, or return without * changing if timed out. * @param timeout to wait in millseconds. * @return true if success, false if timeout. */ bool wait(timeout_t timeout); /** * Alter semaphore limit at runtime * @param count of threads to allow. */ void set(unsigned count); /** * Release the semaphore after waiting for it. */ void release(void); /** * Convenience operator to wait on a counting semaphore. */ inline void operator++(void) {wait();} /** * Convenience operator to release a counting semaphore. */ inline void operator--(void) {release();} }; /** * Generic non-recursive exclusive lock class. This class also impliments * the exclusive_lock protocol. In addition, an interface is offered to * support dynamically managed mutexes which are internally pooled. These * can be used to protect and serialize arbitrary access to memory and * objects on demand. This offers an advantage over embedding mutexes to * serialize access to individual objects since the maximum number of * mutexes will never be greater than the number of actually running threads * rather than the number of objects being potentially protected. The * ability to hash the pointer address into an indexed table further optimizes * access by reducing the chance for collisions on the primary index mutex. * @author David Sugar */ class __EXPORT Mutex : public ExclusiveAccess { protected: mutable pthread_mutex_t mlock; virtual void _lock(void); virtual void _unlock(void); public: friend class autolock; class __EXPORT autolock { private: pthread_mutex_t *mutex; public: inline autolock(const Mutex *object) { mutex = &object->mlock; pthread_mutex_lock(this->mutex); } inline ~autolock() { pthread_mutex_unlock(this->mutex); } }; /** * Guard class to apply scope based mutex locking to objects. The mutex * is located from the mutex pool rather than contained in the target * object, and the lock is released when the guard object falls out of * scope. This is essentially an automation mechanism for mutex::protect. * @author David Sugar */ class __EXPORT guard { private: const void *object; public: /** * Create an unitialized instance of guard. Usually used with a * guard = operator. */ guard(); /** * Construct a guard for a specific object. * @param object to guard. */ guard(const void *object); /** * Release mutex when guard falls out of scope. */ ~guard(); /** * Set guard to mutex lock a new object. If a lock is currently * held, it is released. * @param object to guard. */ void set(const void *object); /** * Prematurely release a guard. */ void release(void); /** * Set guard to mutex lock a new object. If a lock is currently * held, it is released. * @param pointer to object to guard. */ inline void operator=(void *pointer) {set(pointer);} }; /** * Create a mutex lock. */ Mutex(); /** * Destroy mutex lock, release waiting threads. */ ~Mutex(); /** * Acquire mutex lock. This is a blocking operation. */ inline void acquire(void) {pthread_mutex_lock(&mlock);} /** * Acquire mutex lock. This is a blocking operation. */ inline void lock(void) {pthread_mutex_lock(&mlock);} /** * Release acquired lock. */ inline void unlock(void) {pthread_mutex_unlock(&mlock);} /** * Release acquired lock. */ inline void release(void) {pthread_mutex_unlock(&mlock);} /** * Convenience function to acquire os native mutex lock directly. * @param lock to acquire. */ inline static void acquire(pthread_mutex_t *lock) {pthread_mutex_lock(lock);} /** * Convenience function to release os native mutex lock directly. * @param lock to release. */ inline static void release(pthread_mutex_t *lock) {pthread_mutex_unlock(lock);} /** * Specify hash table size for guard protection. The default is 1. * This should be called at initialization time from the main thread * of the application before any other threads are created. * @param size of hash table used for guarding. */ static void indexing(unsigned size); /** * Specify pointer/object/resource to guard protect. This uses a * dynamically managed mutex. * @param pointer to protect. */ static bool protect(const void *pointer); /** * Specify a pointer/object/resource to release. * @param pointer to release. */ static bool release(const void *pointer); }; /** * A mutex locked object smart pointer helper class. This is particularly * useful in referencing objects which will be protected by the mutex * protect function. When the pointer falls out of scope, the protecting * mutex is also released. This is meant to be used by the typed * mutex_pointer template. * @author David Sugar */ class __EXPORT auto_protect { private: // cannot copy... inline auto_protect(const auto_object &pointer) {} protected: const void *object; auto_protect(); public: /** * Construct a protected pointer referencing an existing object. * @param object we point to. */ auto_protect(const void *object); /** * Delete protected pointer. When it falls out of scope the associated * mutex is released. */ ~auto_protect(); /** * Manually release the pointer. This releases the mutex. */ void release(void); /** * Test if the pointer is not set. * @return true if the pointer is not referencing anything. */ inline bool operator!() const {return object == NULL;} /** * Test if the pointer is referencing an object. * @return true if the pointer is currently referencing an object. */ inline operator bool() const {return object != NULL;} /** * Set our pointer to a specific object. If the pointer currently * references another object, the associated mutex is released. The * pointer references our new object and that new object is locked. * @param object to assign to. */ void operator=(const void *object); }; /** * An object pointer that uses mutex to assure thread-safe singleton use. * This class is used to support a threadsafe replacable pointer to a object. * This class is used to form and support the templated locked_pointer class * and used with the locked_release class. An example of where this might be * used is in config file parsers, where a seperate thread may process and * generate a new config object for new threads to refernce, while the old * configuration continues to be used by a reference counted instance that * goes away when it falls out of scope. * @author David Sugar */ class __EXPORT LockedPointer { private: friend class locked_release; mutable pthread_mutex_t mutex; ObjectProtocol *pointer; protected: /** * Create an instance of a locked pointer. */ LockedPointer(); /** * Replace existing object with a new one for next request. * @param object to register with pointer. */ void replace(ObjectProtocol *object); /** * Create a duplicate reference counted instance of the current object. * @return duplicate reference counted object. */ ObjectProtocol *dup(void); /** * Replace existing object through assignment. * @param object to assign. */ inline void operator=(ObjectProtocol *object) {replace(object);} }; /** * Shared singleton object. A shared singleton object is a special kind of * object that may be shared by multiple threads but which only one active * instance is allowed to exist. The shared object is managed by the * templated shared pointer class, and is meant to be inherited as a base * class for the derived shared singleton type. * @author David Sugar */ class __EXPORT SharedObject { protected: friend class SharedPointer; /** * Commit is called when a shared singleton is accepted and replaces * a prior instance managed by a shared pointer. Commit occurs * when replace is called on the shared pointer, and is assured to * happen only when no threads are accessing either the current * or the prior instance that was previously protected by the pointer. * @param pointer that now holds the object. */ virtual void commit(SharedPointer *pointer); public: /** * Allows inherited virtual. */ virtual ~SharedObject(); }; /** * The shared pointer is used to manage a singleton instance of shared object. * This class is used to support the templated shared_pointer class and the * shared_release class, and is not meant to be used directly or as a base * for anything else. One or more threads may aquire a shared lock to the * singleton object through this pointer, and it can only be replaced with a * new singleton instance when no threads reference it. The conditional lock * is used to manage shared access for use and exclusive access when modified. * @author David Sugar */ class __EXPORT SharedPointer : protected ConditionalAccess { private: friend class shared_release; SharedObject *pointer; protected: /** * Created shared locking for pointer. Must be assigned by replace. */ SharedPointer(); /** * Destroy lock and release any blocked threads. */ ~SharedPointer(); /** * Replace existing singleton instance with new one. This happens * during exclusive locking, and the commit method of the object * will be called. * @param object being set. */ void replace(SharedObject *object); /** * Acquire a shared reference to the singleton object. This is a * form of shared access lock. Derived classes and templates access * "release" when the shared pointer is no longer needed. * @return shared object. */ SharedObject *share(void); }; /** * An abstract class for defining classes that operate as a thread. A derived * thread class has a run method that is invoked with the newly created * thread context, and can use the derived object to store all member data * that needs to be associated with that context. This means the derived * object can safely hold thread-specific data that is managed with the life * of the object, rather than having to use the clumsy thread-specific data * management and access functions found in thread support libraries. * @author David Sugar */ class __EXPORT Thread { protected: // may be used in future if we need cancelable threads... #ifdef _MSTHREADS_ HANDLE cancellor; #else void *cancellor; #endif enum {R_UNUSED} reserved; // cancel mode? pthread_t tid; stacksize_t stack; int priority; /** * Create a thread object that will have a preset stack size. If 0 * is used, then the stack size is os defined/default. * @param stack size to use or 0 for default. */ Thread(size_t stack = 0); /** * Map thread for get method. This should be called from start of the * run() method of a derived class. */ void map(void); /** * Check if running. */ virtual bool is_active(void) const; public: /** * Set thread priority without disrupting scheduling if possible. * Based on scheduling policy. It is recommended that the process * is set for realtime scheduling, and this method is actually for * internal use. */ void setPriority(void); /** * Yield execution context of the current thread. This is a static * and may be used anywhere. */ static void yield(void); /** * Sleep current thread for a specified time period. * @param timeout to sleep for in milliseconds. */ static void sleep(timeout_t timeout); /** * Get mapped thread object. This returns the mapped base class of the * thread object of the current executing context. You will need to * cast to the correct derived class to access derived thread-specific * storage. If the current thread context is not mapped NULL is returned. */ static Thread *get(void); /** * Abstract interface for thread context run method. */ virtual void run(void) = 0; /** * Destroy thread object, thread-specific data, and execution context. */ virtual ~Thread(); /** * Exit the thread context. This function should NO LONGER be called * directly to exit a running thread. Instead this method will only be * used to modify the behavior of the thread context at thread exit, * including detached threads which by default delete themselves. This * documented usage was changed to support Mozilla NSPR exit behavior * in case we support NSPR as an alternate thread runtime in the future. */ virtual void exit(void); /** * Used to initialize threading library. May be needed for some platforms. */ static void init(void); /** * Used to specify scheduling policy for threads above priority "0". * Normally we apply static realtime policy SCHED_FIFO (default) or * SCHED_RR. However, we could apply SCHED_OTHER, etc. */ static void policy(int polid); /** * Set concurrency level of process. This is essentially a portable * wrapper for pthread_setconcurrency. */ static void concurrency(int level); /** * Determine if two thread identifiers refer to the same thread. * @param thread1 to test. * @param thread2 to test. * @return true if both are the same context. */ static bool equal(pthread_t thread1, pthread_t thread2); /** * Get current thread id. * @return thread id. */ static pthread_t self(void); inline operator bool() const {return is_active();} inline bool operator!() const {return !is_active();} inline bool isRunning(void) const {return is_active();} }; /** * A child thread object that may be joined by parent. A child thread is * a type of thread in which the parent thread (or process main thread) can * then wait for the child thread to complete and then delete the child object. * The parent thread can wait for the child thread to complete either by * calling join, or performing a "delete" of the derived child object. In * either case the parent thread will suspend execution until the child thread * exits. * @author David Sugar */ class __EXPORT JoinableThread : public Thread { protected: #ifdef _MSTHREADS_ HANDLE running; #else volatile bool running; #endif volatile bool joining; /** * Create a joinable thread with a known context stack size. * @param size of stack for thread context or 0 for default. */ JoinableThread(size_t size = 0); /** * Delete child thread. Parent thread suspends until child thread * run method completes or child thread calls it's exit method. */ virtual ~JoinableThread(); /** * Join thread with parent. Calling from a child thread to exit is * now depreciated behavior and in the future will not be supported. * Threads should always return through their run() method. */ void join(void); bool is_active(void) const; virtual void run(void) = 0; public: /** * Start execution of child context. This must be called after the * child object is created (perhaps with "new") and before it can be * joined. This method actually begins the new thread context, which * then calls the object's run method. Optionally raise the priority * of the thread when it starts under realtime priority. * @param priority of child thread. */ void start(int priority = 0); /** * Start execution of child context as background thread. This is * assumed to be off main thread, with a priority lowered by one. */ inline void background(void) {start(-1);} }; /** * A detached thread object that is stand-alone. This object has no * relationship with any other running thread instance will be automatically * deleted when the running thread instance exits, either by it's run method * exiting, or explicity calling the exit member function. * @author David Sugar */ class __EXPORT DetachedThread : public Thread { protected: bool active; /** * Create a detached thread with a known context stack size. * @param size of stack for thread context or 0 for default. */ DetachedThread(size_t size = 0); /** * Destroys object when thread context exits. Never externally * deleted. Derived object may also have destructor to clean up * thread-specific member data. */ ~DetachedThread(); /** * Exit context of detached thread. Thread object will be deleted. * This function should NO LONGER be called directly to exit a running * thread. Instead, the thread should only "return" through the run() * method to exit. The documented usage was changed so that exit() can * still be used to modify the "delete this" behavior of detached threads * while merging thread exit behavior with Mozilla NSPR. */ void exit(void); bool is_active(void) const; virtual void run(void) = 0; public: /** * Start execution of detached context. This must be called after the * object is created (perhaps with "new"). This method actually begins * the new thread context, which then calls the object's run method. * @param priority to start thread with. */ void start(int priority = 0); }; /** * Auto-pointer support class for locked objects. This is used as a base * class for the templated locked_instance class that uses the managed * LockedPointer to assign a reference to an object. When the locked * instance falls out of scope, the object is derefenced. Ideally the * pointer typed object should be based on the reference counted object class. * @author David Sugar */ class __EXPORT locked_release { protected: ObjectProtocol *object; /**< locked object protected by locked_release */ /** * Create an unassigned locked object pointer base. */ locked_release(); /** * Construct a locked object instance base from an existing instance. This * will create a duplicate (retained) reference. * @param object to copy from. */ locked_release(const locked_release &object); public: /** * Construct a locked object instance base from a LockedPointer. References * a retained instance of the underlying object from the LockedPointer. * @param pointer of locked pointer to assign from. */ locked_release(LockedPointer &pointer); /** * Auto-release pointer to locked object instance. This is used to release * a reference when the pointer template falls out of scope. */ ~locked_release(); /** * Manually release the object reference. */ void release(void); /** * Assign a locked object pointer. If an existing object is already * assigned, the existing pointer is released. * @param pointer reference through locked object. */ locked_release &operator=(LockedPointer &pointer); }; /** * Auto-pointer support class for shared singleton objects. This is used as * a base class for the templated shared_instance class that uses shared * access locking through the SharedPointer class. When the shared instance * falls out of scope, the SharedPointer lock is released. The pointer * typed object must be based on the SharedObject class. * @author David Sugar */ class __EXPORT shared_release { protected: SharedPointer *ptr; /**< Shared lock for protected singleton */ /** * Create an unassigned shared singleton object pointer base. */ shared_release(); /** * Construct a shared object instance base from an existing instance. This * will assign an additional shared lock. * @param object to copy from. */ shared_release(const shared_release &object); public: /** * Access lock a shared singleton instance from a SharedPointer. * @param pointer of shared pointer to assign from. */ shared_release(SharedPointer &pointer); /** * Auto-unlock shared lock for singleton instance protected by shared * pointer. This is used to unlock when the instance template falls out * of scope. */ ~shared_release(); /** * Manually release access to shared singleton object. */ void release(void); /** * Get pointer to singleton object that we have shared lock for. * @return shared object singleton. */ SharedObject *get(void); /** * Assign shared lock access to shared singleton. If an existing * shared lock is held for another pointer, it is released. * @param pointer access for shared object. */ shared_release &operator=(SharedPointer &pointer); }; /** * Templated shared pointer for singleton shared objects of specific type. * This is used as typed template for the SharedPointer object reference * management class. This is used to supply a typed singleton shared * instance to the typed shared_instance template class. * @author David Sugar */ template class shared_pointer : public SharedPointer { public: /** * Created shared locking for typed singleton pointer. */ inline shared_pointer() : SharedPointer() {} /** * Acquire a shared (duplocate) reference to the typed singleton object. * This is a form of shared access lock. Derived classes and templates * access conditionallock "release" when the shared pointer is no longer * needed. * @return typed shared object. */ inline const T *dup(void) {return static_cast(SharedPointer::share());} /** * Replace existing typed singleton instance with new one. This happens * during exclusive locking, and the commit method of the typed object * will be called. * @param object being set. */ inline void replace(T *object) {SharedPointer::replace(object);} /** * Replace existing typed singleton object through assignment. * @param object to assign. */ inline void operator=(T *object) {replace(object);} /** * Access shared lock typed singleton object by pointer reference. * @return typed shared object. */ inline T *operator*() {return dup();} }; /** * Templated locked pointer for referencing locked objects of specific type. * This is used as typed template for the LockedPointer object reference * management class. This is used to supply a typed locked instances * to the typed locked_instance template class. * @author David Sugar */ template class locked_pointer : public LockedPointer { public: /** * Create an instance of a typed locked pointer. */ inline locked_pointer() : LockedPointer() {} /** * Create a duplicate reference counted instance of the current typed * object. * @return duplicate reference counted typed object. */ inline T* dup(void) {return static_cast(LockedPointer::dup());} /** * Replace existing typed object with a new one for next request. * @param object to register with pointer. */ inline void replace(T *object) {LockedPointer::replace(object);} /** * Replace existing object through assignment. * @param object to assign. */ inline void operator=(T *object) {replace(object);} /** * Create a duplicate reference counted instance of the current typed * object by pointer reference. * @return duplicate reference counted typed object. */ inline T *operator*() {return dup();} }; /** * A templated smart pointer instance for lock protected objects. * This is used to reference an instance of a typed locked_pointer. * @author David Sugar */ template class locked_instance : public locked_release { public: /** * Construct empty locked instance of typed object. */ inline locked_instance() : locked_release() {} /** * Construct locked instance of typed object from matching locked_pointer. * @param pointer to get instance from. */ inline locked_instance(locked_pointer &pointer) : locked_release(pointer) {} /** * Extract instance of locked typed object by pointer reference. * @return instance of typed object. */ inline T& operator*() const {return *(static_cast(object));} /** * Access member of instance of locked typed object by member reference. * @return instance of typed object. */ inline T* operator->() const {return static_cast(object);} /** * Get pointer to instance of locked typed object. * @return instance of typed object. */ inline T* get(void) const {return static_cast(object);} }; /** * A templated smart pointer instance for shared singleton typed objects. * This is used to access the shared lock instance of the singleton. * @author David Sugar */ template class shared_instance : public shared_release { public: /** * Construct empty instance to reference shared typed singleton. */ inline shared_instance() : shared_release() {} /** * Construct shared access instance of shared typed singleton from matching * shared_pointer. * @param pointer to get instance from. */ inline shared_instance(shared_pointer &pointer) : shared_release(pointer) {} /** * Access shared typed singleton object this instance locks and references. */ inline const T& operator*() const {return *(static_cast(ptr->pointer));} /** * Access member of shared typed singleton object this instance locks and * references. */ inline const T* operator->() const {return static_cast(ptr->pointer);} /** * Access pointer to typed singleton object this instance locks and * references. */ inline const T* get(void) const {return static_cast(ptr->pointer);} }; /** * Typed smart locked pointer class. This is used to manage references to * objects which are protected by an auto-generated mutex. The mutex is * released when the pointer falls out of scope. * @author David Sugar */ template class mutex_pointer : public auto_protect { public: /** * Create a pointer with no reference. */ inline mutex_pointer() : auto_protect() {} /** * Create a pointer with a reference to a heap object. * @param object we are referencing. */ inline mutex_pointer(T* object) : auto_protect(object) {} /** * Reference object we are pointing to through pointer indirection. * @return object we are pointing to. */ inline T& operator*() const {return *(static_cast(auto_protect::object));} /** * Reference member of object we are pointing to. * @return reference to member of pointed object. */ inline T* operator->() const {return static_cast(auto_protect::object);} /** * Get pointer to object. * @return pointer or NULL if we are not referencing an object. */ inline T* get(void) const {return static_cast(auto_protect::object);} }; /** * Convenience function to start a joinable thread. * @param thread to start. * @param priority of thread. */ inline void start(JoinableThread *thread, int priority = 0) {thread->start(priority);} /** * Convenience function to start a detached thread. * @param thread to start. * @param priority of thread. */ inline void start(DetachedThread *thread, int priority = 0) {thread->start(priority);} /** * Convenience type for using conditional locks. */ typedef ConditionalLock condlock_t; /** * Convenience type for scheduling access. */ typedef ConditionalAccess accesslock_t; /** * Convenience type for using timed events. */ typedef TimedEvent timedevent_t; /** * Convenience type for using exclusive mutex locks. */ typedef Mutex mutex_t; /** * Convenience type for using read/write locks. */ typedef ThreadLock rwlock_t; /** * Convenience type for using recursive exclusive locks. */ typedef RecursiveMutex rexlock_t; /** * Convenience type for using counting semaphores. */ typedef Semaphore semaphore_t; /** * Convenience type for using thread barriers. */ typedef barrier barrier_t; /** * Convenience function to wait on a barrier. * @param barrier to wait. */ inline void wait(barrier_t &barrier) {barrier.wait();} /** * Convenience function to wait on a semaphore. * @param semaphore to wait on. * @param timeout to wait for. */ inline void wait(semaphore_t &semaphore, timeout_t timeout = Timer::inf) {semaphore.wait(timeout);} /** * Convenience function to release a semaphore. * @param semaphore to release. */ inline void release(semaphore_t &semaphore) {semaphore.release();} /** * Convenience function to acquire a mutex. * @param mutex to acquire. */ inline void acquire(mutex_t &mutex) {mutex.lock();} /** * Convenience function to release a mutex. * @param mutex to release. */ inline void release(mutex_t &mutex) {mutex.release();} /** * Convenience function to exclusively schedule conditional access. * @param lock to make exclusive. */ inline void modify(accesslock_t &lock) {lock.modify();} /** * Convenience function to shared read schedule conditional access. * @param lock to access shared. */ inline void access(accesslock_t &lock) {lock.access();} /** * Convenience function to release an access lock. * @param lock to release. */ inline void release(accesslock_t &lock) {lock.release();} /** * Convenience function to commit an exclusive access lock. * lock. * @param lock to commit. */ inline void commit(accesslock_t &lock) {lock.commit();} /** * Convenience function to exclusively lock shared conditional lock. * @param lock to make exclusive. */ inline void exclusive(condlock_t &lock) {lock.exclusive();} /** * Convenience function to restore shared access on a conditional lock. * @param lock to make shared. */ inline void share(condlock_t &lock) {lock.share();} /** * Convenience function to exclusively aquire a conditional lock. * @param lock to acquire for modify. */ inline void modify(condlock_t &lock) {lock.modify();} /** * Convenience function to commit and release an exclusively locked conditional * lock. * @param lock to commit. */ inline void commit(condlock_t &lock) {lock.commit();} /** * Convenience function for shared access to a conditional lock. * @param lock to access. */ inline void access(condlock_t &lock) {lock.access();} /** * Convenience function to release shared access to a conditional lock. * @param lock to release. */ inline void release(condlock_t &lock) {lock.release();} /** * Convenience function for exclusive write access to a read/write lock. * @param lock to write lock. * @param timeout to wait for exclusive locking. */ inline bool exclusive(rwlock_t &lock, timeout_t timeout = Timer::inf) {return lock.modify(timeout);} /** * Convenience function for shared read access to a read/write lock. * @param lock to share read lock. * @param timeout to wait for shared access. */ inline bool share(rwlock_t &lock, timeout_t timeout = Timer::inf) {return lock.access(timeout);} /** * Convenience function to release a shared lock. * @param lock to release. */ inline void release(rwlock_t &lock) {lock.release();} /** * Convenience function to lock a shared recursive mutex lock. * @param lock to acquire. */ inline void lock(rexlock_t &lock) {lock.lock();} /** * Convenience function to release a shared recursive mutex lock. * @param lock to release. */ inline void release(rexlock_t &lock) {lock.release();} #define __AUTOLOCK__ autolock __autolock__(this); #define __SYNC__ for(bool _sync_flag_ = Mutex::protect(this); _sync_flag_; _sync_flag_ = !Mutex::release(this)) #define __SHARED__ for(bool _sync_flag_ = ThreadLock::reader(this); _sync_flag_; _sync_flag_ = !ThreadLock::release(this)) #define ___EXCLUSIVE__ for(bool _sync_flag_ = ThreadLock::writer(this); _sync_flag_; _sync_flag_ = !ThreadLock::release(this)) } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/stream.h0000664000175000017500000003201312504226765014027 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Any ucommon streaming classes that are built from std::streamio facilities * and that support ANSI C++ stream operators. * @file ucommon/stream.h */ #ifndef UCOMMON_SYSRUNTIME #ifndef _UCOMMON_STREAM_H_ #define _UCOMMON_STREAM_H_ #ifndef _UCOMMON_CONFIG_H #include #endif #ifndef _UCOMMON_PROTOCOLS_H_ #include #endif #ifndef _UCOMMON_THREAD_H_ #include #endif #ifndef _UCOMMON_SOCKET_H_ #include #endif #ifndef _UCOMMON_FSYS_H_ #include #endif #ifndef _UCOMMON_SHELL_H_ #include #endif #include namespace ucommon { /** * Common stream buffer for std C++ i/o classes. This both binds the * character protocol to iostream and offers a common base class for all * other c++ stdlib based streaming classes. * @author David Sugar */ class __EXPORT StreamBuffer : protected std::streambuf, public std::iostream { protected: size_t bufsize; char *gbuf, *pbuf; StreamBuffer(); /** * This streambuf method is used for doing unbuffered reads * through the establish tcp socket connection when in interactive mode. * Also this method will handle proper use of buffers if not in * interactive mode. * * @return char from tcp socket connection, EOF if not connected. */ int uflow(); void release(void); void allocate(size_t size); public: /** * Flush the stream input and output buffers, writes pending output. * @return 0 on success, or error code. */ int sync(void); inline bool is_open(void) const {return bufsize > 0;} inline operator bool() const {return bufsize > 0;} inline bool operator!() const {return bufsize == 0;} }; /** * Streamable tcp connection between client and server. The tcp stream * class can represent a client connection to a server or an instance of * a service generated by a tcp listener. As a stream class, data can * be manipulated using the << and >> operators. * * @author David Sugar */ class __EXPORT tcpstream : public StreamBuffer { private: __LOCAL void allocate(unsigned size); __LOCAL void reset(void); protected: socket_t so; timeout_t timeout; virtual ssize_t _read(char *buffer, size_t size); virtual ssize_t _write(const char *buffer, size_t size); virtual bool _wait(void); /** * Release the tcp stream and destroy the underlying socket. */ void release(void); /** * This streambuf method is used to load the input buffer * through the established tcp socket connection. * * @return char from get buffer, EOF if not connected. */ int underflow(void); /** * This streambuf method is used to write the output * buffer through the established tcp connection. * @param ch char to push through. * @return char pushed through. */ int overflow(int ch); inline socket_t getsocket(void) const {return so;} public: /** * Copy constructor... * @param copy for object. */ tcpstream(const tcpstream& copy); /** * Create a stream from an existing tcp listener. * @param server to accept connection from. * @param segsize for tcp segments and buffering. * @param timeout for socket i/o operations. */ tcpstream(const TCPServer *server, unsigned segsize = 536, timeout_t timeout = 0); /** * Create an unconnected tcp stream object that is idle until opened. * @param family of protocol to create. * @param timeout for socket i/o operations. */ tcpstream(int family = PF_INET, timeout_t timeout = 0); /** * A convenience constructor that creates a connected tcp stream directly * from an address. The socket is constructed to match the type of the * the address family in the socket address that is passed. * @param address of service to connect to. * @param segsize for tcp segments and buffering. * @param timeout for socket i/o operations. */ tcpstream(Socket::address& address, unsigned segsize = 536, timeout_t timeout = 0); /** * Destroy a tcp stream. */ virtual ~tcpstream(); /** * See if stream connection is active. * @return true if stream is active. */ inline operator bool() const {return so != INVALID_SOCKET && bufsize > 0;} /** * See if stream is disconnected. * @return true if stream disconnected. */ inline bool operator!() const {return so == INVALID_SOCKET || bufsize == 0;} /** * Open a stream connection to a tcp service. * @param address of service to access. * @param segment buffering size to use. */ void open(Socket::address& address, unsigned segment = 536); /** * Open a stream connectoion to a host and service. * @param host to connect to. * @param service to connect to by name or number as string. * @param segment buffering size to use. */ void open(const char *host, const char *service, unsigned segment = 536); /** * Close an active stream connection. This does not release the * socket but is a disconnect. */ void close(void); }; /** * Streamable tcp connection between client and server. The tcp stream * class can represent a client connection to a server or an instance of * a service generated by a tcp listener. As a stream class, data can * be manipulated using the << and >> operators. * * @author David Sugar */ class __EXPORT pipestream : public StreamBuffer { public: typedef enum { RDONLY, WRONLY, RDWR } access_t; private: __LOCAL void allocate(size_t size, access_t mode); protected: fsys_t rd, wr; shell::pid_t pid; /** * Release the stream, detach/do not wait for the process. */ void release(void); /** * This streambuf method is used to load the input buffer * through the established pipe connection. * * @return char from get buffer, EOF if not connected. */ int underflow(void); /** * This streambuf method is used to write the output * buffer through the established pipe connection. * * @param ch char to push through. * @return char pushed through. */ int overflow(int ch); public: /** * Create an unopened pipe stream. */ pipestream(); /** * Create child process and start pipe. * @param path to execute. * @param access mode of pipe stream. * @param args to pass to command. * @param env to create in child. * @param size of buffer. */ pipestream(const char *command, access_t access, char **args, char **env = NULL, size_t size = 512); /** * Destroy a pipe stream. */ virtual ~pipestream(); /** * See if stream connection is active. * @return true if stream is active. */ inline operator bool() const {return (bufsize > 0);} /** * See if stream is disconnected. * @return true if stream disconnected. */ inline bool operator!() const {return bufsize == 0;} /** * Open a stream connection to a pipe service. * @param path to execute. * @param access mode of stream. * @param args to pass to command. * @param env to create in child process. * @param buffering size to use. */ void open(const char *path, access_t access, char **args, char **env = NULL, size_t buffering = 512); /** * Close an active stream connection. This waits for the child to * terminate. */ int close(void); /** * Force terminate child and close. */ void terminate(void); inline void cancel(void) {terminate();} }; /** * Streamable tcp connection between client and server. The tcp stream * class can represent a client connection to a server or an instance of * a service generated by a tcp listener. As a stream class, data can * be manipulated using the << and >> operators. * * @author David Sugar */ class __EXPORT filestream : public StreamBuffer { public: typedef enum { RDONLY, WRONLY, RDWR } access_t; private: __LOCAL void allocate(size_t size, fsys::access_t mode); protected: fsys_t fd; fsys::access_t ac; /** * This streambuf method is used to load the input buffer * through the established pipe connection. * * @return char from get buffer, EOF if not connected. */ int underflow(void); /** * This streambuf method is used to write the output * buffer through the established pipe connection. * * @param ch char to push through. * @return char pushed through. */ int overflow(int ch); public: /** * Create an unopened pipe stream. */ filestream(); /** * Create duplicate stream. */ filestream(const filestream& copy); /** * Create and open a file stream. */ filestream(const char *path, unsigned mode, fsys::access_t access, size_t bufsize = 512); /** * Open file stream. */ filestream(const char *path, fsys::access_t access, size_t bufsize = 512); /** * Destroy a file stream. */ virtual ~filestream(); /** * See if stream connection is active. * @return true if stream is active. */ inline operator bool() const {return (bufsize > 0);} /** * See if stream is disconnected. * @return true if stream disconnected. */ inline bool operator!() const {return bufsize == 0;} /** * Open a stream connection to a tcp service. */ void open(const char *filename, fsys::access_t access, size_t buffering = 512); /** * Create a stream connection to a tcp service. */ void open(const char *filename, unsigned mode, fsys::access_t access, size_t buffering = 512); /** * Close an active stream connection. */ void close(void); /** * Seek position. */ void seek(fsys::offset_t offset); /** * Get error flag from last i/o operation. * @return last error. */ inline int err(void) const {return fd.err();} }; /** * At least with gcc, linking of stream operators was broken. This provides * an auxillory class to solve the issue. */ class __EXPORT _stream_operators { private: inline _stream_operators() {} public: static std::ostream& print(std::ostream& out, const PrintProtocol& format); static std::istream& input(std::istream& inp, InputProtocol& format); static std::ostream& print(std::ostream& out, const string_t& str); static std::istream& input(std::istream& inp, string_t& str); static std::ostream& print(std::ostream& out, const stringlist_t& list); static std::istream& input(std::istream& in, stringlist_t& list); static std::string& append(std::string& target, String& source); }; inline std::ostream& operator<< (std::ostream& out, const PrintProtocol& format) {return _stream_operators::print(out, format);} inline std::istream& operator>> (std::istream& inp, InputProtocol& format) {return _stream_operators::input(inp, format);} inline std::ostream& operator<< (std::ostream& out, const string_t& str) {return _stream_operators::print(out, str);} inline std::istream& operator>> (std::istream& inp, string_t& str) {return _stream_operators::input(inp, str);} inline std::ostream& operator<< (std::ostream& out, const stringlist_t& list) {return _stream_operators::print(out, list);} inline std::istream& operator>> (std::istream& in, stringlist_t& list) {return _stream_operators::input(in, list);} inline std::string& operator+(std::string& target, String& source) {return _stream_operators::append(target, source);} inline std::string& operator+=(std::string& target, String& source) {return _stream_operators::append(target, source);} inline std::ostream& operator<<(std::ostream& os, Socket::address& addr) { #ifdef AF_INET6 char buf[INET6_ADDRSTRLEN]; #else char buf[INET_ADDRSTRLEN]; #endif addr.print(buf, sizeof(buf), false, true); os << buf; return os; } } // namespace ucommon #endif #endif ucommon-6.4.4/inc/ucommon/object.h0000664000175000017500000003441212537554527014015 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * A common object base class with auto-pointer support. * A common object class is used which may be referenced counted and * associated with a smart auto-pointer class. A lot of the things * found here were inspired by working with Objective-C. Many of the * classes are designed to offer automatic heap management through * smart pointers and temporary objects controlled through the scope of * the stack frame of method calls. * @file ucommon/object.h */ #ifndef _UCOMMON_OBJECT_H_ #define _UCOMMON_OBJECT_H_ #ifndef _UCOMMON_CPR_H_ #include #endif #ifndef _UCOMMON_GENERICS_H_ #include #endif #ifndef _UCOMMON_PROTOCOLS_H_ #include #endif #include namespace ucommon { /** * A base class for reference counted objects. Reference counted objects * keep track of how many objects refer to them and fall out of scope when * they are no longer being referred to. This can be used to achieve * automatic heap management when used in conjunction with smart pointers. * @author David Sugar */ class __EXPORT CountedObject : public ObjectProtocol { private: volatile unsigned count; protected: /** * Construct a counted object, mark initially as unreferenced. */ CountedObject(); /** * Construct a copy of a counted object. Our instance is not a * reference to the original object but a duplicate, so we do not * retain the original and we do reset our count to mark as * initially unreferenced. */ CountedObject(const ObjectProtocol &ref); /** * Dealloc object no longer referenced. The dealloc routine would commonly * be used for a self delete to return the object back to a heap when * it is no longer referenced. */ virtual void dealloc(void); /** * Force reset of count. */ inline void reset(void) { count = 0; } public: /** * Test if the object has copied references. This means that more than * one object has a reference to our object. * @return true if referenced by more than one object. */ inline bool is_copied(void) const { return count > 1; } /** * Test if the object has been referenced (retained) by anyone yet. * @return true if retained. */ inline bool is_retained(void) const { return count > 0; } /** * Return the number of active references (retentions) to our object. * @return number of references to our object. */ inline unsigned copied(void) const { return count; } /** * Increase reference count when retained. */ void retain(void); /** * Decrease reference count when released. If no longer retained, then * the object is dealloc'd. */ void release(void); }; /** * A general purpose smart pointer helper class. This is particularly * useful in conjunction with reference counted objects which can be * managed and automatically removed from the heap when they are no longer * being referenced by a smart pointer. The smart pointer itself would * normally be constructed and initialized as an auto variable in a method * call, and will dereference the object when the pointer falls out of scope. * This is actually a helper class for the typed pointer template. * @author David Sugar */ class __EXPORT auto_object { protected: ObjectProtocol *object; auto_object(); public: /** * Construct an auto-pointer referencing an existing object. * @param object we point to. */ auto_object(ObjectProtocol *object); /** * Construct an auto-pointer as a copy of another pointer. The * retention of the object being pointed to will be increased. * @param pointer we are a copy of. */ auto_object(const auto_object &pointer); /** * Delete auto pointer. When it falls out of scope, the retention * of the object it references is reduced. If it falls to zero in * a reference counted object, then the object is auto-deleted. */ ~auto_object(); /** * Manually release the pointer. This reduces the retention level * of the object and resets the pointer to point to nobody. */ void release(void); /** * Test if the pointer is not set. * @return true if the pointer is not referencing anything. */ bool operator!() const; /** * Test if the pointer is referencing an object. * @return true if the pointer is currently referencing an object. */ operator bool() const; /** * test if the object being referenced is the same as the object we specify. * @param object we compare to. * @return true if this is the object our pointer references. */ bool operator==(ObjectProtocol *object) const; /** * test if the object being referenced is not the same as the object we specify. * @param object we compare to. * @return true if this is not the object our pointer references. */ bool operator!=(ObjectProtocol *object) const; /** * Set our pointer to a specific object. If the pointer currently * references another object, that object is released. The pointer * references our new object and that new object is retained. * @param object to assign to. */ void operator=(ObjectProtocol *object); }; /** * A sparse array of managed objects. This might be used as a simple * array class for reference counted objects. This class assumes that * objects in the array exist when assigned, and that gaps in the array * are positions that do not reference any object. Objects are automatically * created (create on access/modify when an array position is referenced * for the first time. This is an abstract class because it is a type * factory for objects who's derived class form constructor is not known * in advance and is a helper class for the sarray template. * @author David Sugar */ class __EXPORT SparseObjects { private: ObjectProtocol **vector; unsigned max; protected: /** * Object factory for creating members of the spare array when they * are initially requested. * @return new object. */ virtual ObjectProtocol *create(void) = 0; /** * Purge the array by deleting all created objects. */ void purge(void); virtual ObjectProtocol *invalid(void) const; /** * Get (reference) an object at a specified offset in the array. * @param offset in array. * @return new or existing object. */ ObjectProtocol *get(unsigned offset); /** * Create a sparse array of known size. No member objects are * created until they are referenced. * @param size of array. */ SparseObjects(unsigned size); /** * Destroy sparse array and delete all generated objects. */ virtual ~SparseObjects(); public: /** * Get count of array elements. * @return array elements. */ unsigned count(void); }; /** * Generate a typed sparse managed object array. Members in the array * are created when they are first referenced. The types for objects * that are generated by sarray must have Object as a base class. Managed * sparse arrays differ from standard arrays in that the member elements * are not allocated from the heap when the array is created, but rather * as they are needed. * @author David Sugar */ template class sarray : public SparseObjects { public: /** * Generate a sparse typed array of specified size. * @param size of array to create. */ inline sarray(unsigned size) : SparseObjects(size) {} /** * Get typed member of array. If the object does not exist, it is * created. * @param offset in array for object. * @return pointer to typed object. */ inline T *get(unsigned offset) { return static_cast(SparseObjects::get(offset)); } /** * Array operation to access member object. If the object does not * exist, it is created. * @param offset in array for object. * @return pointer to typed object. */ inline T& operator[](unsigned offset) { return reference_cast(get(offset)); } inline const T* at(unsigned offset) const { return immutable_cast(SparseObjects::get(offset)); } private: __LOCAL ObjectProtocol *create(void) { return new T; } }; /** * Template for embedding a data structure into a reference counted object. * This is a convenient means to create reference counted heap managed data * structure. This template can be used for embedding data into other kinds * of managed object classes in addition to reference counting. For example, * it can be used to embed a data structure into a linked list, as shown in * the linked_value template. * @author David Sugar */ template class object_value : public O { protected: /** * Assign our value from a typed data object. This is a helper method. * @param object to assign our value from. */ inline void set(const T& object) { value = object; } public: T value; /**< Embedded data value */ /** * Construct composite value object. */ inline object_value() : O(), value() {} /** * Construct composite value object and assign from existing data value. * @param existing typed value to assign. */ inline object_value(T& existing) : O() { value = existing; } /** * Pointer reference to embedded data value. * @return embedded value. */ inline T& operator*() { return value; } /** * Assign embedded data value. * @param data value to assign. */ inline void operator=(const T& data) { value = data; } /** * Retrieve data value by casting reference. * @return embedded value. */ inline operator T&() { return value; } inline T& operator()() { return value; } /** * Set data value by expression reference. * @param data value to assign. */ inline void operator()(T& data) { value = data; } }; /** * Typed smart pointer class. This is used to manage references to * a specific typed object on the heap that is derived from the base Object * class. This is most commonly used to manage references to reference * counted heap objects so their heap usage can be auto-managed while there * is active references to such objects. Pointers are usually created on * the stack frame and used to reference an object during the life of a * member function. They can be created in other objects that live on the * heap and can be used to maintain active references so long as the object * they are contained in remains in scope as well. * @author David Sugar */ template class object_pointer : public P { public: /** * Create a pointer with no reference. */ inline object_pointer() : P() {} /** * Create a pointer with a reference to a heap object. * @param object we are referencing. */ inline object_pointer(T* object) : P(object) {} /** * Reference object we are pointing to through pointer indirection. * @return pointer to object we are pointing to. */ inline T* operator*() const { return static_cast(P::object); } /** * Reference object we are pointing to through function reference. * @return object we are pointing to. */ inline T& operator()() const { return reference_cast(P::object); } /** * Reference member of object we are pointing to. * @return reference to member of pointed object. */ inline T* operator->() const { return static_cast(P::object); } /** * Get pointer to object. * @return pointer or NULL if we are not referencing an object. */ inline T* get(void) const { return static_cast(P::object); } /** * Iterate our pointer if we reference an array on the heap. * @return next object in array. */ inline T* operator++() { P::operator++(); return get(); } /** * Iterate our pointer if we reference an array on the heap. * @return previous object in array. */ inline void operator--() { P::operator--(); return get(); } /** * Perform assignment operator to existing object. * @param typed object to assign. */ inline void operator=(T *typed) { P::operator=(polypointer_cast(typed)); } /** * See if pointer is set. */ inline operator bool() const { return P::object != NULL; } /** * See if pointer is not set. */ inline bool operator!() const { return P::object == NULL; } }; /** * Convenience function to access object retention. * @param object we are retaining. */ inline void retain(ObjectProtocol *object) { object->retain(); } /** * Convenience function to access object release. * @param object we are releasing. */ inline void release(ObjectProtocol *object) { object->release(); } /** * Convenience function to access object copy. * @param object we are copying. */ inline ObjectProtocol *copy(ObjectProtocol *object) { return object->copy(); } } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/ucommon.h0000664000175000017500000001311612555173716014217 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Top level include file for the GNU uCommon C++ core library. * This is the only include file you need to have in your sources; it * includes the remaining header files. * @file ucommon/ucommon.h */ /** * @short A portable C++ threading library for embedded applications. * GNU uCommon C++ is meant as a very light-weight library to facilitate using * C++ design patterns even for very deeply embedded applications, such as for * systems using uclibc along with posix threading support. For this reason, * uCommon disables language features that consume memory or introduce runtime * overhead, such as rtti and exception handling, and assumes one will mostly * be linking applications with other pure C based libraries rather than using * the overhead of the standard C++ library and other class frameworks. * * uCommon by default does build with support for the bloated ansi standard c++ * library unless this is changed at configure time with the --disable-stdcpp * option. This is to assure maximum portability and will be used to merge * uCommon with GNU Common C++ to form GNU Common C++ 2.0. Some specific * features are tested for when stdc++ is enabled, and these will be used * to add back in GNU Common C++ classes such as TCP Stream and serialization. * * uCommon introduces some Objective-C based design patterns, such as reference * counted objects, memory pools, smart pointers, and offers dynamic typing * through very light use of inline templates for pure type translation that are * then tied to concrete base classes to avoid template instantiation issues. C++ * auto-variable automation is also used to enable referenced objects to be * deleted and threading locks to be released that are acquired automatically when * methods return rather than requiring one to explicitly code for these things. * * uCommon depends on and when necessary will introduce some portable C * replacement functions, especially for sockets, such as adding getaddrinfo for * platforms which do not have it, or when threadsafe versions of existing C * library functions are needed. Basic socket support for connecting to named * destinations and multicast addresses, and binding to interfaces with IPV4 and * IPV6 addresses is directly supported. Support for high resolution timing and * Posix realtime clocks are also used when available. * * uCommon builds all higher level thread synchronization objects directly from * conditionals. Hence, on platforms which for example do not have rwlocks, * barriers, or semaphores, these are still found in uCommon. A common and * consistent call methodology is used for all locks, whether mutex, rw, or * semaphore, based on whether used for exclusive or "shared" locking. * * uCommon requires some knowledge of compiler switches and options to disable * language features, the C++ runtime and stdlibs, and associated C++ headers. The * current version supports compiling with GCC, which is commonly found on * GNU/Linux, OS/X, BSD based systems, and many other platforms; and the Sun * Workshop compiler, which is offered as an example how to adapt uCommon for * additional compilers. uCommon may also be built with GCC cross compiling for * mingw32 to build threaded applications for Microsoft Windows targets nativiely. * * The minimum platform support for uCommon is a modern and working posix * pthread threading library. I further use a subset of posix threads to assure * wider portability by avoiding more specialized features like process shared * synchronization objects, pthread rwlocks and pthread semaphores, as these are * not implemented on all platforms that I have found. Finally, I have * eliminated the use of posix thread cancellation. * @author David Sugar * @license GNU Lesser General Public License Version 3 or later * @mainpage GNU uCommon C++ */ #ifndef _UCOMMON_UCOMMON_H_ #define _UCOMMON_UCOMMON_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef UCOMMON_SYSRUNTIME #include #include #include #endif #endif ucommon-6.4.4/inc/ucommon/cpr.h0000664000175000017500000001213512537554527013331 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Runtime functions. This includes common runtime library functions we * may need portably. * @file ucommon/cpr.h * @author David Sugar */ #ifndef _UCOMMON_CONFIG_H_ #include #endif #ifndef _UCOMMON_CPR_H_ #define _UCOMMON_CPR_H_ #ifdef _MSWINDOWS_ extern "C" { __EXPORT int cpr_setenv(const char *s, const char *v, int p); inline int setenv(const char *s, const char *v, int overwrite) { return cpr_setenv(s, v, overwrite); } } #endif /** * Function to handle runtime errors. When using the standard C library, * runtime errors are handled by a simple abort. When using the stdc++ * library with stdexcept, then std::runtime_error will be thrown. * @param text of runtime error. */ __EXPORT void cpr_runtime_error(const char *text); extern "C" __EXPORT void *cpr_newp(void **handle, size_t size); extern "C" __EXPORT void cpr_freep(void **handle); /** * Portable memory allocation helper function. Handles out of heap error * as a runtime error. * @param size of memory block to allocate from heap. * @return memory address of allocated heap space. */ extern "C" __EXPORT void *cpr_memalloc(size_t size) __MALLOC; /** * Portable memory placement helper function. This is used to process * "placement" new operators where a new object is constructed over a * pre-allocated area of memory. This handles invalid values through * runtime error. * @param size of object being constructed. * @param address where the object is being placed. * @param known size of the location we are constructing the object in. */ extern "C" __EXPORT void *cpr_memassign(size_t size, caddr_t address, size_t known) __MALLOC; /** * Portable swap code. * @param mem1 to swap. * @param mem2 to swap. * @param size of swap area. */ extern "C" __EXPORT void cpr_memswap(void *mem1, void *mem2, size_t size); #ifdef UCOMMON_SYSRUNTIME /** * Our generic new operator. Uses our heap memory allocator. * @param size of object being constructed. * @return memory allocated from heap. */ __EXPORT void *operator new(size_t size); /** * Our generic new array operator. Uses our heap memory allocator. * @param size of memory needed for object array. * @return memory allocated from heap. */ __EXPORT void *operator new[](size_t size); /** * A placement new array operator where we assume the size of memory is good. * We construct the array at a specified place in memory which we assume is * valid for our needs. * @param size of memory needed for object array. * @param address where to place object array. * @return memory we placed object array. */ __EXPORT void *operator new[](size_t size, void *address); /** * A placement new array operator where we know the allocated size. We * find out how much memory is needed by the new and can prevent arrayed * objects from exceeding the available space we are placing the object. * @param size of memory needed for object array. * @param address where to place object array. * @param known size of location we are placing array. * @return memory we placed object array. */ __EXPORT void *operator new[](size_t size, void *address, size_t known); /** * Delete an object from the heap. * @param object to delete. */ #if __cplusplus <= 199711L __EXPORT void operator delete(void *object); #else __EXPORT void operator delete(void *object) noexcept (true); #endif /** * Delete an array from the heap. All array element destructors are called. * @param array to delete. */ #if __cplusplus <= 199711L __EXPORT void operator delete[](void *array); #else __EXPORT void operator delete[](void *array) noexcept(true); #endif #ifdef __GNUC__ extern "C" __EXPORT void __cxa_pure_virtual(void); #endif #endif extern "C" { __EXPORT uint16_t lsb_getshort(uint8_t *b); __EXPORT uint32_t lsb_getlong(uint8_t *b); __EXPORT uint16_t msb_getshort(uint8_t *b); __EXPORT uint32_t msb_getlong(uint8_t *b); __EXPORT void lsb_setshort(uint8_t *b, uint16_t v); __EXPORT void lsb_setlong(uint8_t *b, uint32_t v); __EXPORT void msb_setshort(uint8_t *b, uint16_t v); __EXPORT void msb_setlong(uint8_t *b, uint32_t v); } template T *newp(T **handle) { return static_cast(cpr_newp(handle, sizeof(T))); } template void freep(T **handle) { cpr_freep(handle); } #endif ucommon-6.4.4/inc/ucommon/string.h0000664000175000017500000015373712544232270014053 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * A common string class and character string support functions. * Ucommon offers a simple string class that operates through copy-on-write * when needing to expand buffer size. Derived classes and templates allows * one to create strings which live entirely in the stack frame rather * than using the heap. This offers the benefit of the string class * manipulative members without compromising performance or locking issues * in threaded applications. Other things found here include better and * safer char array manipulation functions. * @file ucommon/string.h */ /** * An example of the string class. * @example string.cpp */ #ifndef _UCOMMON_STRING_H_ #define _UCOMMON_STRING_H_ #ifndef _UCOMMON_CPR_H_ #include #endif #ifndef _UCOMMON_GENERICS_H_ #include #endif #ifndef _UCOMMON_PROTOCOLS_H_ #include #endif #ifndef _UCOMMON_OBJECT_H_ #include #endif #include #include #include #ifdef HAVE_DIRENT_H #include #endif #define PGP_B64_WIDTH 64 #define MIME_B64_WIDTH 76 namespace ucommon { /** * A convenience class for size of strings. */ typedef unsigned short strsize_t; /** * A copy-on-write string class that operates by reference count. This string * class anchors a counted object that is managed as a copy-on-write * instance of the string data. This means that multiple instances of the * string class can refer to the same string in memory if it has not been * modifed, which reduces heap allocation. The string class offers functions * to manipulate both the string object, and generic safe string functions to * manipulate ordinary null terminated character arrays directly in memory. * @author David Sugar */ class __EXPORT String : public ObjectProtocol { protected: /** * This is an internal class which contains the actual string data * along with some control fields. The string can be either NULL * terminated or filled like a Pascal-style string, but with a user * selected fill character. The cstring object is an overdraft * object, as the actual string text which is of unknown size follows * immediately after the class control data. This class is primarily * for internal use. * @author David Sugar */ public: enum { SENSITIVE = 0x00, INSENSITIVE = 0x01 }; class __EXPORT regex { private: void *object; void *results; size_t count; public: regex(const char *pattern, size_t size = 1); regex(size_t size = 1); ~regex(); size_t offset(unsigned member); size_t size(unsigned member); inline size_t members(void) const {return count;} bool match(const char *text, unsigned flags = 0); regex& operator=(const char *string); bool operator*=(const char *string); operator bool() const {return object != NULL;} bool operator!() const {return object == NULL;} }; class __EXPORT cstring : public CountedObject { protected: void dealloc(void); public: #pragma pack(1) strsize_t max; /**< Allocated size of cstring text */ strsize_t len; /**< Current length of cstring text */ char fill; /**< Filler character or 0 for none */ char text[1]; /**< Null terminated text, in overdraft space */ #pragma pack() /** * Create a cstring node allocated for specified string size. The * new operator would also need the size as an overdraft value. * @param size of string. */ cstring(strsize_t size); /** * Create a filled cstring node allocated for specified string size. * The new operator would also need the size as an overdraft value. * The newly allocated string is filled with the fill value. * @param size of string. * @param fill character value to fill string with. */ cstring(strsize_t size, char fill); /** * Used to clear a string. If null terminated, then the string ends * at the offset, otherwise it is simply filled with fill data up to * the specified size. * @param offset to clear from. * @param size of field to clear. */ void clear(strsize_t offset, strsize_t size); /** * Set part or all of a string with new text. * @param offset to set from. * @param text to insert from null terminated string. * @param size of field to modify. This is filled for fill mode. */ void set(strsize_t offset, const char *text, strsize_t size); /** * Set our string from null terminated text up to our allocated size. * @param text to set from. */ void set(const char *text); /** * Append null terminated text to our string buffer. * @param text to append. */ void add(const char *text); /** * Append a single character to our string buffer. * @param character to append. */ void add(char character); /** * Fill our string buffer to end if fill mode. */ void fix(void); /** * Trim filler at end to reduce filled string to null terminated * string for further processing. */ void unfix(void); /** * Adjust size of our string buffer by deleting characters from * start of buffer. * @param number of characters to delete. */ void inc(strsize_t number); /** * Adjust size of our string buffer by deleting characters from * end of buffer. * @param number of characters to delete. */ void dec(strsize_t number); }; protected: cstring *str; /**< cstring instance our object references. */ /** * Factory create a cstring object of specified size. * @param size of allocated space for string buffer. * @param fill character to use or 0 if null. * @return new cstring object. */ cstring *create(strsize_t size, char fill = 0) const; public: /** * Compare the values of two string. This is a virtual so that it * can be overridden for example if we want to create strings which * ignore case, or which have special ordering rules. * @param string to compare with. * @return 0 if equal, <0 if less than, 0> if greater than. */ virtual int compare(const char *string) const; inline int collate(const char *string) const {return compare(string);} protected: /** * Test if two string values are equal. * @param string to compare with. * @return true if equal. */ bool equal(const char *string) const; /** * Increase retention of our reference counted cstring. May be overridden * for memstring which has fixed cstring object. */ virtual void retain(void); /** * Decrease retention of our reference counted cstring. May be overridden * for memstring which has fixed cstring object. */ virtual void release(void); /** * Return cstring to use in copy constructors. Is virtual for memstring. * @return cstring for copy constructor. */ virtual cstring *c_copy(void) const; /** * Copy on write operation for cstring. This always creates a new * unique copy for write/modify operations and is a virtual for memstring * to disable. * @param size to add to allocated space when creating new cstring. */ virtual void cow(strsize_t size = 0); strsize_t getStringSize(void) const; public: #if _MSC_VER > 1400 // windows broken dll linkage issue... const static strsize_t npos = ((strsize_t)-1); const static char eos = '\0'; #else static const strsize_t npos; static const char eos; #endif /** * Create a new empty string object. */ String(); /** * Create a string from a long integer. * @param value to convert to string. */ String(long value); /** * Create a string from a floating point. * @param value to convert to string. */ String(double value); /** * Create an empty string with a buffer pre-allocated to a specified size. * @param size of buffer to allocate. */ String(strsize_t size); /** * Create a filled string with a buffer pre-allocated to a specified size. * @param size of buffer to allocate. * @param fill character to use. */ String(strsize_t size, char fill); /** * Create a string by printf-like formating into a pre-allocated space * of a specified size. A typical use might be in a concat function * like String x = (String)something + (String){10, "%ud", var}. * @param size of buffer to allocate. * @param format control for string. */ String(strsize_t size, const char *format, ...) __PRINTF(3, 4); /** * Create a string from null terminated text. * @param text to use for string. */ String(const char *text); /** * Create a string from null terminated text up to a maximum specified * size. * @param text to use for string. * @param size limit of new string. */ String(const char *text, strsize_t size); /** * Create a string for a substring. The end of the substring is a * pointer within the substring itself. * @param text to use for string. * @param end of text in substring. */ String(const char *text, const char *end); /** * Construct a copy of a string object. Our copy inherets the same * reference counted instance of cstring as in the original. * @param existing string to copy from. */ String(const String& existing); /** * Destroy string. De-reference cstring. If last reference to cstring, * then also remove cstring from heap. */ virtual ~String(); /** * Get a new string object as a substring of the current object. * @param offset of substring. * @param size of substring or 0 if to end. * @return string object holding substring. */ String get(strsize_t offset, strsize_t size = 0) const; /** * Scan input items from a string object. * @param format string of input to scan. * @return number of items scanned. */ int scanf(const char *format, ...) __SCANF(2, 3); /** * Scan input items from a string object. * @param format string of input to scan. * @param args list to scan into. * @return number of items scanned. */ int vscanf(const char *format, va_list args) __SCANF(2, 0); /** * Print items into a string object. * @param format string of print format. * @return number of bytes written to string. */ strsize_t printf(const char *format, ...) __PRINTF(2, 3); /** * Print items into a string object. * @param format string of print format. * @param args list to print. * @return number of bytes written to string. */ strsize_t vprintf(const char *format, va_list args) __PRINTF(2, 0); /** * Get memory text buffer of string object. * @return writable string buffer. */ char *c_mem(void) const; /** * Get character text buffer of string object. * @return character text buffer. */ const char *c_str(void) const; /** * Resize and re-allocate string memory. * @param size to allocate for string. * @return true if re-allocated. False in derived memstring. */ virtual bool resize(strsize_t size); /** * Set string object to text of a null terminated string. * @param text string to set. */ void set(const char *text); /** * Set a portion of the string object at a specified offset to a text * string. * @param offset in object string buffer. * @param text to set at offset. * @param size of text area to set or 0 until end of text. */ void set(strsize_t offset, const char *text, strsize_t size = 0); /** * Set a text field within our string object. * @param text to set. * @param overflow character to use as filler if text is too short. * @param offset in object string buffer to set text at. * @param size of part of buffer to set with text and overflow. */ void set(const char *text, char overflow, strsize_t offset, strsize_t size = 0); /** * Set a text field within our string object offset from the end of buffer. * @param text to set. * @param overflow character to use as filler if text is too short. * @param offset from end of object string buffer to set text at. * @param size of part of buffer to set with text and overflow. */ void rset(const char *text, char overflow, strsize_t offset, strsize_t size = 0); /** * Append null terminated text to our string buffer. * @param text to append. */ void add(const char *text); /** * Append a single character to our string buffer. * @param character to append. */ void add(char character); /** * Trim lead characters from the string. * @param list of characters to remove. */ void trim(const char *list); /** * Trim lead characters from text. * @param count of characters to remove. */ inline void trim(strsize_t count = 1) {operator+=(count);} /** * Chop trailing characters from the string. * @param list of characters to remove. */ void chop(const char *list); /** * Chop trailing characters from text. * @param count of characters to remove. */ inline void chop(strsize_t count = 1) {operator-=(count);} /** * Strip lead and trailing characters from the string. * @param list of characters to remove. */ void strip(const char *list); /** * Unquote a quoted string. Removes lead and trailing quote marks. * @param quote pairs of characters for open and close quote. * @return true if string was quoted. */ bool unquote(const char *quote); /** * Cut (remove) text from string. * @param offset to start of text field to remove. * @param size of text field to remove or 0 to remove to end of string. */ void cut(strsize_t offset, strsize_t size = 0); /** * Insert (paste) text into string. * @param offset to start paste. * @param text to paste. * @param size of text to paste. */ void paste(strsize_t offset, const char *text, strsize_t size = 0); /** * Clear a field of a filled string with filler. * @param offset to start of field to clear. * @param size of field to fill or 0 to fill to end of string. */ void clear(strsize_t offset, strsize_t size = 0); /** * Clear string by setting to empty. */ void clear(void); /** * Convert string to upper case. */ void upper(void); /** * Convert string to lower case. */ void lower(void); /** * Erase string memory. */ void erase(void); /** * Count number of occurrences of characters in string. * @param list of characters to find. * @return count of instances of characters in string. */ strsize_t ccount(const char *list) const; /** * Count all characters in the string (strlen). * @return count of characters. */ strsize_t count(void) const; /** * Get the size of currently allocated space for string. * @return size allocated for text. */ strsize_t size(void) const; /** * Find offset of a pointer into our string buffer. This can be used * to find the offset position of a pointer returned by find, for * example. This is used when one needs to convert a member function * that returns a pointer to call a member function that operates by * a offset value. If the pointer is outside the range of the string * then npos is returned. * @param pointer into our object's string buffer. */ strsize_t offset(const char *pointer) const; /** * Return character found at a specific position in the string. * @param position in string, negative values computed from end. * @return character code at specified position in string. */ char at(int position) const; /** * Get pointer to first character in string for iteration. * @return first character pointer or NULL if empty. */ const char *begin(void) const; /** * Get pointer to last character in string for iteration. * @return last character pointer or NULL if empty. */ const char *end(void) const; /** * Skip lead characters in the string. * @param list of characters to skip when found. * @param offset to start of scan. * @return pointer to first part of string past skipped characters. */ const char *skip(const char *list, strsize_t offset = 0) const; /** * Skip trailing characters in the string. This searches the * string in reverse order. * @param list of characters to skip when found. * @param offset to start of scan. Default is end of string. * @return pointer to first part of string before skipped characters. */ const char *rskip(const char *list, strsize_t offset = npos) const; /** * Search for a substring in the string. * @param substring to search for. * @param flags for case insensitive search. */ const char *search(const char *string, unsigned instance = 0, unsigned flags = 0) const; const char *search(regex& expr, unsigned instance = 0, unsigned flags = 0) const; unsigned replace(const char *string, const char *text = NULL, unsigned flags = 0); unsigned replace(regex& expr, const char *text = NULL, unsigned flags = 0); /** * Find a character in the string. * @param list of characters to search for. * @param offset to start of search. * @return pointer to first occurrence of character. */ const char *find(const char *list, strsize_t offset = 0) const; /** * Find last occurrence of character in the string. * @param list of characters to search for. * @param offset to start of search. Default is end of string. * @return pointer to last occurrence of character. */ const char *rfind(const char *list, strsize_t offset = npos) const; /** * Split the string by a pointer position. Everything after the pointer * is removed. * @param pointer to split position in string. */ void split(const char *pointer); /** * Split the string at a specific offset. Everything after the offset * is removed. * @param offset to split position in string. */ void split(strsize_t offset); /** * Split the string by a pointer position. Everything before the pointer * is removed. * @param pointer to split position in string. */ void rsplit(const char *pointer); /** * Split the string at a specific offset. Everything before the offset * is removed. * @param offset to split position in string. */ void rsplit(strsize_t offset); /** * Find pointer in string where specified character appears. * @param character to find. * @return string pointer for character if found, NULL if not. */ const char *chr(char character) const; /** * Find pointer in string where specified character last appears. * @param character to find. * @return string pointer for last occurrence of character if found, * NULL if not. */ const char *rchr(char character) const; /** * Get length of string. * @return length of string. */ strsize_t len(void) const; /** * Get filler character used for field array strings. * @return filler character or 0 if none. */ char fill(void); /** * Casting reference to raw text string. * @return null terminated text of string. */ inline operator const char *() const {return c_str();} /** * Reference raw text buffer by pointer operator. * @return null terminated text of string. */ inline const char *operator*() const {return c_str();} /** * Test if the string's allocated space is all used up. * @return true if no more room for append. */ bool full(void) const; /** * Get a new substring through object expression. * @param offset of substring. * @param size of substring or 0 if to end. * @return string object holding substring. */ String operator()(int offset, strsize_t size) const; /** * Convenience method for left of string. * @param size of substring to gather. * @return string object holding substring. */ inline String left(strsize_t size) const {return operator()(0, size);} /** * Convenience method for right of string. * @param offset of substring from right. * @return string object holding substring. */ inline String right(strsize_t offset) const {return operator()(-((int)offset), 0);} /** * Convenience method for substring extraction. * @param offset into string. * @param size of string to return. * @return string object holding substring. */ inline String copy(strsize_t offset, strsize_t size) const {return operator()((int)offset, size);} /** * Reference a string in the object by relative offset. Positive * offsets are from the start of the string, negative from the * end. * @param offset to string position. * @return pointer to string data or NULL if invalid offset. */ const char *operator()(int offset) const; /** * Reference a single character in string object by array offset. * @param offset to character. * @return character value at offset. */ const char operator[](int offset) const; /** * Test if string is empty. * @return true if string is empty. */ bool operator!() const; /** * Test if string has data. * @return true if string has data. */ operator bool() const; /** * Create new cow instance and assign value from another string object. * @param object to assign from. * @return our object for expression use. */ String& operator^=(const String& object); /** * Concatenate text to an existing string object. This will use the * old behavior when +/= updated. */ String& operator|=(const char *text); String& operator&=(const char *text); /** * Concatenate text to an existing string object. * @param text to add. * @return our object for expression use. */ String& operator+=(const char *text); /** * Create new cow instance and assign value from null terminated text. * @param text to assign from. * @return our object for expression use. */ String& operator^=(const char *text); /** * Concatenate null terminated text to our object. * @param text to concatenate. */ String operator+(const char *text); /** * Concatenate null terminated text to our object. This creates a new * copy-on-write instance to hold the concatenated string. This will * eventually replace '+' when + creates a new string instance instead. * @param text to concatenate. */ String& operator|(const char *text); /** * Concatenate null terminated text to our object. This directly * appends the text to the string buffer and does not resize the * object if the existing cstring allocation space is fully used. * @param text to concatenate. */ String& operator&(const char *text); /** * Assign our string with the cstring of another object. If we had * an active string reference, it is released. The object now has * a duplicate reference to the cstring of the other object. * @param object to assign from. */ String& operator=(const String& object); bool operator*=(const char *substring); bool operator*=(regex& expr); /** * Assign text to our existing buffer. This performs a set method. * @param text to assign from. */ String& operator=(const char *text); /** * Delete first character from string. */ String& operator++(void); /** * Delete a specified number of characters from start of string. * @param number of characters to delete. */ String& operator+=(strsize_t number); /** * Delete last character from string. */ String& operator--(void); /** * Delete a specified number of characters from end of string. * @param number of characters to delete. */ String& operator-=(strsize_t number); /** * Delete a specified number of characters from start of string. * @param number of characters to delete. */ String& operator*=(strsize_t number); /** * Compare our object with null terminated text. * @param text to compare with. * @return true if we are equal. */ bool operator==(const char *text) const; /** * Compare our object with null terminated text. Compare method is used. * @param text to compare with. * @return true if we are not equal. */ bool operator!=(const char *text) const; /** * Compare our object with null terminated text. Compare method is used. * @param text to compare with. * @return true if we are less than text. */ bool operator<(const char *text) const; /** * Compare our object with null terminated text. Compare method is used. * @param text to compare with. * @return true if we are less than or equal to text. */ bool operator<=(const char *text) const; /** * Compare our object with null terminated text. Compare method is used. * @param text to compare with. * @return true if we are greater than text. */ bool operator>(const char *text) const; /** * Compare our object with null terminated text. Compare method is used. * @param text to compare with. * @return true if we are greater than or equal to text. */ bool operator>=(const char *text) const; inline String& operator<<(const char *text) {add(text); return *this;} inline String& operator<<(char code) {add(code); return *this;} /** * Parse short integer value from a string. * @param value to store. * @return object in expression. */ String &operator%(short& value); /** * Parse long integer value from a string. * @param value to store. * @return object in expression. */ String &operator%(unsigned short& value); /** * Parse long integer value from a string. * @param value to store. * @return object in expression. */ String &operator%(long& value); /** * Parse long integer value from a string. * @param value to store. * @return object in expression. */ String &operator%(unsigned long& value); /** * Parse double value from a string. * @param value to store. * @return object in expression. */ String &operator%(double& value); /** * Parse text from a string in a scan expression. * @param text to scan and bypass. * @return object in expression. */ String &operator%(const char *text); /** * Swap the cstring references between two strings. * @param object1 to swap. * @param object2 to swap. */ static void swap(String& object1, String& object2); /** * Fix and reset string object filler. * @param object to fix. */ static void fix(String& object); /** * Check if string is valid and in specific constraints. * @param string to check. * @param maximum size allowed. * @param minimum size required. * @return true if string is valid. */ static bool check(const char *string, size_t maximum, size_t minimum = 0); /** * Erase string memory. Often used to clear out passwords. * @param text string to erase. */ static void erase(char *text); /** * Convert null terminated text to lower case. * @param text to convert. */ static void lower(char *text); /** * Convert null terminated text to upper case. * @param text to convert. */ static void upper(char *text); /** * A thread-safe token parsing routine for null terminated strings. This * is related to strtok, but with safety checks for NULL values and a * number of enhancements including support for quoted text that may * contain token separators within quotes. The text string is modified * as it is parsed. * @param text string to examine for tokens. * @param last token position or set to NULL for start of string. * @param list of characters to use as token separators. * @param quote pairs of characters for quoted text or NULL if not used. * @param end of line marker characters or NULL if not used. * @return token extracted from string or NULL if no more tokens found. */ static char *token(char *text, char **last, const char *list, const char *quote = NULL, const char *end = NULL); /** * Skip after lead characters in a null terminated string. * @param text pointer to start at. * @param list of characters to skip when found. * @return pointer to first part of string past skipped characters. */ static char *skip(char *text, const char *list); /** * Skip before trailing characters in a null terminated string. * @param text pointer to start at. * @param list of characters to skip when found. * @return pointer to last part of string past skipped characters. */ static char *rskip(char *text, const char *list); /** * Unquote a quoted null terminated string. Returns updated string * position and replaces trailing quote with null byte if quoted. * @param text to examine. * @param quote pairs of character for open and close quote. * @return new text pointer if quoted, NULL if unchanged. */ static char *unquote(char *text, const char *quote); /** * Set a field in a null terminated string relative to the end of text. * @param buffer to modify. * @param size of field to set. * @param text to replace end of string with. * @return pointer to text buffer. */ static char *rset(char *buffer, size_t size, const char *text); /** * Safely set a null terminated string buffer in memory. If the text * is too large to fit into the buffer, it is truncated to the size. * @param buffer to set. * @param size of buffer. Includes null byte at end of string. * @param text to set in buffer. * @return pointer to text buffer. */ static char *set(char *buffer, size_t size, const char *text); /** * Safely set a null terminated string buffer in memory. If the text * is too large to fit into the buffer, it is truncated to the size. * @param buffer to set. * @param size of buffer. Includes null byte at end of string. * @param text to set in buffer. * @param max size of text to set. * @return pointer to text buffer. */ static char *set(char *buffer, size_t size, const char *text, size_t max); /** * Safely append a null terminated string into an existing string in * memory. If the resulting string is too large to fit into the buffer, * it is truncated to the size. * @param buffer to set. * @param size of buffer. Includes null byte at end of string. * @param text to set in buffer. * @return pointer to text buffer. */ static char *add(char *buffer, size_t size, const char *text); /** * Safely append a null terminated string into an existing string in * memory. If the resulting string is too large to fit into the buffer, * it is truncated to the size. * @param buffer to set. * @param size of buffer. Includes null byte at end of string. * @param text to set in buffer. * @param max size of text to append. * @return pointer to text buffer. */ static char *add(char *buffer, size_t size, const char *text, size_t max); /** * Find position of case insensitive substring within a string. * @param text to search in. * @param key string to locate. * @param optional separator chars if formatted as list of keys. * @return substring position if found, or NULL. */ static const char *ifind(const char *text, const char *key, const char *optional); /** * Find position of substring within a string. * @param text to search in. * @param key string to locate. * @param optional separator chars if formatted as list of keys. * @return substring position if found, or NULL. */ static const char *find(const char *text, const char *key, const char *optional); /** * Safe version of strlen function. Accepts NULL as 0 length strings. * @param text string. * @return length of string. */ static size_t count(const char *text); /** * Safe string collation function. * @param text1 to compare. * @param text2 to compare. * @return 0 if equal, >0 if text1 > text2, <0 if text1 < text2. */ static int compare(const char *text1, const char *text2); static inline int collate(const char *text1, const char *text2) {return compare(text1, text2);} /** * Simple equal test for strings. * @param text1 to test. * @param text2 to test. * @return true if equal and case is same. */ static bool equal(const char *text1, const char *text2); /** * Depreciated string comparison function. * @param text1 to compare. * @param text2 to compare. * @param size limit of strings to compare. * @return 0 if equal, >0 if text1 > text2, <0 if text1 < text2. */ static int compare(const char *text1, const char *text2, size_t size); /** * Simple equal test for strings. * @param text1 to test. * @param text2 to test. * @param size limit of strings to compare. * @return true if equal and case is same. */ static bool equal(const char *text1, const char *text2, size_t size); /** * Depreciated case insensitive string comparison function. * @param text1 to compare. * @param text2 to compare. * @return 0 if equal, >0 if text1 > text2, <0 if text1 < text2. */ static int case_compare(const char *text1, const char *text2); /** * Simple case insensitive equal test for strings. * @param text1 to test. * @param text2 to test. * @return true if equal. */ static bool eq_case(const char *text1, const char *text2); /** * Depreciated case insensitive string comparison function. * @param text1 to compare. * @param text2 to compare. * @param size limit of strings to compare. * @return 0 if equal, >0 if text1 > text2, <0 if text1 < text2. */ static int case_compare(const char *text1, const char *text2, size_t size); /** * Simple case insensitive equal test for strings. * @param text1 to test. * @param text2 to test. * @param size limit of strings to compare. * @return true if equal. */ static bool eq_case(const char *text1, const char *text2, size_t size); /** * Return start of string after characters to trim from beginning. * This function does not modify memory. * @param text buffer to examine. * @param list of characters to skip from start. * @return position in text past lead trim. */ static char *trim(char *text, const char *list); /** * Strip trailing characters from the text string. This function will * modify memory. * @param text buffer to examine. * @param list of characters to chop from trailing end of string. * @return pointer to text buffer. */ static char *chop(char *text, const char *list); /** * Skip lead and remove trailing characters from a text string. This * function will modify memory. * @param text buffer to examine. * @param list of characters to trim and chop. * @return position in text past lead trim. */ static char *strip(char *text, const char *list); /** * Fill a section of memory with a fixed text character. Adds a null * byte at the end. * @param text buffer to fill. * @param size of text buffer with null terminated byte. * @param character to fill with. * @return pointer to text buffer. */ static char *fill(char *text, size_t size, char character); /** * Count instances of characters in a list in a text buffer. * @param text buffer to examine. * @param list of characters to count in buffer. * @return number of instances of the characters in buffer. */ static unsigned ccount(const char *text, const char *list); /** * Find the first occurrence of a character in a text buffer. * @param text buffer to examine. * @param list of characters to search for. * @return pointer to first instance found or NULL. */ static char *find(char *text, const char *list); /** * Offset until next occurrence of character in a text or length. * @param text buffer to examine. * @param list of characters to search for. * @return offset to next occurrence or length of string. */ static size_t seek(char *text, const char *list); /** * Find the last occurrence of a character in a text buffer. * @param text buffer to examine. * @param list of characters to search for. * @return pointer to last instance found or NULL. */ static char *rfind(char *text, const char *list); /** * Duplicate null terminated text into the heap. * @param text to duplicate. * @return duplicate copy of text allocated from heap. */ static char *dup(const char *text); /** * Duplicate null terminated text of specific size to heap. * @param text to duplicate. * @param size of text, maximum space allocated. * @return duplicate copy of text allocated on heap. */ static char *left(const char *text, size_t size); /** * Compute position in string. * @param text of string. * @param offset from start, negative values from end. * @return pointer to string position. */ static const char *pos(const char *text, ssize_t offset); inline static char *right(const char *text, size_t size) {return dup(pos(text, -(ssize_t)size));} inline static char *copy(const char *text, size_t offset, size_t len) {return left(pos(text, (ssize_t)offset), len);} static void cut(char *text, size_t offset, size_t len); static void paste(char *text, size_t max, size_t offset, const char *data, size_t len = 0); /** * A thread-safe token parsing routine for strings objects. This * is related to strtok, but with safety checks for NULL values and a * number of enhancements including support for quoted text that may * contain token separators within quotes. The object is modified * as it is parsed. * @param last token position or set to NULL for start of string. * @param list of characters to use as token separators. * @param quote pairs of characters for quoted text or NULL if not used. * @param end of line marker characters or NULL if not used. * @return token extracted from string or NULL if no more tokens found. */ inline char *token(char **last, const char *list, const char *quote = NULL, const char *end = NULL) {return token(c_mem(), last, list, quote, end);} /** * Convert string to a double value. * @param object to convert. * @param pointer to update with end of parsed value. * @return double value of object. */ inline double tod(char **pointer = NULL) {return strtod(c_mem(), pointer);} /** * Convert string to a long value. * @param object to convert. * @param pointer to update with end of parsed value. * @return long value of object. */ inline long tol(char **pointer = NULL) {return strtol(c_mem(), pointer, 0);} /** * Convert text to a double value. * @param text to convert. * @param pointer to update with end of parsed value. * @return double value of object. */ inline static double tod(const char *text, char **pointer = NULL) {return strtod(text, pointer);} /** * Convert text to a long value. * @param text to convert. * @param pointer to update with end of parsed value. * @return long value of object. */ inline static long tol(const char *text, char **pointer = NULL) {return strtol(text, pointer, 0);} /** * Standard radix 64 string encoding. * @param binary data to encode. * @param size of binary data to encode. * @return encoded string. */ static String b64(const uint8_t *binary, size_t size); /** * Standard radix 64 encoding. * @param string of encoded text save into. * @param binary data to encode. * @param size of binary data to encode. * @param width of string buffer for data if partial supported. * @return number of bytes encoded. */ static size_t b64encode(char *string, const uint8_t *binary, size_t size, size_t width = 0); /** * Standard radix 64 decoding. * @param binary data to save. * @param string of encoded text. * @param size of destination buffer. * @return number of bytes actually decoded. */ static size_t b64decode(uint8_t *binary, const char *string, size_t size); /** * 24 bit crc as used in openpgp. * @param binary data to sum. * @param size of binary data to sum. * @return 24 bit crc of data. */ static uint32_t crc24(uint8_t *binary, size_t size); /** * ccitt 16 bit crc for binary data. * @param binary data to sum. * @param size of binary data to sum. * @return 16 bit crc. */ static uint16_t crc16(uint8_t *binary, size_t size); /** * Convert binary data buffer into hex string. * @param binary data to convert. * @param size of data. * @return string from data. */ static String hex(const unsigned char *binary, size_t size); /** * Dump hex data to a string buffer. * @param binary memory to dump. * @param string to save into. * @param format string to convert with. * @return number of bytes processed. */ static unsigned hexdump(const unsigned char *binary, char *string, const char *format); /** * Pack hex data from a string buffer. * @param binary memory to pack. * @param string to save into. * @param format string to convert with. * @return number of bytes processed. */ static unsigned hexpack(unsigned char *binary, const char *string, const char *format); static unsigned hexsize(const char *format); }; /** * A string class that uses a cstring buffer that is fixed in memory. * This allows one to manipulate a fixed buffer of text in memory through * the string class. The size of the memory used must include space for * the overhead() size needed for the cstring object control data. * @author David Sugar */ class __EXPORT memstring : public String { public: #if _MSC_VER > 1400 // windows broken dll linkage issue... const static size_t header = sizeof(String::cstring); #else static const size_t header; #endif private: bool resize(strsize_t size); void cow(strsize_t adj = 0); void release(void); protected: cstring *c_copy(void) const; public: /** * Assign the text of a string to our object. * @param object to copy text from. */ inline void operator=(String& object) {set(object.c_str());} /** * Assign null terminated text to our object. * @param text to copy. */ inline void operator=(const char *text) {set(text);} /** * Create an instance of a memory string. * @param memory to use for cstring object. * @param size of string. Total size must include space for overhead. * @param fill character for fixed character fields. */ memstring(void *memory, strsize_t size, char fill = 0); /** * Destroy memory string. */ ~memstring(); /** * Create a memory string with memory allocated from the heap. * @param size of string to allocate. Automatically adds control size. * @param fill character for fixed field strings. */ static memstring *create(strsize_t size, char fill = 0); /** * Create a memory string with memory allocated from a pager. * @param pager to allocate memory from. * @param size of string to allocate. Automatically adds control size. * @param fill character for fixed field strings. */ static memstring *create(MemoryProtocol *pager, strsize_t size, char fill = 0); }; /** * A template to create a character array that can be manipulated as a string. * This is a mini string/stringbuf class that supports a subset of * functionality but does not require a complex supporting object. Like * stringbuf, this can be used to create local string variables. * @author David Sugar */ template class charbuf { private: char buffer[S]; public: /** * Create a new character buffer with an empty string. */ inline charbuf() {buffer[0] = 0;} /** * Create a character buffer with assigned text. If the text is * larger than the size of the object, it is truncated. * @param text to assign. */ inline charbuf(const char *text) {String::set(buffer, S, text);} /** * Copy constructor. */ inline charbuf(const charbuf& copy) {String::set(buffer, S, copy.buffer);} /** * Assign null terminated text to the object. * @param text to assign. */ inline void operator=(const char *text) {String::set(buffer, S, text);} /** * Concatenate text into the object. If the text is larger than the * size of the object, then it is truncated. * @param text to append. */ inline void operator+=(const char *text) {String::add(buffer, S, text);} /** * Test if data is contained in the object. * @return true if there is text. */ inline operator bool() const {return buffer[0];} /** * Test if the object is empty. * @return true if the object is empty. */ inline bool operator!() const {return buffer[0] == 0;} /** * Get text by casting reference. * @return pointer to text in object. */ inline operator char *() {return buffer;} /** * Get text by object pointer reference. * @return pointer to text in object. */ inline char *operator*() {return buffer;} /** * Array operator to get a character from the object. * @param offset of character in string buffer. * @return character at offset. */ inline char& operator[](size_t offset) const {return buffer[offset];} /** * Get a pointer to an offset in the object by expression operator. * @param offset of character in string buffer. * @return pointer to offset in object. */ inline char *operator()(size_t offset) {return buffer + offset;} /** * Get allocated size of the object. * @return allocated size. */ inline size_t size(void) const {return S;} /** * Get current length of string. * @return length of string. */ inline size_t len(void) const {return strlen(buffer);} }; /** * A convenience type for string. */ typedef String string_t; typedef String::regex stringex_t; /** * A string class that has a predefined string buffer. The string class * and buffer are allocated together as one object. This allows one to use * string objects entirely resident on the local stack as well as on the * heap. Using a string class on the local stack may be more convenient * than a char array since one can use all the features of the class * including assignment and concatenation which a char buffer cannot as * easily do. * @author David Sugar */ template class stringbuf : public memstring { private: char buffer[sizeof(cstring) + S]; public: /** * Create an empty instance of a string buffer. */ inline stringbuf() : memstring(buffer, S) {} /** * Create a string buffer from a null terminated string. * @param text to place in object. */ inline stringbuf(const char *text) : memstring(buffer, S) {set(text);} /** * Assign a string buffer from a null terminated string. * @param text to assign to object. */ inline void operator=(const char *text) {set(text);} /** * Assign a string buffer from another string object. * @param object to assign from. */ inline void operator=(String& object) {set(object.c_str());} }; #if !defined(_MSWINDOWS_) && !defined(__QNX__) #ifndef stricmp #define stricmp(x,y) String::case_compare(x,y) #endif #ifndef strnicmp #define strnicmp(x,y,z) String::case_compare(x,y,z) #endif #endif /** * Compare two null terminated strings if equal. * @param s1 string to compare. * @param s2 string to compare. * @return true if equal. */ inline bool eq(char const *s1, char const *s2) {return String::equal(s1, s2);} inline bool ne(char const *s1, char const *s2) {return !String::equal(s1, s2);} /** * Compare two null terminated strings if equal up to specified size. * @param s1 string to compare. * @param s2 string to compare. * @param size of string to compare. * @return true if equal. */ inline bool eq(char const *s1, char const *s2, size_t size) {return String::equal(s1, s2, size);} inline bool ne(char const *s1, char const *s2, size_t size) {return !String::equal(s1, s2, size);} /** * Compare two string objects if equal. The left string is an object, * the right may be an object or converted to a const string. The * compare virtual method of the left object is used, so we can do * things like collation order or derived class specific sorting. * @param s1 string to compare. * @param s2 string to compare. * @return true if equal. */ inline bool eq(String &s1, const char *s2) {return s1.compare(s2) == 0;} inline bool ne(String &s1, String &s2) {return s1.compare(s2) != 0;} inline bool lt(String &s1, const char *s2) {return s1.compare(s2) < 0;} inline bool gt(String &s1, const char *s2) {return s1.compare(s2) > 0;} inline bool le(String &s1, const char *s2) {return s1.compare(s2) <= 0;} inline bool ge(String &s1, const char *s2) {return s1.compare(s2) >= 0;} /** * Compare two null terminated strings if equal ignoring case. This is * related to stricmp or gcc strcasecmp. * @param s1 string to compare. * @param s2 string to compare. * @return true if equal. */ inline bool eq_case(char const *s1, char const *s2) {return String::eq_case(s1, s2);} inline bool ne_case(char const *s1, char const *s2) {return !String::eq_case(s1, s2);} /** * Compare two null terminated strings if equal for a specified size * ignoring case. This is related to stricmp or gcc strcasecmp. * @param s1 string to compare. * @param s2 string to compare. * @param size of string to compare. * @return true if equal. */ inline bool eq_case(char const *s1, char const *s2, size_t size) {return String::eq_case(s1, s2, size);} inline String str(const char *string) {return (String)string;} inline String str(String& string) {return (String)string;} inline String str(short value) {String temp(16, "%hd", value); return temp;} inline String str(unsigned short value) {String temp(16, "%hu", value); return temp;} inline String str(long value) {String temp(32, "%ld", value); return temp;} inline String str(unsigned long value) {String temp(32, "%lu", value); return temp;} inline String str(double value) {String temp(40, "%f", value); return temp;} String str(CharacterProtocol& cp, strsize_t size); template<> inline void swap(string_t& s1, string_t& s2) {String::swap(s1, s2);} class __EXPORT strdup_t { private: char *data; public: inline strdup_t() {data = NULL;} inline strdup_t(char *str) {data = str;} inline ~strdup_t() {if(data) ::free(data);} inline strdup_t& operator=(char *str) {if(data) ::free(data); data = str; return *this;} inline operator bool() const {return data != NULL;} inline bool operator!() const {return data == NULL;} inline operator char*() const {return data;} inline const char *c_str(void) const {return data;} inline const char *operator*() const {return data;} inline char& operator[](int size) {return data[size];} inline char *operator+(size_t size) {return data + size;} }; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/bitmap.h0000664000175000017500000001010412537554527014013 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * A simple class to perform bitmap manipulation. * Bitmaps are used to manage bit-aligned objects, such as network cidr * addresses. This header introduces a common bitmap management class * for the ucommon library. * @file ucommon/bitmap.h */ #ifndef _UCOMMON_BITMAP_H_ #define _UCOMMON_BITMAP_H_ #ifndef _UCOMMON_CONFIG_H_ #include #endif namespace ucommon { /** * A class to access bit fields in external bitmaps. The actual bitmap this * object manipulates may not be stored in the object. Bitmaps may be * referenced on special memory mapped or i/o bus based devices or other * structures that have varying data word sizes which may differ from the * default cpu bus size. The bitmap class can be set to the preferred memory * bus size of the specific external bitmap being used. Bitmap size may also * be relevant when accessing individual bits in memory mapped device registers * where performing reference and manipulations may change the state of the * device and hence must be aligned with the device register being effected. * * This class offers only the most basic bit manipulations, getting and * setting individual bits in the bitmap. More advanced bit manipulations * and other operations can be created in derived classes. * @author David Sugar */ class __EXPORT bitmap { protected: size_t size; typedef union { void *a; uint8_t *b; uint16_t *w; uint32_t *l; uint64_t *d; } addr_t; addr_t addr; public: /** * Specify data word size to use in accessing a bitmap. */ typedef enum { BMALLOC, /**< Use default cpu size */ B8, /**< Accessing a bitmap on 8 bit bus device */ B16, /**< Accessing a bitmap on a 16 bit device */ B32, /**< Accessing a bitmap on a 32 bit device */ B64, /**< Accessing a bitmap on a 64 bit device */ BMIN = BMALLOC, BMAX = B64 } bus_t; protected: bus_t bus; unsigned memsize(void) const; public: /** * Create an object to reference the specified bitmap. * @param addr of the bitmap in mapped memory. * @param length of the bitmap being accessed in bits. * @param size of the memory bus or manipulation to use. */ bitmap(void *addr, size_t length, bus_t size = B8); /** * Create a bitmap to manipulate locally. This bitmap is created * as part of the object itself, and uses the BMALLOC bus mode. * @param length of bitmap to create in bits. */ explicit bitmap(size_t length); /** * Destroy bitmap manipulation object. If a bitmap was locally * created with the alternate constructor, that bitmap will also be * removed from memory. */ ~bitmap(); /** * Clear (zero) all the bits in the bitmap. */ void clear(void); /** * Get the value of a "bit" in the bitmap. * @param offset to bit in map to get. * @return true if bit is set. */ bool get(size_t offset) const; /** * Set an individual bit in the bitmask. * @param offset to bit in map to change. * @param value to change specified bit to. */ void set(size_t offset, bool value); }; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/secure.h0000664000175000017500000006414412544227420014025 00000000000000// Copyright (C) 2010-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * This library holds basic cryptographic functions and secure socket support * for use with GNU uCommon C++. This library might be used in conjunction * with openssl, gnutls, etc. If no secure socket library is available, then * a stub library may be used with very basic cryptographic support. * @file ucommon/secure.h */ /** * Example of SSL socket code. * @example ssl.cpp */ /** * Example of cryptographic digest code. * @example digest.cpp */ /** * Example of cipher code. * @example cipher.cpp */ #ifndef _UCOMMON_SECURE_H_ #define _UCOMMON_SECURE_H_ #ifndef _UCOMMON_CONFIG_H_ #include #endif #ifndef _UCOMMON_UCOMMON_H_ #include #endif #define MAX_CIPHER_KEYSIZE 512 #define MAX_DIGEST_HASHSIZE 512 namespace ucommon { /** * Common secure socket support. This offers common routines needed for * secure/ssl socket support code. * @author David Sugar */ class __SHARED secure { public: /** * Different error states of the security context. */ typedef enum {OK=0, INVALID, MISSING_CERTIFICATE, MISSING_PRIVATEKEY, INVALID_CERTIFICATE, INVALID_AUTHORITY, INVALID_PEERNAME, INVALID_CIPHER} error_t; protected: /** * Last error flagged for this context. */ error_t error; inline secure() {error = OK;} public: /** * This is derived in different back-end libraries, and will be used to * clear certificate credentials. */ virtual ~secure(); /** * Convenience type to represent a security context. */ typedef secure *client_t; typedef secure *server_t; /** * Convenience type to represent a secure socket session. */ typedef void *session_t; /** * Convenience type to represent a secure socket buf i/o stream. */ typedef void *bufio_t; /** * Initialize secure stack for first use, and report if SSL support is * compiled in. * @return true if ssl support is available, false if not. */ static bool init(void); /** * Initialize secure stack with fips support. If fips support is not * successfully enabled, the secure stack is also not initialized. Hence * init() can be used for non-fips certified operation if fips fails. * @return true if fips support enabled and stack initialized. */ static bool fips(void); /** * Copy system certificates to a local path. * @param path to copy to. * @return 0 or error number on failure. */ static int oscerts(const char *path); /** * Get path to system certificates. * @return path to system certificates. */ static const char *oscerts(void); /** * Verify a certificate chain through your certificate authority. * This uses the ca loaded as an optional argument for client and * server. Optionally the hostname of the connection can also be * verified by pulling the peer certificate. * @param session that is connected. * @param peername that we expect. * @return secure error level or secure::OK if none. */ static error_t verify(session_t session, const char *peername = NULL); /** * Create a sever context. The certificate file used will be based on * the init() method name. This may often be /etc/ssl/certs/initname.pem. * Similarly, a matching private key certificate will also be loaded. An * optional certificate authority document can be used when we are * establishing a service which ssl clients have their own certificates. * @param authority path to use or NULL if none. * @return a security context that is cast from derived library. */ static server_t server(const char *keyfile = NULL, const char *authority = NULL); /** * Create an anonymous client context with an optional authority to * validate. * @param authority path to use or NULL if none. * @return a basic client security context. */ static client_t client(const char *authority = NULL); /** * Create a peer user client context. This assumes a user certificate * in ~/.ssl/certs and the user private key in ~/.ssl/private. The * path to an authority is also sent. * @param authority path to use. */ static client_t user(const char *authority); /** * Assign a non-default cipher to the context. * @param context to set cipher for. * @param ciphers to set. */ static void cipher(secure *context, const char *ciphers); /** * Determine if the current security context is valid. * @return true if valid, -1 if not. */ inline bool is_valid(void) const {return error == OK;}; /** * Get last error code associated with the security context. * @return last error code or 0/OK if none. */ inline error_t err(void) const {return error;}; /** * Create 36 character traditional version 1 uuid. * @param string to write uuid into, must be 37 bytes or more. */ static void uuid(char *string); static String uuid(void); template inline static void erase(T *object) {memset(object, 0, sizeof(T)); delete object;} inline operator bool() const {return is_valid();} inline bool operator!() const {return !is_valid();} }; /** * Secure socket buffer. This is used to create ssl socket connections * for both clients and servers. The use depends in part on the type of * context created and passed at construction time. If no context is * passed (NULL), then this reverts to TCPBuffer behavior. * @author David Sugar */ class __SHARED SSLBuffer : public TCPBuffer { protected: secure::session_t ssl; secure::bufio_t bio; bool server; bool verify; public: SSLBuffer(secure::client_t context); SSLBuffer(const TCPServer *server, secure::server_t context, size_t size = 536); ~SSLBuffer(); /** * Connect a ssl client session to a specific host uri. If the socket * was already connected, it is automatically closed first. * @param host we are connecting to. * @param service to connect to. * @param size of buffer and tcp fragments. */ void open(const char *host, const char *service, size_t size = 536); void close(void); void release(void); size_t _push(const char *address, size_t size); size_t _pull(char *address, size_t size); bool _flush(void); bool _pending(void); inline bool is_secure(void) const {return bio != NULL;} }; /** * A generic data ciphering class. This is used to construct cryptographic * ciphers to encode and decode data as needed. The cipher type is specified * by the key object. This class can be used to send output streaming to * memory or in a fixed size buffer. If the latter is used, a push() method * is called through a virtual when the buffer is full. Since block ciphers * are used, buffers should be aligned to the block size. * @author David Sugar */ class __SHARED Cipher { public: typedef enum {ENCRYPT = 1, DECRYPT = 0} mode_t; /** * Cipher key formed by hash algorithm. This can generate both a * key and iv table based on the algorithms used and required. Normally * it is used from a pass-phrase, though any block of data may be * supplied. * @author David Sugar */ class __SHARED Key { protected: friend class Cipher; union { const void *algotype; int algoid; }; union { const void *hashtype; int hashid; }; int modeid; // assume 512 bit cipher keys possible... unsigned char keybuf[MAX_CIPHER_KEYSIZE / 8], ivbuf[MAX_CIPHER_KEYSIZE / 8]; // generated keysize size_t keysize, blksize; Key(const char *ciper); void set(const char *cipher); public: Key(); Key(const char *cipher, const char *digest, const char *text, size_t size = 0, const unsigned char *salt = NULL, unsigned rounds = 1); Key(const char *cipher, const uint8_t *iv, size_t ivsize); Key(const char *cipher, const char *digest); ~Key(); void set(const unsigned char *key, size_t size); void set(const char *cipher, const char *digest); void set(const char *cipher, const uint8_t *iv, size_t ivsize); void assign(const char *key, size_t size, const unsigned char *salt, unsigned rounds); void assign(const char *key, size_t size = 0); void clear(void); String b64(void); void b64(const char *string); size_t get(uint8_t *key, uint8_t *ivout = NULL); inline size_t size(void) const {return keysize;} inline size_t iosize(void) const {return blksize;} inline operator bool() const {return keysize > 0;} inline bool operator!() const {return keysize == 0;} inline Key& operator=(const char *pass) {assign(pass); return *this;} static void options(const unsigned char *salt = NULL, unsigned rounds = 1); }; typedef Key *key_t; private: Key keys; size_t bufsize, bufpos; mode_t bufmode; unsigned char *bufaddr; void *context; protected: virtual void push(unsigned char *address, size_t size); void release(void); public: Cipher(); Cipher(key_t key, mode_t mode, unsigned char *address = NULL, size_t size = 0); virtual ~Cipher(); void set(unsigned char *address, size_t size = 0); void set(key_t key, mode_t mode, unsigned char *address, size_t size = 0); /** * Push a final cipher block. This is used to push the final buffer into * the push method for any remaining data. */ size_t flush(void); /** * Process cipher data. This requires the size to be a multiple of the * cipher block size. If an unaligned sized block of data is used, it * will be ignored and the size returned will be 0. * @param data to process. * @param size of data to process. * @return size of processed output, should be same as size or 0 if error. */ size_t put(const unsigned char *data, size_t size); /** * This essentially encrypts a single string and pads with NULL bytes * as needed. * @param string to encrypt. * @return total encrypted size. */ size_t puts(const char *string); /** * This is used to process any data unaligned to the blocksize at the end * of a cipher session. On an encryption, it will add padding or an * entire padding block with the number of bytes to strip. On decryption * it will remove padding at the end. The pkcs5 method of padding with * removal count is used. This also sets the address buffer to NULL * to prevent further puts until reset. * @param address of data to add before final pad. * @param size of data to add before final pad. * @return actual bytes encrypted or decrypted. */ size_t pad(const unsigned char *address, size_t size); /** * Process encrypted data in-place. This assumes no need to set the * address buffer. * @param address of data to process. * @param size of data to process. * @param flag if to pad data. * @return bytes processed and written back to buffer. */ size_t process(unsigned char *address, size_t size, bool flag = false); inline size_t size(void) const {return bufsize;} inline size_t pos(void) const {return bufpos;} inline size_t align(void) const {return keys.iosize();} /** * Check if a specific cipher is supported. * @param name of cipher to check. * @return true if supported, false if not. */ static bool has(const char *name); }; /** * A cryptographic digest class. This class can support md5 digests, sha1, * sha256, etc, depending on what the underlying library supports. The * hash class accumulates the hash in the object. * @author David Sugar */ class __SHARED Digest { private: void *context; union { const void *hashtype; int hashid; }; unsigned bufsize; unsigned char buffer[MAX_DIGEST_HASHSIZE / 8]; char textbuf[MAX_DIGEST_HASHSIZE / 8 + 1]; protected: void release(void); public: Digest(const char *type); Digest(); ~Digest(); inline bool puts(const char *str) {return put(str, strlen(str));} inline Digest &operator<<(const char *str) {puts(str); return *this;} inline Digest &operator<<(int16_t value) {int16_t v = htons(value); put(&v, 2); return *this;} inline Digest &operator<<(int32_t value) {int32_t v = htonl(value); put(&v, 4); return *this;} inline Digest &operator<<(const PrintProtocol& p) {const char *cp = p._print(); if(cp) puts(cp); return *this;} bool put(const void *memory, size_t size); inline unsigned size() const {return bufsize;} const unsigned char *get(void); const char *c_str(void); inline String str(void) {return String(c_str());} inline operator String() {return String(c_str());} void set(const char *id); inline void operator=(const char *id) {set(id);}; inline bool operator *=(const char *text) {return puts(text);} inline bool operator +=(const char *text) {return puts(text);} inline const char *operator*() {return c_str();} inline bool operator!() const {return !bufsize && context == NULL;} inline operator bool() const {return bufsize > 0 || context != NULL;} /** * Finalize and recycle current digest to start a new * digest. * @param binary digest used rather than text if true. */ void recycle(bool binary = false); /** * Reset and restart digest object. */ void reset(void); /** * Test to see if a specific digest type is supported. * @param name of digest we want to check. * @return true if supported, false if not. */ static bool has(const char *name); static void uuid(char *string, const char *name, const unsigned char *ns = NULL); static String uuid(const char *name, const unsigned char *ns = NULL); /** * Shortcut for short md5 digests if supported... * @param text to create a digest for. * @return digest string. */ static String md5(const char *text); static String sha1(const char *text); static String sha256(const char *text); }; /** * A cryptographic message authentication code class. This class can support * md5 digests, sha1, sha256, etc, depending on what the underlying library * supports. * @author David Sugar */ class __SHARED HMAC { private: void *context; union { const void *hmactype; int hmacid; }; unsigned bufsize; unsigned char buffer[MAX_DIGEST_HASHSIZE / 8]; char textbuf[MAX_DIGEST_HASHSIZE / 8 + 1]; protected: void release(void); public: HMAC(const char *digest, const char *key, size_t keylen = 0); HMAC(); ~HMAC(); inline bool puts(const char *str) {return put(str, strlen(str));} inline HMAC &operator<<(const char *str) {puts(str); return *this;} inline HMAC &operator<<(int16_t value) {int16_t v = htons(value); put(&v, 2); return *this;} inline HMAC &operator<<(int32_t value) {int32_t v = htonl(value); put(&v, 4); return *this;} inline HMAC &operator<<(const PrintProtocol& p) {const char *cp = p._print(); if(cp) puts(cp); return *this;} bool put(const void *memory, size_t size); inline unsigned size() const {return bufsize;} const unsigned char *get(void); const char *c_str(void); inline String str(void) {return String(c_str());} inline operator String() {return String(c_str());} void set(const char *digest, const char *key, size_t len); inline bool operator *=(const char *text) {return puts(text);} inline bool operator +=(const char *text) {return puts(text);} inline const char *operator*() {return c_str();} inline bool operator!() const {return !bufsize && context == NULL;} inline operator bool() const {return bufsize > 0 || context != NULL;} /** * Test to see if a specific digest type is supported. * @param name of digest we want to check. * @return true if supported, false if not. */ static bool has(const char *name); }; /** * Cryptographically relevant random numbers. This is used both to gather * entropy pools and pseudo-random values. * @author David Sugar */ class __SHARED Random { public: /** * Push entropic seed. * @param buffer of random data to push. * @param size of buffer. * @return true if successful. */ static bool seed(const unsigned char *buffer, size_t size); /** * Re-seed pseudo-random generation and entropy pools. */ static void seed(void); /** * Get high-entropy random data. This is often used to * initialize keys. This operation may block if there is * insufficient entropy immediately available. * @param memory buffer to fill. * @param size of buffer. * @return number of bytes filled. */ static size_t key(unsigned char *memory, size_t size); /** * Fill memory with pseudo-random values. This is used * as the basis for all get and real operations and does * not depend on seed entropy. * @param memory buffer to fill. * @param size of buffer to fill. * @return number of bytes set. */ static size_t fill(unsigned char *memory, size_t size); /** * Get a pseudo-random integer, range 0 - 32767. * @return random integer. */ static int get(void); /** * Get a pseudo-random integer in a preset range. * @param min value of random integer. * @param max value of random integer. * @return random value from min to max. */ static int get(int min, int max); /** * Get a pseudo-random floating point value. * @return psudo-random value 0 to 1. */ static double real(void); /** * Get a pseudo-random floating point value in a preset range. * @param min value of random floating point number. * @param max value of random floating point number. * @return random value from min to max. */ static double real(double min, double max); /** * Determine if we have sufficient entropy to return random * values. * @return true if sufficient entropy. */ static bool status(void); /** * Create 36 character random uuid string. * @param string to write uuid into, must be 37 bytes or more. */ static void uuid(char *string); static String uuid(void); template inline static T value(void) { T tmp; Random::key(reinterpret_cast(&tmp), sizeof(tmp)); return tmp; } template inline static T value(T max) { T slice; T value; value = 0xffffffff; slice = 0xffffffff / max; while(value >= max) { value = Random::value() / slice; } return value; } template inline static T value(T min, T max) { return min + Random::value(max - min); } }; /** * Convenience type for secure socket. */ typedef SSLBuffer ssl_t; /** * Convenience type for generic digests. */ typedef Digest digest_t; /** * Convenience type for generic digests. */ typedef HMAC hmac_t; /** * Convenience type for generic ciphers. */ typedef Cipher cipher_t; /** * Convenience type for generic cipher key. */ typedef Cipher::Key skey_t; inline void zerofill(void *addr, size_t size) { ::memset(addr, 0, size); } #ifndef UCOMMON_SYSRUNTIME /** * Secure socket using std::iostream. This class is similar to SSLBuffer * but uses the libstdc++ library to stream i/o. Being based on tcpstream, * it also inherits the character protocol. Like SSLBuffer, if no context * is given or the handshake fails, then the stream defaults to insecure TCP * connection behavior. * @author David Sugar */ class __SHARED sstream : public tcpstream { protected: secure::session_t ssl; secure::bufio_t bio; bool server; bool verify; private: // kill copy constructor sstream(const sstream&); public: sstream(secure::client_t context); sstream(const TCPServer *server, secure::server_t context, size_t size = 536); ~sstream(); void open(const char *host, const char *service, size_t size = 536); void close(void); int sync(); void release(void); ssize_t _write(const char *address, size_t size); ssize_t _read(char *address, size_t size); bool _wait(void); inline void flush(void) {sync();} inline bool is_secure(void) const {return bio != NULL;} }; /** * A template to create a string array that automatically erases. * This is a mini string/stringbuf class that supports a subset of * functionality but does not require a complex supporting object. Like * stringbuf, this can be used to create local string variables. When * the object falls out of scope it's memory is reset. * @author David Sugar */ template class keystring { private: char buffer[S]; /** * Disable copy constructor. */ inline keystring(const keystring& copy) {} public: /** * Create a new character buffer with an empty string. */ inline keystring() {buffer[0] = 0;} /** * Create a character buffer with assigned text. If the text is * larger than the size of the object, it is truncated. * @param text to assign. */ inline keystring(const char *text) {String::set(buffer, S, text);} /** * Clear memory when destroyed. */ inline ~keystring() {memset(buffer, 0, S);} /** * Clear current key memory. */ inline void clear(void) {memset(buffer, 0, S);} /** * Assign null terminated text to the object. * @param text to assign. */ inline void operator=(const char *text) {String::set(buffer, S, text);} /** * Concatenate text into the object. If the text is larger than the * size of the object, then it is truncated. * @param text to append. */ inline void operator+=(const char *text) {String::add(buffer, S, text);} /** * Test if data is contained in the object. * @return true if there is text. */ inline operator bool() const {return buffer[0];} /** * Test if the object is empty. * @return true if the object is empty. */ inline bool operator!() const {return buffer[0] == 0;} /** * Get text by casting reference. * @return pointer to text in object. */ inline operator char *() {return buffer;} /** * Get text by object pointer reference. * @return pointer to text in object. */ inline char *operator*() {return buffer;} /** * Array operator to get a character from the object. * @param offset of character in string buffer. * @return character at offset. */ inline char& operator[](size_t offset) const {return buffer[offset];} /** * Get a pointer to an offset in the object by expression operator. * @param offset of character in string buffer. * @return pointer to offset in object. */ inline char *operator()(size_t offset) {return buffer + offset;} /** * Get allocated size of the object. * @return allocated size. */ inline size_t size(void) const {return S;} /** * Get current length of string. * @return length of string. */ inline size_t len(void) const {return strlen(buffer);} }; /** * A template to create a random generated key of specified size. The * key memory is cleared when the object is destroyed. * @author David Sugar */ template class keyrandom { private: unsigned char buffer[S]; /** * Disable copy constructor. */ inline keyrandom(const keyrandom& copy) {} public: /** * Create a new character buffer with an empty string. */ inline keyrandom() {Random::key(buffer, S);} /** * Clear memory when destroyed. */ inline ~keyrandom() {memset(buffer, 0, S);} /** * Update with new random key. */ inline void update(void) {Random::key(buffer, S);} /** * Clear current key memory. */ inline void clear(void) {memset(buffer, 0, S);} /** * Get text by casting reference. * @return pointer to text in object. */ inline operator unsigned char *() {return buffer;} /** * Get text by object pointer reference. * @return pointer to text in object. */ inline unsigned char *operator*() {return buffer;} /** * Get allocated size of the object. * @return allocated size. */ inline size_t size(void) const {return S;} }; #endif } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/buffer.h0000664000175000017500000000742212537554527014021 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Classes which use the buffer protocol to stream data. * @file ucommon/buffer.h */ #ifndef _UCOMMON_BUFFER_H_ #define _UCOMMON_BUFFER_H_ #ifndef _UCOMMON_CONFIG_H_ #include #endif #ifndef _UCOMMON_PROTOCOLS_H_ #include #endif #ifndef _UCOMMON_SOCKET_H_ #include #endif #ifndef _UCOMMON_STRING_H_ #include #endif #ifndef _UCOMMON_FSYS_H_ #include #endif #ifndef _UCOMMON_SHELL_H_ #include #endif namespace ucommon { /** * A generic tcp socket class that offers i/o buffering. All user i/o * operations are directly inherited from the IOBuffer base class public * members. Some additional members are added for layering ssl services. * @author David Sugar */ class __EXPORT TCPBuffer : public BufferProtocol, protected Socket { protected: void _buffer(size_t size); virtual size_t _push(const char *address, size_t size); virtual size_t _pull(char *address, size_t size); int _err(void) const; void _clear(void); bool _blocking(void); /** * Get the low level socket object. * @return socket we are using. */ inline socket_t getsocket(void) const { return so; } public: /** * Construct an unconnected tcp client and specify our service profile. */ TCPBuffer(); /** * Construct a tcp server session from a listening socket. * @param server socket we are created from. * @param size of buffer and tcp fragments. */ TCPBuffer(const TCPServer *server, size_t size = 536); /** * Construct a tcp client session connected to a specific host uri. * @param host and optional :port we are connecting to. * @param service identifier of our client. * @param size of buffer and tcp fragments. */ TCPBuffer(const char *host, const char *service, size_t size = 536); /** * Destroy the tcp socket and release all resources. */ virtual ~TCPBuffer(); /** * Connect a tcp socket to a client from a listener. If the socket was * already connected, it is automatically closed first. * @param server we are connected from. * @param size of buffer and tcp fragments. */ void open(const TCPServer *server, size_t size = 536); /** * Connect a tcp client session to a specific host uri. If the socket * was already connected, it is automatically closed first. * @param host we are connecting. * @param service to connect to. * @param size of buffer and tcp fragments. */ void open(const char *host, const char *service, size_t size = 536); /** * Close active connection. */ void close(void); protected: /** * Check for pending tcp or ssl data. * @return true if data pending. */ virtual bool _pending(void); }; /** * Convenience type for pure tcp sockets. */ typedef TCPBuffer tcp_t; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/vector.h0000664000175000017500000005573112537554527014060 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Basic array and reusable object factory heap support. * This offers ucommon support for vector arrays, and for forming * reusable object pools. Reusable object pools can be tied to local * heaps and offer a means to create type factories that do not require * global locking through malloc. * @file ucommon/vector.h */ #ifndef _UCOMMON_VECTOR_H_ #define _UCOMMON_VECTOR_H_ #ifndef _UCOMMON_THREAD_H_ #include #endif namespace ucommon { typedef unsigned short vectorsize_t; /** * An array of reusable objects. This class is used to support the * array_use template. A pool of objects are created which can be * allocated as needed. Deallocated objects are returned to the pool * so they can be reallocated later. This is a private fixed size heap. * @author David Sugar */ class __EXPORT ArrayReuse : public ReusableAllocator { private: size_t objsize; unsigned count, limit, used; caddr_t mem; protected: ArrayReuse(size_t objsize, unsigned c); ArrayReuse(size_t objsize, unsigned c, void *memory); public: /** * Destroy reusable private heap array. */ ~ArrayReuse(); protected: bool avail(void) const; ReusableObject *get(timeout_t timeout); ReusableObject *get(void); ReusableObject *request(void); }; /** * A mempager source of reusable objects. This is used by the reuse_pager * template to allocate new objects either from a memory pager used as * a private heap, or from previously allocated objects that have been * returned for reuse. * @author David Sugar */ class __EXPORT PagerReuse : protected MemoryRedirect, protected ReusableAllocator { private: unsigned limit, count; size_t osize; protected: PagerReuse(mempager *pager, size_t objsize, unsigned count); ~PagerReuse(); bool avail(void) const; ReusableObject *get(void); ReusableObject *get(timeout_t timeout); ReusableObject *request(void); }; /** * A managed vector for generic object pointers. This vector is memory * managed at runtime by basic cow (copy-on-write) operations of a reference * counted object list. This allows the size of the vector to be changed * at runtime and for the vector to be copied by managing reference counted * copies of the list of objects as needed. * * This class is somewhat analogous to the string class, but rather than * holding a string "array of chars" that may be re-sized and reallocated, * the Vector holds an array of Object pointers. Since the object pointers * we store in the vector are objects inherited from Object, a vector can * itself act as a vector of smart pointers to reference counted objects * (derived from CountedObject). * @author David Sugar . */ class __EXPORT Vector { public: class __EXPORT array : public CountedObject { public: #pragma pack(1) vectorsize_t max, len; ObjectProtocol *list[1]; #pragma pack() array(vectorsize_t size); void dealloc(void); void set(ObjectProtocol **items); void add(ObjectProtocol **list); void add(ObjectProtocol *obj); void purge(void); void inc(vectorsize_t adj); void dec(vectorsize_t adj); }; protected: array *data; array *create(vectorsize_t size) const; virtual void release(void); virtual void cow(vectorsize_t adj = 0); ObjectProtocol **list(void) const; friend class Vector::array; protected: /** * Object handler for index outside vector range. * @return default object, often NULL. */ virtual ObjectProtocol *invalid(void) const; public: /** * npos is a constant for an "invalid" position value. */ static const vectorsize_t npos; /** * Create an initially empty vector. */ Vector(); /** * Create a vector of size object pointers. * @param size of vector to create. */ Vector(vectorsize_t size); /** * Create a vector of size objects from existing object pointers. * This allocates the vector and initializes the object pointers from * an existing array of object pointers. Either a specific vector * size may be used, or the end of the vector will be found by a NULL * object pointer. * @param items to place into the vector. * @param size of the vector to create, or use NULL item for end. */ Vector(ObjectProtocol **items, vectorsize_t size = 0); /** * Destroy the current reference counted vector of object pointers. */ virtual ~Vector(); /** * Get the size of the vector (number of active members). * @return number of active pointers in vector. */ vectorsize_t len(void) const; /** * Get the effective allocation space used by the vector. This is the * number of pointers it can hold before it needs to be resized. * @return storage size of vector. */ vectorsize_t size(void) const; /** * Get an object pointer from a specified member of the vector. * @param index of member pointer to return. Negative values from end. * @return object pointer of member. */ ObjectProtocol *get(int index) const; /** * Copy the vector to an external pointer array. * @param mem array of external pointers to hold vector. * @param max size of the external array. * @return number of elements copied into external array. */ vectorsize_t get(void **mem, vectorsize_t max) const; /** * Get the first object pointer contained in the vector. Typically used * in iterations. * @return first object pointer. */ ObjectProtocol *begin(void) const; /** * Get the last object pointer contained in the vector. Typically used * in iterations. * @return last object pointer. */ ObjectProtocol *end(void) const; /** * Find the first instance of a specific pointer in the vector. * @param pointer to locate in the vector. * @param offset to start searching in vector. * @return position of pointer in vector or npos if not found. */ vectorsize_t find(ObjectProtocol *pointer, vectorsize_t offset = 0) const; /** * Split the vector at a specified offset. All members after the split * are de-referenced and dropped from the vector. * @param position to split vector at. */ void split(vectorsize_t position); /** * Split the vector after a specified offset. All members before the split * are de-referenced and dropped. The member starting at the split point * becomes the first member of the vector. * @param position to split vector at. */ void rsplit(vectorsize_t position); /** * Set a member of the vector to an object. If an existing member was * present and is being replaced, it is de-referenced. * @param position in vector to place object pointer. * @param pointer to place in vector. */ void set(vectorsize_t position, ObjectProtocol *pointer); /** * Set the vector to a list of objects terminated by a NULL pointer. * @param list of object pointers. */ void set(ObjectProtocol **list); /** * Add (append) a NULL terminated list of objects to the vector. * @param list of object pointers to add. */ void add(ObjectProtocol **list); /** * Add (append) a single object pointer to the vector. * @param pointer to add to vector. */ void add(ObjectProtocol *pointer); /** * De-reference and remove all pointers from the vector. */ void clear(void); /** * Re-size & re-allocate the total (allocated) size of the vector. * @param size to allocate for vector. */ virtual bool resize(vectorsize_t size); /** * Set (duplicate) an existing vector into our vector. * @param vector to duplicate. */ inline void set(Vector &vector) { set(vector.list()); } /** * Add (append) an existing vector to our vector. * @param vector to append. */ inline void add(Vector &vector) { add(vector.list()); } /** * Return a pointer from the vector by array reference. * @param index of vector member pointer to return. */ inline ObjectProtocol *operator[](int index) { return get(index); } /** * Assign a member of the vector directly. * @param position to assign. * @param pointer to object to assign to vector. */ inline void operator()(vectorsize_t position, ObjectProtocol *pointer) { set(position, pointer); } /** * Retrieve a member of the vector directly. * @param position to retrieve object from. * @return object pointer retrieved from vector. */ inline ObjectProtocol *operator()(vectorsize_t position) { return get(position); } /** * Append a member to the vector directly. * @param pointer to object to add to vector. */ inline void operator()(ObjectProtocol *pointer) { add(pointer); } /** * Assign (copy) into our existing vector from another vector. * @param vector to assign from. */ inline void operator=(Vector &vector) { set(vector.list()); } /** * Append into our existing vector from another vector. * @param vector to append from. */ inline void operator+=(Vector &vector) { add(vector.list()); } /** * Concatenate into our existing vector from assignment list. * @param vector to append from. */ inline Vector& operator+(Vector &vector) { add(vector.list()); return *this; } /** * Release vector and concat vector from another vector. * @param vector to assign from. */ Vector &operator^(Vector &vector); /** * Release our existing vector and duplicate from another vector. This * differs from assign in that the allocated size of the vector is reset * to the new list. * @param vector to assign from. */ void operator^=(Vector &vector); /** * Drop first member of vector. */ void operator++(); /** * Drop last member of the vector. */ void operator--(); /** * Drop first specified members from the vector. * @param count of members to drop. */ void operator+=(vectorsize_t count); /** * Drop last specified members from the vector. * @param count of members to drop. */ void operator-=(vectorsize_t count); /** * Compute the effective vector size of a list of object pointers. * The size is found as the NULL pointer in the list. * @return size of list. */ static vectorsize_t size(void **list); }; /** * Vector with fixed size member list. This is analogous to the memstring * class and is used to tie a vector to a fixed list in memory. * @author David Sugar */ class __EXPORT MemVector : public Vector { private: bool resize(vectorsize_t size); void cow(vectorsize_t adj = 0); void release(void); friend class Vector::array; public: /** * Create and manage a vector stored in fixed memory. * @param pointer to where our vector list lives. * @param size of vector list in memory. */ MemVector(void *pointer, vectorsize_t size); /** * Destroy the vector. */ ~MemVector(); /** * Assign an existing vector into our fixed vector list. * @param vector to copy from. */ inline void operator=(Vector &vector) { set(vector); } }; /** * A templated vector for a list of a specific Object subtype. The * templated type must be derived from Object. * @author David Sugar */ template class vectorof : public Vector { public: /** * Create an empty vector for specified type. */ inline vectorof() : Vector() {} /** * Create an empty vector of allocated size for specified type. * @param size of vector to allocate. */ inline vectorof(vectorsize_t size) : Vector(size) {} inline T& operator[](int index) { return static_cast(Vector::get(index)); } inline const T& at(int index) { return immutable_cast(Vector::get(index)); } /** * Retrieve a typed member of the vector directly. * @param position to retrieve object from. * @return typed object pointer retrieved from vector. */ inline T *operator()(vectorsize_t position) { return static_cast(Vector::get(position)); } /** * Get the first typed object pointer contained in the vector. * @return first typed object pointer. */ inline T *begin(void) { return static_cast(Vector::begin()); } /** * Get the last typed object pointer contained in the vector. * @return last typed object pointer. */ inline T *end(void) { return static_cast(Vector::end()); } /** * Concatenate typed vector in an expression. * @param vector to concatenate. * @return effective object to continue in expression. */ inline Vector &operator+(Vector &vector) { Vector::add(vector); return static_cast(*this); } }; /** * An array of reusable types. A pool of typed objects is created which can * be allocated as needed. Deallocated typed objects are returned to the pool * so they can be reallocated later. This is a private fixed size heap. * @author David Sugar */ template class array_reuse : protected ArrayReuse { public: /** * Create private heap of reusable objects of specified type. * @param count of objects of specified type to allocate. */ inline array_reuse(unsigned count) : ArrayReuse(sizeof(T), count) {} /** * Create reusable objects of specific type in preallocated memory. * @param count of objects of specified type in memory. * @param memory to use. */ inline array_reuse(unsigned count, void *memory) : ArrayReuse(sizeof(T), count, memory) {} /** * Test if typed objects available in heap or re-use list. * @return true if objects still are available. */ inline operator bool() const { return avail(); } /** * Test if the entire heap has been allocated. * @return true if no objects are available. */ inline bool operator!() const { return !avail(); } /** * Request immediately next available typed object from the heap. * @return typed object pointer or NULL if heap is empty. */ inline T* request(void) { return static_cast(ArrayReuse::request()); } /** * Get a typed object from the heap. This function blocks when the * heap is empty until an object is returned to the heap. * @return typed object pointer from heap. */ inline T* get(void) { return static_cast(ArrayReuse::get()); } /** * Create a typed object from the heap. This function blocks when the * heap is empty until an object is returned to the heap. * @return typed object pointer from heap. */ inline T* create(void) { return init(static_cast(ArrayReuse::get())); } /** * Get a typed object from the heap. This function blocks until the * the heap has an object to return or the timer has expired. * @param timeout to wait for heap in milliseconds. * @return typed object pointer from heap or NULL if timeout. */ inline T* get(timeout_t timeout) { return static_cast(ArrayReuse::get(timeout)); } /** * Create a typed object from the heap. This function blocks until the * the heap has an object to return or the timer has expired. * @param timeout to wait for heap in milliseconds. * @return typed object pointer from heap or NULL if timeout. */ inline T* create(timeout_t timeout) { return init(static_cast(ArrayReuse::get(timeout))); } /** * Release (return) a typed object back to the heap for re-use. * @param object to return. */ inline void release(T *object) { ArrayReuse::release(object); } /** * Get a typed object from the heap by type casting reference. This * function blocks while the heap is empty. * @return typed object pointer from heap. */ inline operator T*() { return array_reuse::get(); } /** * Get a typed object from the heap by pointer reference. This * function blocks while the heap is empty. * @return typed object pointer from heap. */ inline T *operator*() { return array_reuse::get(); } }; /** * A reusable private pool of reusable types. A pool of typed objects is * created which can be allocated from a memory pager. Deallocated typed * objects are also returned to this pool so they can be reallocated later. * @author David Sugar */ template class paged_reuse : protected PagerReuse { public: /** * Create a managed reusable typed object pool. This manages a heap of * typed objects that can either be reused from released objects or * allocate from an existing memory pager pool. * @param pager pool to allocate from. * @param count of objects of specified type to allocate. */ inline paged_reuse(mempager *pager, unsigned count) : PagerReuse(pager, sizeof(T), count) {} /** * Test if typed objects available from the pager or re-use list. * @return true if objects still are available. */ inline operator bool() const { return PagerReuse::avail(); } /** * Test if no objects are available for reuse or the pager. * @return true if no objects are available. */ inline bool operator!() const { return !PagerReuse::avail(); } /** * Get a typed object from the pager heap. This function blocks when the * heap is empty until an object is returned to the heap. * @return typed object pointer from heap. */ inline T *get(void) { return static_cast(PagerReuse::get()); } /** * Get a typed object from the pager heap. This function blocks when the * heap is empty until an object is returned to the heap. The objects * default constructor is used. * @return typed object pointer from heap. */ inline T *create(void) { return init(static_cast(PagerReuse::get())); } /** * Get a typed object from the heap. This function blocks until the * the heap has an object to return or the timer has expired. * @param timeout to wait for heap in milliseconds. * @return typed object pointer from heap or NULL if timeout. */ inline T *get(timeout_t timeout) { return static_cast(PagerReuse::get(timeout)); } /** * Create a typed object from the heap. This function blocks until the * the heap has an object to return or the timer has expired. The * objects default constructor is used. * @param timeout to wait for heap in milliseconds. * @return typed object pointer from heap or NULL if timeout. */ inline T *create(timeout_t timeout) { return init(static_cast(PagerReuse::get(timeout))); } /** * Request immediately next available typed object from the pager heap. * @return typed object pointer or NULL if heap is empty. */ inline T *request(void) { return static_cast(PagerReuse::request()); } /** * Release (return) a typed object back to the pager heap for re-use. * @param object to return. */ inline void release(T *object) { PagerReuse::release(object); } /** * Get a typed object from the pager heap by type casting reference. This * function blocks while the heap is empty. * @return typed object pointer from heap. */ inline T *operator*() { return paged_reuse::get(); } /** * Get a typed object from the pager heap by pointer reference. This * function blocks while the heap is empty. * @return typed object pointer from heap. */ inline operator T*() { return paged_reuse::get(); } }; /** * Allocated vector list of a specified type. This analogous to the stringbuf * class and allows one to create a vector with it's member list as a single * object that can live in the heap or that can be created at once and used as * a auto variable. * @author David Sugar */ template class vectorbuf : public MemVector { private: char buffer[sizeof(array) + (S * sizeof(void *))]; public: /** * Construct fixed sized vector object in heap or stack. */ inline vectorbuf() : MemVector(buffer, S) {} /** * Get object pointer of specified type from fixed vector. * @param index of typed member to return, < 0 to use from end of list. * @return typed object pointer of member. */ inline const T& at(int index) { return immutable_cast(Vector::get(index)); } inline T& operator[](int index) { return static_cast(Vector::get(index)); } /** * Retrieve a typed member of the fixed vector directly. * @param position to retrieve object from. * @return typed object pointer retrieved from vector. */ inline T *operator()(vectorsize_t position) { return static_cast(Vector::get(position)); } /** * Get the first typed object pointer contained in the fixed vector. * @return first typed object pointer. */ inline T *begin(void) { return static_cast(Vector::begin()); } /** * Get the last typed object pointer contained in the fixed vector. * @return last typed object pointer. */ inline T *end(void) { return static_cast(Vector::end()); } /** * Concatenate fixed typed vector in an expression. * @param vector to concatenate. * @return effective object to continue in expression. */ inline Vector &operator+(Vector &vector) { Vector::add(vector); return static_cast(*this); } }; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/typeref.h0000664000175000017500000001337012557431651014217 00000000000000// Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * A thread-safe atomic heap management system. This is used to manage * immutable heap instances of object types that are reference counted * and automatically deleted when no longer used. All references to the * object are through smart typeref pointers. Both specific classes for * strings and byte arrays, and generic templates to support generic * types in the heap are offered. * @file ucommon/typeref.h */ #ifndef _UCOMMON_TYPEREF_H_ #define _UCOMMON_TYPEREF_H_ #ifndef _UCOMMON_CPR_H_ #include #endif #ifndef _UCOMMON_ATOMIC_H_ #include #endif #ifndef _UCOMMON_PROTOCOLS_H_ #include #endif #ifndef _UCOMMON_OBJECT_H_ #include #endif namespace ucommon { /** * Smart pointer base class for auto-retained objects. * @author David Sugar */ class __EXPORT TypeRef { protected: /** * Heap base-class container for typeref objects. * @author David Sugar */ class __EXPORT Counted : public ObjectProtocol { protected: friend class TypeRef; mutable atomic::counter count; size_t size; void *memory; explicit Counted(void *addr, size_t size); virtual void dealloc(); public: inline bool is() const { return (count.get() > 0); } inline unsigned copies() const { return ((unsigned)count.get()); } void operator delete(void *addr); void retain(); void release(); }; Counted *ref; // heap reference... TypeRef(Counted *object); TypeRef(const TypeRef& copy); TypeRef(); void set(Counted *object); static caddr_t alloc(size_t size); static caddr_t mem(caddr_t addr); public: virtual ~TypeRef(); void set(const TypeRef& ptr); void release(void); inline bool is() const { return ref != NULL; } inline bool operator!() const { return ref == NULL; } inline unsigned copies() const { if(!ref) return 0; return ref->copies(); } inline size_t size() const { if(!ref) return 0; return ref->size; } }; template class typeref : public TypeRef { private: class value : public Counted { public: inline value(caddr_t mem) : Counted(mem, sizeof(value)) {}; inline value(caddr_t mem, const T& object) : Counted(mem, sizeof(value)) { data = object; } T data; }; public: inline typeref() : TypeRef() {}; inline typeref(const typeref& copy) : TypeRef(copy) {}; inline typeref(const T& object) : TypeRef() { caddr_t p = TypeRef::alloc(sizeof(value)); TypeRef::set(new(mem(p)) value(p, object)); } inline T* operator->() { if(!ref) return NULL; value *v = polystatic_cast(ref); return &(v->data); } inline const T *operator*() const { if(!ref) return NULL; value *v = polystatic_cast(ref); return &(v->data); } inline operator const T&() const { value *v = polystatic_cast(ref); return *(&(v->data)); } inline typeref& operator=(const typeref& ptr) { TypeRef::set(ptr); return *this; } inline void set(T& object) { release(); caddr_t p = TypeRef::alloc(sizeof(value)); TypeRef::set(new(mem(p)) value(p, object)); } inline typeref& operator=(T& object) { set(object); return *this; } }; class __EXPORT stringref : public TypeRef { public: class value : public Counted { protected: friend class stringref; char mem[1]; value(caddr_t addr, size_t size, const char *str); void destroy(void); public: inline char *get() { return &mem[0]; } inline size_t len() { return strlen(mem); } inline size_t max() { return size; } }; stringref(); stringref(const stringref& copy); stringref(const char *str); const char *operator*() const; inline operator const char *() const { return operator*(); } stringref& operator=(const stringref& objref); stringref& operator=(const char *str); stringref& operator=(value *chars); const char *operator()(ssize_t offset) const; void set(const char *str); void assign(value *chars); static void expand(value **handle, size_t size); static value *create(size_t size); static void destroy(value *bytes); }; class __EXPORT byteref : public TypeRef { public: class value : public Counted { protected: friend class byteref; uint8_t mem[1]; value(caddr_t addr, size_t size, const uint8_t *data); value(caddr_t addr, size_t size); void destroy(void); public: inline size_t max() { return size; } inline uint8_t *get() { return &mem[0]; } }; byteref(); byteref(const byteref& copy); byteref(const uint8_t *str, size_t size); const uint8_t *operator*() const; inline operator const uint8_t *() const { return operator*(); } byteref& operator=(const byteref& objref); byteref& operator=(value *bytes); void set(const uint8_t *str, size_t size); void assign(value *bytes); static value *create(size_t size); static void destroy(value *bytes); }; typedef stringref::value *charvalues_t; typedef byteref::value *bytevalues_t; typedef stringref stringref_t; typedef byteref byteref_t; } // namespace #endif ucommon-6.4.4/inc/ucommon/linked.h0000664000175000017500000016335412555235012014006 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Linked objects, lists, templates, and containers. * Common support for objects that might be organized as single and double * linked lists, rings and queues, and tree oriented data structures. These * generic classes may be used to help form anything from callback * registration systems and indexed memory hashes to xml parsed tree nodes. * @file ucommon/linked.h */ /** * An example of the linked object classes and their use. * @example linked.cpp */ #ifndef _UCOMMON_LINKED_H_ #define _UCOMMON_LINKED_H_ #ifndef _UCOMMON_CONFIG_H_ #include #endif #ifndef _UCOMMON_OBJECT_H_ #include #endif #ifdef nil #undef nil #endif namespace ucommon { class OrderedObject; /** * Common base class for all objects that can be formed into a linked list. * This base class is used directly for objects that can be formed into a * single linked list. It is also used directly as a type for a pointer to the * start of list of objects that are linked together as a list. * @author David Sugar */ class __EXPORT LinkedObject : public ObjectProtocol { protected: friend class OrderedIndex; friend class LinkedRing; friend class NamedObject; friend class ObjectStack; LinkedObject *Next; /** * Construct base class attached to a chain of objects. * @param root pointer to chain of objects we are part of. */ LinkedObject(LinkedObject **root); /** * Construct base class unattached to anyone. This might be * used to construct intermediary base classes that may form * lists through indexing objects. */ LinkedObject(); public: static const LinkedObject *nil; /**< Marker for end of linked list. */ static const LinkedObject *inv; /**< Marker for invalid list pointer */ virtual ~LinkedObject(); /** * Release list, mark as no longer linked. Inherited from base Object. */ virtual void release(void); /** * Retain by marking as self referenced list. Inherited from base Object. */ virtual void retain(void); /** * Add our object to an existing linked list through a pointer. This * forms a container sorted in lifo order since we become the head * of the list, and the previous head becomes our next. * @param root pointer to list we are adding ourselves to. */ void enlist(LinkedObject **root); /** * Locate and remove ourselves from a list of objects. This searches * the list to locate our object and if found relinks the list around * us. * @param root pointer to list we are removing ourselves from. */ void delist(LinkedObject **root); /** * Search to see if we are a member of a specific list. * @return true if we are member of the list. */ bool is_member(LinkedObject *list) const; /** * Release all objects from a list. * @param root pointer to list we are purging. */ static void purge(LinkedObject *root); /** * Count the number of linked objects in a list. * @param root pointer to list we are counting. */ static unsigned count(const LinkedObject *root); /** * Get member by index. * @return indexed member in linked list. * @param root pointer to list we are indexing. * @param index member to find. */ static LinkedObject *getIndexed(LinkedObject *root, unsigned index); /** * Get next effective object when iterating. * @return next linked object in list. */ inline LinkedObject *getNext(void) const { return Next; } }; /** * Reusable objects for forming private heaps. Reusable objects are * linked objects that may be allocated in a private heap, and are * returned to a free list when they are no longer needed so they can * be reused without having to be re-allocated. The free list is the * root of a linked object chain. This is used as a base class for those * objects that will be managed through reusable heaps. * @author David Sugar */ class __EXPORT ReusableObject : public LinkedObject { friend class ReusableAllocator; protected: virtual void release(void); public: /** * Get next effective reusable object when iterating. * @return next reusable object in list. */ inline ReusableObject *getNext(void) { return polypointer_cast(LinkedObject::getNext()); } }; /** * An index container for maintaining an ordered list of objects. * This index holds a pointer to the head and tail of an ordered list of * linked objects. Fundamental methods for supporting iterators are * also provided. * @author David Sugar */ class __EXPORT OrderedIndex { protected: friend class OrderedObject; friend class DLinkedObject; friend class LinkedList; friend class NamedObject; OrderedObject *head, *tail; public: void copy(const OrderedIndex& source); /** * Create and initialize an empty index. */ OrderedIndex(); inline OrderedIndex(const OrderedIndex& source) { copy(source); } /** * Destroy index. */ virtual ~OrderedIndex(); /** * Find a specific member in the ordered list. * @param offset to member to find. */ LinkedObject *find(unsigned offset) const; /** * Count of objects this list manages. * @return number of objects in the list. */ unsigned count(void) const; /** * Purge the linked list and then set the index to empty. */ void purge(void); /** * Reset linked list to empty without purging. */ void reset(void); /** * Used to synchronize lists managed by multiple threads. A derived * locking method would be invoked. */ virtual void lock_index(void); /** * Used to synchronize lists managed by multiple threads. A derived * unlocking method would be invoked. */ virtual void unlock_index(void); /** * Return a pointer to the head of the list. This allows the head * pointer to be used like a simple root list pointer for pure * LinkedObject based objects. * @return LinkedIndex style object. */ LinkedObject **index(void) const; /** * Get (pull) object off the list. The start of the list is advanced to * the next object. * @return LinkedObject based object that was head of the list. */ LinkedObject *get(void); /** * Add an object into the ordered index. * @param ordered object to add to the index. */ void add(OrderedObject *ordered); /** * Get an indexed member from the ordered index. * @param index of member to fetch. * @return LinkedObject member of index. */ inline LinkedObject *getIndexed(unsigned index) const { return LinkedObject::getIndexed(polystatic_cast(head), index); } /** * Return first object in list for iterators. * @return first object in list. */ inline LinkedObject *begin(void) const { return polystatic_cast(head); } /** * Return last object in list for iterators. * @return last object in list. */ inline LinkedObject *end(void) const { return polystatic_cast(tail); } /** * Return head object pointer. * @return head pointer. */ inline LinkedObject *operator*() const { return polystatic_cast(head); } /** * Assign ordered index. * @param object to copy from. */ OrderedIndex& operator=(const OrderedIndex& object) { copy(object); return *this; } /** * Add object to our list. * @param object to add. */ void operator*=(OrderedObject *object); }; /** * A linked object base class for ordered objects. This is used for * objects that must be ordered and listed through the OrderedIndex * class. * @author David Sugar */ class __EXPORT OrderedObject : public LinkedObject { protected: friend class LinkedList; friend class OrderedIndex; friend class DLinkedObject; friend class ObjectQueue; /** * Construct an ordered object aot end of a an index. * @param index we are listed on. */ OrderedObject(OrderedIndex *index); /** * Construct an ordered object unattached. */ OrderedObject(); public: /** * List our ordered object at end of a linked list on an index. * @param index we are listing on. */ void enlistTail(OrderedIndex *index); /** * List our ordered object at start of a linked list on an index. * @param index we are listing on. */ void enlistHead(OrderedIndex *index); /** * List our ordered object in default strategy mode. The default * base class uses enlistTail. * @param index we are listing on. */ virtual void enlist(OrderedIndex *index); /** * Remove our ordered object from an existing index. * @param index we are listed on. */ void delist(OrderedIndex *index); /** * Get next ordered member when iterating. * @return next ordered object. */ inline OrderedObject *getNext(void) const { return static_cast(LinkedObject::getNext()); } }; /** * A double-linked Object, used for certain kinds of lists. * @author David Sugar */ class __EXPORT DLinkedObject : public OrderedObject { public: friend class ObjectQueue; /** * Construct an empty object. */ DLinkedObject(); protected: /** * Remove a cross-linked list from itself. */ void delist(void); private: DLinkedObject *Prev; }; /** * A linked object base class with members found by name. This class is * used to help form named option lists and other forms of name indexed * associative data structures. The id is assumed to be passed from a * dupped or dynamically allocated string. If a constant string is used * then you must not call delete for this object. * * Named objects are either listed on an ordered list or keyed through an * associate hash map table. When using a hash table, the name id string is * used to determine the slot number to use in a list of n sized linked * object lists. Hence, a hash index refers to a specific sized array of * object indexes. * @author David Sugar */ class __EXPORT NamedObject : public OrderedObject { protected: char *Id; /** * Create an empty unnamed cell object. */ NamedObject(); /** * Create a named object and add to hash indexed list. * @param hash map table to list node on. * @param name of the object we are listing. * @param size of hash map table used. */ NamedObject(NamedObject **hash, char *name, unsigned size = 1); /** * Created a named object on an ordered list. This is commonly used * to form attribute lists. * @param index to list object on. * @param name of the object we are listing. */ NamedObject(OrderedIndex *index, char *name); /** * Destroy named object. We do not always destroy named objects, since * we may use them in reusable pools or we may initialize a list that we * keep permanently. If we do invoke delete for something based on * NamedObject, then be aware the object id is assumed to be formed from * a dup'd string which will also be freed unless clearId is overridden. */ ~NamedObject(); /** * The behavior of clearing id's can be overridden if they are not * assigned as strdup's from the heap... */ virtual void clearId(void); public: /** * Add object to hash indexed list. * @param hash map table to list node on. * @param name of the object we are listing. * @param size of hash map table used. */ void add(NamedObject **hash, char *name, unsigned size = 1); /** * Purge a hash indexed table of named objects. * @param hash map table to purge. * @param size of hash map table used. */ static void purge(NamedObject **hash, unsigned size); /** * Convert a hash index into a linear object pointer array. The * object pointer array is created from the heap and must be deleted * when no longer used. * @param hash map table of objects to index. * @param size of hash map table used. * @return array of named object pointers. */ static NamedObject **index(NamedObject **hash, unsigned size); /** * Count the total named objects in a hash table. * @param hash map table of objects to index. * @param size of hash map table used. */ static unsigned count(NamedObject **hash, unsigned size); /** * Find a named object from a simple list. This may also use the * begin() member of an ordered index of named objects. * @param root node of named object list. * @param name of object to find. * @return object pointer or NULL if not found. */ static NamedObject *find(NamedObject *root, const char *name); /** * Remove a named object from a simple list. * @param root node of named object list. * @param name of object to find. * @return object pointer or NULL if not found. */ static NamedObject *remove(NamedObject **root, const char *name); /** * Find a named object through a hash map table. * @param hash map table of objects to search. * @param name of object to find. * @param size of hash map table. * @return object pointer or NULL if not found. */ static NamedObject *map(NamedObject **hash, const char *name, unsigned size); /** * Remove an object from a hash map table. * @param hash map table of object to remove from. * @param name of object to remove. * @param size of hash map table. * @return object that is removed or NULL if not found. */ static NamedObject *remove(NamedObject **hash, const char *name, unsigned size); /** * Iterate through a hash map table. * @param hash map table to iterate. * @param current named object we iterated or NULL to find start of list. * @param size of map table. * @return next named object in hash map or NULL if no more objects. */ static NamedObject *skip(NamedObject **hash, NamedObject *current, unsigned size); /** * Internal function to convert a name to a hash index number. * @param name to convert into index. * @param size of map table. */ static unsigned keyindex(const char *name, unsigned size); /** * Sort an array of named objects in alphabetical order. This would * typically be used to sort a list created and returned by index(). * @param list of named objects to sort. * @param count of objects in the list or 0 to find by NULL pointer. * @return list in sorted order. */ static NamedObject **sort(NamedObject **list, size_t count = 0); /** * Get next effective object when iterating. * @return next linked object in list. */ inline NamedObject *getNext(void) const { return static_cast(LinkedObject::getNext()); } /** * Get the named id string of this object. * @return name id. */ inline char *getId(void) const { return Id; }; /** * Compare the name of our object to see if equal. This is a virtual * so that it can be overridden when using named lists or hash lookups * that must be case insensitive. * @param name to compare our name to. * @return 0 if effectivily equal, used for sorting keys. */ virtual int compare(const char *name) const; /** * Equal function which calls compare. * @param name to compare our name to. * @return true if equal. */ inline bool equal(const char *name) const { return (compare(name) == 0); } /** * Comparison operator between our name and a string. * @param name to compare with. * @return true if equal. */ inline bool operator==(const char *name) const { return compare(name) == 0; } /** * Comparison operator between our name and a string. * @param name to compare with. * @return true if not equal. */ inline bool operator!=(const char *name) const { return compare(name) != 0; } }; /** * The named tree class is used to form a tree oriented list of associated * objects. Typical uses for such data structures might be to form a * parsed XML document, or for forming complex configuration management * systems or for forming system resource management trees. * @author David Sugar */ class __EXPORT NamedTree : public NamedObject { protected: NamedTree *Parent; OrderedIndex Child; /** * Create a stand-alone or root tree node, with an optional name. * @param name for this node. */ NamedTree(char *name = NULL); /** * Create a tree node as a child of an existing node. * @param parent node we are listed under. * @param name of our node. */ NamedTree(NamedTree *parent, char *name); /** * Construct a copy of the tree. * @param source object to copy from. */ NamedTree(const NamedTree& source); /** * Delete node in a tree. If we delete a node, we must delist it from * it's parent. We must also delink any child nodes. This is done by * calling the purge() member. */ virtual ~NamedTree(); /** * Performs object destruction. Note, if we delete a named tree object * the name of our member object is assumed to be a dynamically allocated * string that will also be free'd. */ void purge(void); public: /** * Find a child node of our object with the specified name. This will * also recursivily search all child nodes that have children until * the named node can be found. This seeks a child node that has * children. * @param name to search for. * @return tree object found or NULL. */ NamedTree *find(const char *name) const; /** * Find a subnode by a dot separated list of node names. If one or * more lead dots are used, then the search will go through parent * node levels of our node. The dot separated list could be thought * of as a kind of pathname where dot is used like slash. This implies * that individual nodes can never use names which contain dot's if * the path function will be used. * @param path name string being sought. * @return tree node object found at the path or NULL. */ NamedTree *path(const char *path) const; /** * Find a child leaf node of our object with the specified name. This * will recursively search all our child nodes until it can find a leaf * node containing the specified id but that holds no further children. * @param name of leaf node to search for. * @return tree node object found or NULL. */ NamedTree *leaf(const char *name) const; /** * Find a direct child of our node which matches the specified name. * @param name of child node to find. * @return tree node object of child or NULL. */ NamedTree *getChild(const char *name) const; /** * Find a direct leaf node on our node. A leaf node is a node that has * no children of it's own. This does not perform a recursive search. * @param name of leaf child node to find. * @return tree node object of leaf or NULL. */ NamedTree *getLeaf(const char *name) const; /** * Get first child node in our ordered list of children. This might * be used to iterate child nodes. This may also be used to get * unamed child nodes. * @return first child node or NULL if no children. */ inline NamedTree *getFirst(void) const { return static_cast(Child.begin()); } /** * Get parent node we are listed as a child on. * @return parent node or NULL if none. */ inline NamedTree *getParent(void) const { return static_cast(Parent); }; /** * Get child by index number. * @param index of child to fetch. * @return indexed child node. */ inline NamedTree *getIndexed(unsigned index) const { return static_cast(Child.getIndexed(index)); } /** * Get the ordered index of our child nodes. * @return ordered index of our children. */ inline OrderedIndex *getIndex(void) const { return const_cast(&Child); } /** * Test if this node has a name. * @return true if name is set. */ inline operator bool() const { return (Id != NULL); } /** * Test if this node is unnamed. * @return false if name is set. */ inline bool operator!() const { return (Id == NULL); } /** * Set or replace the name id of this node. This will free the string * if a name had already been set. * @param name for this node to set. */ void setId(char *name); /** * Remove our node from our parent list. The name is set to NULL to * keep delete from freeing the name string. */ void remove(void); /** * Test if node has children. * @return true if node contains child nodes. */ inline bool is_leaf(void) const { return (Child.begin() == NULL); } /** * Test if node is root node. * @return true if node is root node. */ inline bool is_root(void) const { return (Parent == NULL); } /** * Add leaf to a trunk, by order. If NULL, just remove. * @param trunk we add leaf node to. */ void relistTail(NamedTree *trunk); /** * Add leaf to a trunk, by reverse order. If NULL, just remove. * @param trunk we add leaf node to. */ void relistHead(NamedTree *trunk); /** * Default relist is by tail... * @param trunk we add leaf node to, NULL to delist. */ inline void relist(NamedTree *trunk = NULL) { relistTail(trunk); } }; /** * A double linked list object. This is used as a base class for objects * that will be organized through ordered double linked lists which allow * convenient insertion and deletion of list members anywhere in the list. * @author David Sugar */ class __EXPORT LinkedList : public OrderedObject { protected: friend class ObjectQueue; LinkedList *Prev; OrderedIndex *Root; /** * Construct and add our object to an existing double linked list at end. * @param index of linked list we are listed in. */ LinkedList(OrderedIndex *index); /** * Construct an unlinked object. */ LinkedList(); /** * Delete linked list object. If it is a member of a list of objects, * then the list is reformed around us. */ virtual ~LinkedList(); public: /** * Remove our object from the list it is currently part of. */ void delist(void); /** * Attach our object to the start of a linked list though an ordered index. * If we are already attached to a list we are delisted first. * @param index of linked list we are joining. */ void enlistHead(OrderedIndex *index); /** * Attach our object to the end of a linked list though an ordered index. * If we are already attached to a list we are delisted first. * @param index of linked list we are joining. */ void enlistTail(OrderedIndex *index); /** * Attach our object to a linked list. The default strategy is to add * to tail. * @param index of linked list we are joining. */ void enlist(OrderedIndex *index); /** * Test if we are at the head of a list. * @return true if we are the first node in a list. */ inline bool is_head(void) const { return polypointer_cast(Root->head) == this; } /** * Test if we are at the end of a list. * @return true if we are the last node in a list. */ inline bool is_tail(void) const { return polypointer_cast(Root->tail) == this; } /** * Get previous node in the list for reverse iteration. * @return previous node in list. */ inline LinkedList *getPrev(void) const { return static_cast(Prev); } /** * Get next node in the list when iterating. * @return next node in list. */ inline LinkedList *getNext(void) const { return static_cast(LinkedObject::getNext()); } /** * Insert object behind our object. * @param object to add to list. */ void insertTail(LinkedList *object); /** * Insert object in front of our object. * @param object to add to list. */ void insertHead(LinkedList *object); /** * Insert object, method in derived object. * @param object to add to list. */ virtual void insert(LinkedList *object); /** * Insert object behind our object. * @param object to add to list. */ inline void operator+=(LinkedList *object) { insertTail(object); } /** * Insert object in front of our object. * @param object to add to list. */ inline void operator-=(LinkedList *object) { insertHead(object); } /** * Insert object in list with our object. * @param object to add to list. */ inline void operator*=(LinkedList *object) { insert(object); } }; /** * A queue of double linked object. This uses the linkedlist class to * form a basic queue of objects. * @author David Sugar */ class __EXPORT ObjectQueue : public OrderedIndex { public: /** * Create an empty object queue. */ ObjectQueue(); /** * Add an object to the end of the queue. * @param object to add. */ void add(DLinkedObject *object); /** * Push an object to the front of the queue. * @param object to push. */ void push(DLinkedObject *object); /** * Pull an object from the front of the queue. * @return object pulled or NULL if empty. */ DLinkedObject *pull(void); /** * Pop an object from the end of the queue. * @return object popped or NULL if empty. */ DLinkedObject *pop(void); }; class __EXPORT ObjectStack { protected: LinkedObject *root; public: /** * Create an empty stack. */ ObjectStack(); /** * Create a stack from an existing list of objects. * @param list of already linked objects. */ ObjectStack(LinkedObject *list); /** * Push an object onto the stack. * @param object to push. */ void push(LinkedObject *object); /** * Pull an object from the stack. * @return object popped from stack or NULL if empty. */ LinkedObject *pull(void); /** * Pop an object from the stack. * @return object popped from stack or NULL if empty. */ inline LinkedObject *pop(void) { return ObjectStack::pull(); } }; /** * A multipath linked list where membership is managed in multiple * lists. * @author David Sugar */ class __EXPORT MultiMap : public ReusableObject { private: typedef struct { const char *key; size_t keysize; MultiMap *next; MultiMap **root; } link_t; unsigned paths; link_t *links; protected: /** * Initialize a multilist object. * @param count of link paths. */ MultiMap(unsigned count); /** * Destroy a multilist object. */ virtual ~MultiMap(); /** * Modifiable interface for key matching. * @param path to check. * @param key to check. * @param size of key to check or 0 if NULL terminated string. * @return true if matches key. */ virtual bool equal(unsigned path, caddr_t key, size_t size) const; public: /** * Enlist on a single linked list. * @param path to attach through. * @param root of list to attach. */ void enlist(unsigned path, MultiMap **root); /** * Enlist binary key on a single map path. * @param path to attach through. * @param index to attach to. * @param key value to use. * @param size of index. * @param keysize of key or 0 if NULL terminated string. */ void enlist(unsigned path, MultiMap **index, caddr_t key, unsigned size, size_t keysize = 0); /** * De-list from a single map path. * @param path to detach from. */ void delist(unsigned path); /** * Get next node from single chain. * @param path to follow. */ MultiMap *next(unsigned path) const; /** * Compute binary key index. * @param key memory to compute. * @param max size of index. * @param size of key or 0 if NULL terminated string. * @return associated hash value. */ static unsigned keyindex(caddr_t key, unsigned max, size_t size = 0); /** * Find a multikey node. * @return node that is found or NULL if none. * @param path of table. * @param index of hash table. * @param key to locate. * @param max size of index. * @param size of key or 0 if NULL terminated string. */ static MultiMap *find(unsigned path, MultiMap **index, caddr_t key, unsigned max, size_t size = 0); }; /** * Template value class to embed data structure into a named list. * This is used to form a class which can be searched by name and that * contains a member value object. Most of the core logic for this * template is found in and derived from the object_value template. * @author David Sugar */ template class named_value : public object_value { public: /** * Construct embedded named object on a linked list. * @param root node or pointer for list. * @param name of our object. */ inline named_value(LinkedObject **root, char *name) { LinkedObject::enlist(root); O::id = name; } /** * Assign embedded value from related type. * @param typed_value to assign. */ inline void operator=(const T& typed_value) { this->set(typed_value); } /** * Find embedded object in chain by name. * @param first object in list to search from. * @param name to search for. * @return composite object found by name or NULL if not found. */ inline static named_value find(named_value *first, const char *name) { return static_cast(NamedObject::find(first, name)); } }; /** * Template value class to embed data structure into a linked list. * This is used to form a class which can be linked together using * either an ordered index or simple linked pointer chain and that * contains a member value object. Most of the core logic for this * template is found in and derived from the object_value template. * @author David Sugar */ template class linked_value : public object_value { public: /** * Create embedded value object unlinked. */ inline linked_value() {} /** * Construct embedded object on a linked list. * @param root node or pointer for list. */ inline linked_value(LinkedObject **root) { LinkedObject::enlist(root); } /** * Construct embedded object on an ordered list. * @param index pointer for the ordered list. */ inline linked_value(OrderedIndex *index) { O::enlist(index); } /** * Assign embedded value from related type and link to list. * @param root node or pointer for list. * @param typed_value to assign. */ inline linked_value(LinkedObject **root, const T& typed_value) { LinkedObject::enlist(root); this->set(typed_value); } /** * Assign embedded value from related type and add to list. * @param index to list our object on. * @param typed_value to assign. */ inline linked_value(OrderedIndex *index, const T& typed_value) { O::enlist(index); this->set(typed_value); } /** * Assign embedded value from related type. * @param typed_value to assign. */ inline void operator=(const T& typed_value) { this->set(typed_value); } }; /** * Template for typesafe basic object stack container. The object type, T, * that is contained in the stack must be derived from LinkedObject. * @author David Sugar */ template class objstack : public ObjectStack { public: /** * Create a new object stack. */ inline objstack() : ObjectStack() {} /** * Create an object stack from a list of objects. */ inline objstack(T *list) : ObjectStack(list) {} /** * Push an object onto the object stack. * @param object of specified type to push. */ inline void push(T *object) { ObjectStack::push(polypointer_cast(object)); } /** * Add an object onto the object stack. * @param object of specified type to push. */ inline void add(T *object) { ObjectStack::push(polypointer_cast(object)); } /** * Pull an object from the object stack. * @return object of specified type or NULL if empty. */ inline T *pull(void) { return static_cast(ObjectStack::pull()); } /** * Pull (pop) an object from the object stack. * @return object of specified type or NULL if empty. */ inline T *pop(void) { return static_cast(ObjectStack::pull()); } }; /** * Template for typesafe basic object fifo container. The object type, T, * that is contained in the fifo must be derived from OrderedObject or * LinkedObject. * @author David Sugar */ template class objfifo : public OrderedIndex { public: /** * Create a new object stack. */ inline objfifo() : OrderedIndex() {} /** * Push an object onto the object fifo. * @param object of specified type to push. */ inline void push(T *object) { OrderedIndex::add(polypointer_cast(object)); } /** * Add an object onto the object fifo. * @param object of specified type to push. */ inline void add(T *object) { OrderedIndex::add(polypointer_cast(object)); } /** * Pull an object from the object stack. * @return object of specified type or NULL if empty. */ inline T *pull(void) { return static_cast(OrderedIndex::get()); } /** * Pull (pop) an object from the object stack. * @return object of specified type or NULL if empty. */ inline T *pop(void) { return static_cast(OrderedIndex::get()); } }; /** * Template for typesafe basic object queue container. The object type, T, * that is contained in the fifo must be derived from DLinkedObject. * @author David Sugar */ template class objqueue : public ObjectQueue { public: /** * Create a new object stack. */ inline objqueue() : ObjectQueue() {} /** * Push an object to start of queue. * @param object of specified type to push. */ inline void push(T *object) { ObjectQueue::push(polypointer_cast(object)); } /** * Add an object to the end of the object queue. * @param object of specified type to add. */ inline void add(T *object) { ObjectQueue::add(polypointer_cast(object)); } /** * Pull an object from the start of the object queue. * @return object of specified type or NULL if empty. */ inline T *pull(void) { return static_cast(ObjectQueue::pull()); } /** * Pop an object from the end of the object queue. * @return object of specified type or NULL if empty. */ inline T *pop(void) { return static_cast(ObjectQueue::pop()); } }; /** * A smart pointer template for iterating linked lists. This class allows * one to access a list of single or double linked objects and iterate * through each member of a list. * @author David Sugar */ template class linked_pointer { private: T *ptr; public: /** * Create a linked pointer and assign to start of a list. * @param pointer to first member of a linked list. */ inline linked_pointer(T *pointer) { ptr = pointer; } /** * Create a copy of an existing linked pointer. * @param pointer to copy from. */ inline linked_pointer(const linked_pointer &pointer) { ptr = pointer.ptr; } /** * Create a linked pointer assigned from a raw linked object pointer. * @param pointer to linked object. */ inline linked_pointer(LinkedObject *pointer) { ptr = static_cast(pointer); } inline linked_pointer(const LinkedObject *pointer) { ptr = static_cast(pointer); } /** * Create a linked pointer to examine an ordered index. * @param index of linked objects to iterate through. */ inline linked_pointer(OrderedIndex *index) { ptr = static_cast(index->begin()); } /** * Create a linked pointer not attached to a list. */ inline linked_pointer() { ptr = NULL; } /** * Assign our typed iterative pointer from a matching typed object. * @param pointer to typed object. */ inline void operator=(T *pointer) { ptr = pointer; } /** * Assign our pointer from another pointer. * @param pointer to assign from. */ inline void operator=(linked_pointer &pointer) { ptr = pointer.ptr; } /** * Assign our pointer from the start of an ordered index. * @param index to assign pointer from. */ inline void operator=(OrderedIndex *index) { ptr = static_cast(index->begin()); } /** * Assign our pointer from a generic linked object pointer. * @param pointer of linked list. */ inline void operator=(LinkedObject *pointer) { ptr = static_cast(pointer); } /** * Return member from typed object our pointer references. * @return evaluated member of object we point to. */ inline T* operator->() const { return ptr; } /** * Return object we currently point to. * @return object linked pointer references. */ inline T* operator*() const { return ptr; } /** * Return object we point to by casting. * @return object linked pointer references. */ inline operator T*() const { return ptr; } /** * Move (iterate) pointer to previous member in double linked list. */ inline void prev(void) { ptr = static_cast(ptr->getPrev()); } /** * Move (iterate) pointer to next member in linked list. */ inline void next(void) { ptr = static_cast(ptr->getNext()); } /** * Get the next member in linked list. Do not change who we point to. * @return next member in list or NULL if end of list. */ inline T *getNext(void) const { return static_cast(ptr->getNext()); } /** * Get the previous member in double linked list. Do not change who we * point to. * @return previous member in list or NULL if start of list. */ inline T *getPrev(void) const { return static_cast(ptr->getPrev()); } /** * Move (iterate) pointer to next member in linked list. */ inline void operator++() { ptr = static_cast(ptr->getNext()); } /** * Move (iterate) pointer to previous member in double linked list. */ inline void operator--() { ptr = static_cast(ptr->getPrev()); } /** * Test for next member in linked list. * @return true if there is more members after current one. */ inline bool is_next(void) const { return (ptr->getNext() != NULL); } /** * Test for previous member in double linked list. * @return true if there is more members before current one. */ inline bool is_prev(void) const { return (ptr->getPrev() != NULL); } /** * Test if linked pointer is set/we are not at end of list. * @return true if we are not at end of list. */ inline operator bool() const { return (ptr != NULL); } /** * Test if linked list is empty/we are at end of list. * @return true if we are at end of list. */ inline bool operator!() const { return (ptr == NULL); } /** * Return pointer to our linked pointer to use as root node of a chain. * @return our object pointer as a root index. */ inline LinkedObject **root(void) const { T **r = &ptr; return static_cast(r); } }; /** * Embed data objects into a multipap structured memory database. This * can be used to form multi-key hash nodes. Embedded values can either be * of direct types that are then stored as part of the template object, or * of class types that are data pointers. * @author David Sugar */ template class multimap : public MultiMap { protected: T value; public: /** * Construct a multimap node. */ inline multimap() : MultiMap(P) {} /** * Destroy a multimap object. */ inline ~multimap() {} /** * Return the typed value of this node. * @return reference to value of node. */ inline T &get(void) const { return value; } /** * Return next multimap typed object. * @param path to follow. * @return multimap typed. */ inline multimap *next(unsigned path) { return static_cast(MultiMap::next(path)); } /** * Return typed value of this node by pointer reference. * @return value of node. */ inline T& operator*() const { return value; } /** * Set the pointer of a pointer based value tree. * @param pointer to set. */ inline void setPointer(const T pointer) { value = pointer; } /** * Set the value of a data based value tree. * @param reference to value to copy into node. */ inline void set(const T &reference) { value = reference; } /** * Assign the value of our node. * @param data value to assign. */ inline void operator=(const T& data) { value = data; } /** * Find multimap key entry. * @param path to search through. * @param index of associated keys. * @param key to search for, binary or NULL terminated string. * @param size of index used. * @param keysize or 0 if NULL terminated string. * @return multipath typed object. */ inline static multimap *find(unsigned path, MultiMap **index, caddr_t key, unsigned size, unsigned keysize = 0) { return static_cast(MultiMap::find(path, index, key, size, keysize)); } }; /** * Embed data objects into a tree structured memory database. This can * be used to form XML document trees or other data structures that * can be organized in trees. The NamedTree class is used to manage * the structure of the tree, and the type specified is embedded as a * data value object which can be manipulated. Name identifiers are * assumed to be dynamically allocated if tree node elements are deletable. * * Embedded values can either be of direct types that are then stored as * part of the template object, or of class types that are data pointers. * The latter might be used for trees that contain data which might be * parsed dynamically from a document and/or saved on a heap. Pointer trees * assume that NULL pointers are for nodes that are empty, and that NULL data * value nodes with children are trunk nodes. Generally data values are then * allocated with a pointer stored in pure leaf nodes. * @author David Sugar */ template class treemap : public NamedTree { protected: T value; public: /** * Construct a typed root node for the tree. The root node may be * named as a stand-alone node or unnamed. * @param name of the node we are creating. */ inline treemap(char *name = NULL) : NamedTree(name) {} /** * Construct a copy of the treemap object. * @param source of copy for new object. */ inline treemap(const treemap& source) : NamedTree(source) { value = source.value; }; /** * Construct a child node on an existing tree. * @param parent of this node to attach. * @param name of this node. */ inline treemap(treemap *parent, char *name) : NamedTree(parent, name) {} /** * Construct a child node on an existing tree and assign it's value. * @param parent of this node to attach. * @param name of this node. * @param reference to value to assign to this node. */ inline treemap(treemap *parent, char *name, T& reference) : NamedTree(parent, name) { value = reference; } /** * Return the typed value of this node. * @return reference to value of node. */ inline const T& get(void) const { return value; } /** * Return typed value of this node by pointer reference. * @return value of node. */ inline const T& operator*() const { return value; } /** * Return value from tree element when value is a pointer. * @param node in our typed tree. * @return value of node. */ static inline T getPointer(treemap *node) { return (node == NULL) ? NULL : node->value; } /** * Test if this node is a leaf node for a tree pointer table. * @return true if value pointer is not NULL and there are no children. */ inline bool is_attribute(void) const { return (!Child.begin() && value != NULL); } /** * Get the pointer of a pointer based value tree. * @return value pointer of node. */ inline const T getPointer(void) const { return value; } /** * Get the data value of a data based value tree. * @return data value of node. */ inline const T& getData(void) const { return value; } /** * Set the pointer of a pointer based value tree. * @param pointer to set. */ inline void setPointer(const T pointer) { value = pointer; } /** * Set the value of a data based value tree. * @param reference to value to copy into node. */ inline void set(const T& reference) { value = reference; } /** * Assign the value of our node. * @param data value to assign. */ inline void operator=(const T& data) { value = data; } /** * Get child member node by index. * @param index of child member. * @return node or NULL if past end. */ inline treemap *getIndexed(unsigned index) const { return static_cast(Child.getIndexed(index)); } /** * Get the typed parent node for our node. * @return parent node or NULL if root of tree. */ inline treemap *getParent(void) const { return static_cast(Parent); } /** * Get direct typed child node of our node of specified name. This * does not perform a recursive search. * @param name of child node. * @return typed child node pointer or NULL if not found. */ inline treemap *getChild(const char *name) const { return static_cast(NamedTree::getChild(name)); } /** * Find a direct typed leaf node on our node. A leaf node is a node that * has no children of it's own. This does not perform a recursive search. * @param name of leaf child node to find. * @return typed leaf node object of leaf or NULL. */ inline treemap *getLeaf(const char *name) const { return static_cast(NamedTree::getLeaf(name)); } /** * Get the value pointer of a leaf node of a pointer tree. This allows * one to find a leaf node and return it's pointer value in a single * operation. * @param name of leaf node. * @return value of leaf pointer if found and contains value, or NULL. */ inline T getValue(const char *name) const { return getPointer(getLeaf(name)); } /** * Find a subnode from our node by name. This performs a recursive * search. * @param name to search for. * @return typed node that is found or NULL if none is found. */ inline treemap *find(const char *name) const { return static_cast(NamedTree::find(name)); } /** * Find a subnode by pathname. This is the same as the NamedTree * path member function. * @param path name to search for node. * @return typed node that is found at path or NULL. */ inline treemap *path(const char *path) const { return static_cast(NamedTree::path(path)); } /** * Search for a leaf node of our node. This performs a recursive * search. * @param name to search for. * @return typed not that is found or NULL if none is found. */ inline treemap *leaf(const char *name) const { return static_cast(NamedTree::leaf(name)); } /** * Get first child of our node. This is useful for iterating children. * @return first child or NULL. */ inline treemap *getFirst(void) const { return static_cast(NamedTree::getFirst()); } }; /** * A template class for a hash map. This provides a has map index object as * a chain of keyindex selected linked pointers of a specified size. This * is used for the index and size values for NamedObject's which are listed * on a hash map. * @author David Sugar */ template class keymap { private: NamedObject *idx[M]; public: /** * Destroy the hash map by puring the index chains. */ inline ~keymap() { NamedObject::purge(idx, M); } /** * Retrieve root of index to use in NamedObject constructors. * @return root node of index. */ inline NamedObject **root(void) const { return idx; } /** * Retrieve key size to use in NamedObject constructors. * @return key size of hash map. */ inline unsigned limit(void) const { return M; } /** * Find a typed object derived from NamedObject in the hash map by name. * @param name to search for. * @return typed object if found through map or NULL. */ inline T *get(const char *name) const { return static_cast(NamedObject::map(idx, name, M)); } /** * Find a typed object derived from NamedObject in the hash map by name. * @param name to search for. * @return typed object if found through map or NULL. */ inline T& operator[](const char *name) const { return static_cast(NamedObject::map(idx, name, M)); } /** * Add a typed object derived from NamedObject to the hash map by name. * @param name to add. * @param object to add. */ inline void add(const char *name, T& object) { object.NamedObject::add(idx, name, M); } /** * Add a typed object derived from NamedObject to the hash map by name. * @param name to add. * @param object to add. */ inline void add(const char *name, T *object) { object->NamedObject::add(idx, name, M); } /** * Remove a typed object derived from NamedObject to the hash map by name. * @param name to remove. * @return object removed if found or NULL. */ inline T *remove(const char *name) { return static_cast(NamedObject::remove(idx, name, M)); } /** * Find first typed object in hash map to iterate. * @return first typed object or NULL if nothing in list. */ inline T *begin(void) const { return static_cast(NamedObject::skip(idx, NULL, M)); } /** * Find next typed object in hash map for iteration. * @param current typed object we are referencing. * @return next iterative object or NULL if past end of map. */ inline T *next(T *current) const { return static_cast(NamedObject::skip(idx, current, M)); } /** * Count the number of typed objects in our hash map. * @return count of typed objects. */ inline unsigned count(void) const { return NamedObject::count(idx, M); } /** * Convert our hash map into a linear object pointer array. The * object pointer array is created from the heap and must be deleted * when no longer used. * @return array of typed named object pointers. */ inline T **index(void) const { return NamedObject::index(idx, M); } /** * Convert our hash map into an alphabetically sorted linear object * pointer array. The object pointer array is created from the heap * and must be deleted when no longer used. * @return sorted array of typed named object pointers. */ inline T **sort(void) const { return NamedObject::sort(NamedObject::index(idx, M)); } /** * Convenience typedef for iterative pointer. */ typedef linked_pointer iterator; }; /** * A template for ordered index of typed name key mapped objects. * This is used to hold an iterable linked list of typed named objects * where we can find objects by their name as well as through iteration. * @author David Sugar */ template class keylist : public OrderedIndex { public: /** * Return a root node pointer to use in NamedObject constructors. * @return pointer to index root. */ inline NamedObject **root(void) { return static_cast(&head); } /** * Return first item in ordered list. This is commonly used to * iterate the list. * @return first item in list or NULL if empty. */ inline T *begin(void) { return static_cast(head); } /** * Return last item in ordered list. This is commonly used to determine * end of list iteration. * @return last item in list or NULL if empty. */ inline T *end(void) { return static_cast(tail); } /** * Create a new typed named object with default constructor. * This creates a new object which can be deleted. * @param name of object to create. * @return typed named object. */ inline T *create(const char *name) { return new T(this, name); } /** * Iterate next object in list. * @param current object we are referencing. * @return next logical object in linked list or NULL if end. */ inline T *next(LinkedObject *current) { return static_cast(current->getNext()); } /** * Find a specific object by name. * @param name to search for. * @return type named object that matches or NULL if not found. */ inline T *find(const char *name) { return static_cast(NamedObject::find(begin(), name)); } inline T *offset(unsigned offset) { return static_cast(OrderedIndex::find(offset)); } /** * Retrieve a specific object by position in list. * @param offset in list for object we want. * @return type named object or NULL if past end of list. */ inline T& operator[](unsigned offset) { return static_cast(OrderedIndex::find(offset)); } inline T& operator[](const char *name) { return static_cast(NamedObject::find(begin(), name)); } /** * Convert our linked list into a linear object pointer array. The * object pointer array is created from the heap and must be deleted * when no longer used. * @return array of typed named object pointers. */ inline T **index(void) { return static_cast(OrderedIndex::index()); } /** * Convert our linked list into an alphabetically sorted linear object * pointer array. The object pointer array is created from the heap * and must be deleted when no longer used. * @return array of typed named object pointers. */ inline T **sort(void) { return static_cast(NamedObject::sort(index())); } /** * Convenience typedef for iterative pointer. */ typedef linked_pointer iterator; }; /** * Convenience typedef for root pointers of single linked lists. */ typedef LinkedObject *LinkedIndex; /** * Convenience type for a stack of linked objects. */ typedef ObjectStack objstack_t; /** * Convenience type for a fifo of linked objects. */ typedef OrderedIndex objfifo_t; /** * Convenience type for a queue of linked objects. */ typedef ObjectQueue objqueue_t; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/stl.h0000664000175000017500000000255012504226753013336 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Placeholder for future classes that require stl support. * @file ucommon/stl.h */ #ifndef UCOMMON_SYSRUNTIME #if !defined(_MSC_VER) || _MSC_VER >= 1400 #ifndef _UCOMMON_STL_H_ #define _UCOMMON_STL_H_ #ifndef _UCOMMON_PLATFORM_H_ #include #endif #include // example... namespace ucommon { /* In the future we may introduce optional classes which require and/or build upon the standard template library. This header indicates how and where they may be added. */ } // namespace ucommon #endif #endif #endif ucommon-6.4.4/inc/ucommon/atomic.h0000664000175000017500000000745212555173716014024 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Atomic pointers and locks. These are meant to use atomic CPU operations * and hence offer maximum performance. * @file ucommon/atomic.h * @author David Sugar */ #ifndef _UCOMMON_ATOMIC_H_ #define _UCOMMON_ATOMIC_H_ #ifndef _UCOMMON_CONFIG_H_ #include #endif #ifdef _MSWINDOWS_ typedef LONG atomic_t; #else typedef int atomic_t; #endif namespace ucommon { /** * Generic atomic class for referencing atomic objects and static functions. * We have an atomic counter and spinlock, and in the future we may add * other atomic classes and atomic manipulations needed to create lockfree * data structures. The atomic classes use mutexes if no suitable atomic * code is available. * @author David Sugar */ class __EXPORT atomic { public: /** * Set to true if atomics have to be simulated with mutexes. */ static const bool simulated; /** * Atomic counter class. Can be used to manipulate value of an * atomic counter without requiring explicit thread locking. * @author David Sugar */ class __EXPORT counter { private: mutable volatile atomic_t value; public: counter(atomic_t initial = 0); // fetch add/sub optimized semantics atomic_t fetch_add(atomic_t offset = 1) volatile; atomic_t fetch_sub(atomic_t offset = 1) volatile; atomic_t operator++() volatile; atomic_t operator--() volatile; atomic_t operator+=(atomic_t offset) volatile; atomic_t operator-=(atomic_t offset) volatile; atomic_t get() volatile; void clear() volatile; inline operator atomic_t() volatile { return get(); } inline atomic_t operator*() volatile { return get(); } }; /** * Atomic spinlock class. Used as high-performance sync lock between * threads. * @author David Sugar */ class __EXPORT spinlock { private: #ifdef __GNUC__ mutable volatile atomic_t value __attribute__ ((aligned(16))); #else mutable volatile atomic_t value; #endif public: /** * Construct and initialize spinlock. */ spinlock(); /**NAMESPACE_UCOMMON * Acquire the lock. If the lock is not acquired, one "spins" * by doing something else. One suggestion is using thread::yield. * @return true if acquired. */ bool acquire(void) volatile; /** * Wait for and aquire spinlock. */ void wait(void) volatile; /** * Release an acquired spinlock. */ void release(void) volatile; }; /** * Atomically aligned heap alloc function. * @param size of memory to allocate. * @return pointer or NULL if cannot alloc. */ static void *alloc(size_t size); }; // for abi7 typedef atomic Atomic; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/mapped.h0000664000175000017500000004004512504226574014004 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Support for memory mapped objects. * Memory mapped objects can be used to publish information so that it may be * accessible directly by external programs. The mapped memory objects will * usually be built as a vector vector or reusable type factory, in the latter * case using the allocated shared memory block itself as a local heap. A * simple template can be used to view the mapped contents that have been * published by another process. * @file ucommon/mapped.h */ #ifndef _UCOMMON_MAPPED_H_ #define _UCOMMON_MAPPED_H_ #ifndef _UCOMMON_LINKED_H_ #include #endif #ifndef _UCOMMON_THREAD_H_ #include #endif #ifndef _UCOMMON_STRING_H_ #include #endif #ifndef _MSWINDOWS_ #include #endif namespace ucommon { /** * Construct or access a named section of memory. A logical name is used * which might map to something that is invoked from a call like shm_open * or a named w32 mapped swap segment. This is meant to support mapping a * vector onto shared memory and is often used as a supporting class for our * shared memory access templates. * @author David Sugar */ class __EXPORT MappedMemory { private: size_t mapsize; caddr_t map; fd_t fd; protected: size_t size, used; char idname[65]; bool erase; MappedMemory(); /** * Supporting function to construct a new or access an existing * shared memory segment. Used by primary constructors. * @param name of segment to create or access. * @param size of segment if creating new. Use 0 for read-only access. */ void create(const char *name, size_t size = (size_t)0); /** * Handler to invoke in derived class when accessing outside the * shared memory segment boundary. */ virtual void *invalid(void) const; /** * Handler for failure to map (allocate) memory. */ virtual void fault(void) const; public: /** * Construct a read/write access mapped shared segment of memory of a * known size. This constructs a new memory segment. * @param name of segment. * @param size of segment. */ MappedMemory(const char *name, size_t size); /** * Provide read-only mapped access to an existing named shared memory * segment. The size of the map is found by the size of the already * existing segment. * @param name of existing segment. */ MappedMemory(const char *name); /** * Unmap memory segment. */ virtual ~MappedMemory(); /** * Unmap memory segment. */ void release(void); /** * Destroy a previously existing memory segment under the specified name. * This is used both before creating a new one, and after a publishing * process unmaps the segment it created. * @param name of segment to remove. */ static void remove(const char *name); /** * Test if map active. * @return true if active map. */ inline operator bool() const {return (size != 0);} /** * Test if map is inactive. * @return true if map inactive. */ inline bool operator!() const {return (size == 0);} /** * Extend size of managed heap on shared memory segment. This does not * change the size of the mapped segment in any way, only that of any * heap space that is being allocated and used from the mapped segment. * @return start of space from map. * @param size of space requested. Will fault if past end of segment. */ void *sbrk(size_t size); /** * Get memory from a specific offset within the mapped memory segment. * @param offset from start of segment. Will fault if past end. * @return address of offset. */ void *offset(size_t offset) const; /** * Copy memory from specific offset within the mapped memory segment. * This function assures the copy is not in the middle of being modified. * @param offset from start of segment. * @param buffer to copy into. * @param size of object to copy. * @return true on success. */ bool copy(size_t offset, void *buffer, size_t size) const; /** * Get size of mapped segment. * @return size of mapped segment. */ inline size_t len(void) const {return size;} /** * Get starting address of mapped segment. * @return starting address of mapped segment. */ inline caddr_t addr(void) {return map;} /** * An API that allows "disabling" of publishing shared memory maps. * This may be useful when an app doesn't want to use shared memory * as a runtime or build option, but does not want to have to be "recoded" * explicitly for non-shared memory either. Basically it substitutes a * dummy map running on the local heap. */ static void disable(void); }; /** * Map a reusable allocator over a named shared memory segment. This may be * used to form a resource bound fixed size managed heap in shared memory. * The request can either be fulfilled from the object reuse pool or from a * new section of memory, and if all memory in the segment has been exhausted, * it can wait until more objects are returned by another thread to the reuse * pool. * @author David Sugar */ class __EXPORT MappedReuse : protected ReusableAllocator, protected MappedMemory { private: unsigned objsize; unsigned reading; mutex_t mutex; protected: MappedReuse(size_t osize); inline void create(const char *fname, unsigned count) {MappedMemory::create(fname, count * objsize);} public: /** * Construct a named memory segment for use with managed fixed size * reusable objects. The segment is created as writable. There is no * read-only version of mapped reuse since the mapped segment can be read * by another process directly as a mapped read-only vector. The actual * mapped type will be derived from ReusableObject to meet the needs of * the reusable allocator. The template version should be used to * assure type correctness rather than using this class directly. * @param name of shared memory segment. * @param size of the object type being mapped. * @param count of the maximum number of active mapped objects. */ MappedReuse(const char *name, size_t size, unsigned count); /** * Check whether there are objects available to be allocated. * @return true if objects are available. */ bool avail(void) const; /** * Request a reusable object from the free list or mapped space. * @return free object or NULL if pool is exhausted. */ ReusableObject *request(void); /** * Request a reusable object from the free list or mapped space. * This method blocks until an object becomes available. * @return free object. */ ReusableObject *get(void); /** * Request a reusable object from the free list or mapped space. * This method blocks until an object becomes available or the * timeout has expired. * @param timeout to wait in milliseconds. * @return free object or NULL if timeout. */ ReusableObject *getTimed(timeout_t timeout); /** * Used to get an object from the reuse pool when the mutex lock is * already held. * @return object from pool or NULL if exhausted. */ ReusableObject *getLocked(void); /** * Used to return an object to the reuse pool when the mutex lock is * already held. * @param object being returned. */ void removeLocked(ReusableObject *object); }; /** * Template class to map typed vector into shared memory. This is used to * construct a typed read/write vector of objects that are held in a named * shared memory segment. * @author David Sugar */ template class mapped_array : public MappedMemory { protected: inline mapped_array() : MappedMemory() {} inline void create(const char *fn, unsigned members) {MappedMemory::create(fn, members * sizeof(T));} public: /** * Construct mapped vector array of typed objects. This is constructed * for read/write access. mapped_view is used in all cases for read-only * access to mapped data. Member objects are linearly allocated from * the shared memory segment, or may simply be directly accessed by offset. * @param name of mapped segment to construct. * @param number of objects in the mapped vector. */ inline mapped_array(const char *name, unsigned number) : MappedMemory(name, number * sizeof(T)) {} /** * Initialize typed data in mapped array. Assumes default constructor * for type. */ inline void initialize(void) {new((caddr_t)offset(0)) T[size / sizeof(T)];} /** * Add mapped space while holding lock for one object. * @return address of object. */ inline void *addLock(void) {return sbrk(sizeof(T));} /** * Get typed pointer to member object of vector in mapped segment. * @param member to access. * @return typed pointer or NULL if past end of array. */ inline T *operator()(unsigned member) {return static_cast(offset(member * sizeof(T)));} /** * Allocate mapped space for one object. * @return address of object. */ inline T *operator()(void) {return static_cast(sbrk(sizeof(T)));} /** * Reference typed object of vector in mapped segment. * @param member to access. * @return typed reference. */ inline T& operator[](unsigned member) {return *(operator()(member));} /** * Get member size of typed objects that can be held in mapped vector. * @return members mapped in segment. */ inline unsigned max(void) const {return (unsigned)(size / sizeof(T));} }; /** * Template class to map typed reusable objects into shared memory heap. * This is used to construct a read/write heap of objects that are held in a * named shared memory segment. Member objects are allocated from a reusable * heap but are stored in the shared memory segment as a vector. * @author David Sugar */ template class mapped_reuse : public MappedReuse { protected: inline mapped_reuse() : MappedReuse(sizeof(T)) {} public: /** * Construct mapped reuse array of typed objects. This is constructed * for read/write access. mapped_view is used in all cases for read-only * access to mapped data. * @param name of mapped segment to construct. * @param number of objects in the mapped vector. */ inline mapped_reuse(const char *name, unsigned number) : MappedReuse(name, sizeof(T), number) {} /** * Initialize typed data in mapped array. Assumes default constructor * for type. */ inline void initialize(void) {new((caddr_t)pos(0)) T[size / sizeof(T)];} /** * Check whether there are typed objects available to be allocated. * @return true if objects are available. */ inline operator bool() const {return MappedReuse::avail();} /** * Check whether there are typed objects available to be allocated. * @return true if no more typed objects are available. */ inline bool operator!() const {return !MappedReuse::avail();} /** * Request a typed reusable object from the free list or mapped space. * This method blocks until an object becomes available. * @return free object. */ inline operator T*() {return mapped_reuse::get();} /** * Request a typed reusable object from the free list or mapped space by * pointer reference. This method blocks until an object becomes available. * @return free object. */ inline T* operator*() {return mapped_reuse::get();} /** * Get typed object from a specific member offset within the mapped segment. * @param member offset from start of segment. Will fault if past end. * @return typed object pointer. */ inline T *pos(size_t member) {return static_cast(MappedReuse::offset(member * sizeof(T)));} /** * Request a typed reusable object from the free list or mapped space. * This method blocks until an object becomes available. * @return free typed object. */ inline T *get(void) {return static_cast(MappedReuse::get());} /** * Request a typed reusable object from the free list or mapped space. * This method blocks until an object becomes available from another * thread or the timeout expires. * @param timeout in milliseconds. * @return free typed object. */ inline T *getTimed(timeout_t timeout) {return static_cast(MappedReuse::getTimed(timeout));} /** * Request a typed reusable object from the free list or mapped space. * This method does not block or wait. * @return free typed object if available or NULL. */ inline T *request(void) {return static_cast(MappedReuse::request());} /** * Used to return a typed object to the reuse pool when the mutex lock is * already held. * @param object being returned. */ inline void removeLocked(T *object) {MappedReuse::removeLocked(object);} /** * Used to get a typed object from the reuse pool when the mutex lock is * already held. * @return typed object from pool or NULL if exhausted. */ inline T *getLocked(void) {return static_cast(MappedReuse::getLocked());} /** * Used to release a typed object back to the reuse typed object pool. * @param object being released. */ inline void release(T *object) {ReusableAllocator::release(object);} }; /** * Class to access a named mapped segment published from another process. * This offers a simple typed vector interface to access the shared memory * segment in read-only mode. * @author David Sugar */ template class mapped_view : protected MappedMemory { public: /** * Map existing named memory segment. The size of the map is derived * from the existing map alone. * @param name of memory segment to map. */ inline mapped_view(const char *name) : MappedMemory(name) {} /** * Access typed member object in the mapped segment. * @param member to access. * @return typed object pointer. */ inline volatile const T *operator()(unsigned member) {return static_cast(offset(member * sizeof(T)));} /** * Reference typed member object in the mapped segment. * @param member to access. * @return typed object reference. */ inline volatile const T &operator[](unsigned member) {return *(operator()(member));} inline volatile const T *get(unsigned member) {return static_cast(offset(member * sizeof(T)));} inline void copy(unsigned member, T& buffer) {MappedMemory::copy(member * sizeof(T), &buffer, sizeof(T));} /** * Get count of typed member objects held in this map. * @return count of typed member objects. */ inline unsigned count(void) const {return (unsigned)(size / sizeof(T));} }; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/access.h0000664000175000017500000002232312537554527014006 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Locking protocol classes for member function automatic operations. * This header covers ucommon access related classes. These are used to * provide automatic management of locks and synchronization objects through * common virtual base classes which can be used with automatic objects. * These classes are related to "protocols" and are used in conjunction * with smart pointer/referencing classes. The access interface supports * member functions to acquire a lock when entered and automatically * release the lock when the member function returns that are used in * conjunction with special referencing smart pointers. * @file ucommon/access.h */ // we do this twice because of some bizarre issue in just this file that // otherwise breaks doxygen and lists all items outside the namespace... #include #ifndef _UCOMMON_ACCESS_H_ #define _UCOMMON_ACCESS_H_ #ifndef _UCOMMON_CPR_H_ #include #endif #ifndef _UCOMMON_PROTOCOLS_H_ #include #endif namespace ucommon { /** * Common unlock protocol for locking protocol interface classes. * This is to assure _unlock is a common base virtual method. * @author David Sugar */ class __EXPORT UnlockAccess { public: virtual ~UnlockAccess(); protected: virtual void _unlock(void) = 0; }; /** * An exclusive locking protocol interface base. * This is an abstract class to form objects that will operate under an * exclusive lock while being actively referenced by a smart pointer. * @author David Sugar */ class __EXPORT ExclusiveAccess : public UnlockAccess { protected: virtual ~ExclusiveAccess(); virtual void _lock(void) = 0; public: /** * Access interface to exclusive lock the object. */ inline void exclusive_lock(void) { return _lock(); } /** * Access interface to release a lock. */ inline void release_exclusive(void) { return _unlock(); } }; /** * An exclusive locking access interface base. * This is an abstract class to form objects that will operate under an * exclusive lock while being actively referenced by a smart pointer. * @author David Sugar */ class __EXPORT SharedAccess : protected UnlockAccess { protected: virtual ~SharedAccess(); protected: /** * Access interface to share lock the object. */ virtual void _share(void) = 0; public: /** * Share the lock with other referencers. Many of our shared locking * objects support the ability to switch between shared and exclusive * mode. This derived protocol member allows one to restore the lock * to shared mode after it has been made exclusive. */ virtual void share(void); /** * Convert object to an exclusive lock. Many of our shared locking * objects such as the "conditional lock" support the ability to switch * between shared and exclusive locking modes. This derived protocol * member allows one to temporarily assert exclusive locking when tied * to such methods. */ virtual void exclusive(void); inline void shared_lock(void) { return _share(); } inline void release_share(void) { return _unlock(); } }; /** * A kind of smart pointer object to support exclusive locking protocol. * This object initiates an exclusive lock for the object being referenced when * it is instantiated, and releases the exclusive lock when it is destroyed. * You would pass the pointer an object that has the Exclusive as a base class. * @author David Sugar */ class __EXPORT exclusive_access { private: ExclusiveAccess *lock; public: /** * Create an instance of an exclusive object reference. * @param object containing Exclusive base class protocol to lock. */ exclusive_access(ExclusiveAccess *object); /** * Destroy reference to exclusively locked object, release lock. */ ~exclusive_access(); /** * Test if the reference holds an active lock. * @return true if is not locking an object. */ inline bool operator!() const { return lock == NULL; } /** * Test if the reference holds an active lock. * @return true if locking an object. */ inline operator bool() const { return lock != NULL; } /** * Release a held lock programmatically. This can be used to de-reference * the object being exclusively locked without having to wait for the * destructor to be called when the exclusive_lock falls out of scope. */ void release(void); }; /** * A kind of smart pointer object to support shared locking protocol. * This object initiates a shared lock for the object being referenced when * it is instantiated, and releases the shared lock when it is destroyed. * You would pass the pointer an object that has the Shared as a base class. * @author David Sugar */ class __EXPORT shared_access { private: SharedAccess *lock; int state; bool modify; public: /** * Create an instance of an exclusive object reference. * @param object containing Exclusive base class protocol to lock. */ shared_access(SharedAccess *object); /** * Destroy reference to shared locked object, release lock. */ ~shared_access(); /** * Test if the reference holds an active lock. * @return true if is not locking an object. */ inline bool operator!() const { return lock == NULL; } /** * Test if the reference holds an active lock. * @return true if locking an object. */ inline operator bool() const { return lock != NULL; } /** * Release a held lock programmatically. This can be used to de-reference * the object being share locked without having to wait for the * destructor to be called when the shared_lock falls out of scope. */ void release(void); /** * Call exclusive access on referenced objects protocol. */ void exclusive(void); /** * Restore shared access on referenced objects protocol. */ void share(void); }; /** * Convenience function to exclusively lock an object through it's protocol. * @param object to lock. */ inline void lock(ExclusiveAccess& object) { object.exclusive_lock(); } /** * Convenience function to unlock an exclusive object through it's protocol. * @param object to unlock. */ inline void unlock(ExclusiveAccess& object) { object.release_exclusive(); } /** * Convenience function to access (lock) shared object through it's protocol. * @param object to share lock. */ inline void access(SharedAccess& object) { object.shared_lock(); } /** * Convenience function to unlock shared object through it's protocol. * @param object to unlock. */ inline void release(SharedAccess& object) { object.release_share(); } /** * Convenience function to exclusive lock shared object through it's protocol. * @param object to exclusive lock. */ inline void exclusive(SharedAccess& object) { object.exclusive(); } /** * Convenience function to restore shared locking for object through it's protocol. * @param object to restore shared locking. */ inline void share(SharedAccess& object) { object.share(); } /** * Convenience type to use for object referencing an exclusive object. */ typedef exclusive_access exlock_t; /** * Convenience type to use for object referencing a shared object. */ typedef shared_access shlock_t; /** * Convenience function to release a reference to an exclusive lock. * @param reference to object referencing exclusive locked object. */ inline void release(exlock_t &reference) { reference.release(); } /** * Convenience function to release a reference to a shared lock. * @param reference to object referencing shared locked object. */ inline void release(shlock_t &reference) { reference.release(); } // Special macros to allow member functions of an object with a protocol // to create self locking states while the member functions are called by // placing an exclusive_lock or shared_lock smart object on their stack // frame to reference their self. #define exclusive_object() exlock_t __autolock__ = this #define protected_object() shlock_t __autolock__ = this #define exclusive_locking(x) exlock_t __autolock__ = &x #define protected_locking(x) shlock_t __autolock__ = &x } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/export.h0000664000175000017500000000347412504226464014062 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Export interfaces for library interfaces. * This is a special header used when we have to build DLL's for dumb * platforms which require explicit declaration of imports and exports. * The real purpose is to include our local headers in a new library * module with external headers referenced as imports, and then to define * our own interfaces in our new library as exports. This allows native * construction of new DLL's based on/that use ucommon on Microsoft Windows * and perhaps for other similarly defective legacy platforms. Otherwise * this header is not used at all, and not when building applications. * @file ucommon/export.h */ #if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) #ifdef __EXPORT #undef __EXPORT #endif #ifdef __SHARED #undef __SHARED #endif #ifdef UCOMMON_STATIC #define __EXPORT #else #define __EXPORT __declspec(dllexport) #endif #if defined(UCOMMON_STATIC) || defined(UCOMMON_RUNTIME) #define __SHARED #else #define __SHARED __declspec(dllexport) #endif #endif ucommon-6.4.4/inc/ucommon/unicode.h0000664000175000017500000004025112544454312014160 00000000000000// Copyright (C) 2009-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Basic UCommon Unicode support. * This includes computing unicode transcoding and supporting a * UTF8-aware string class (UString). We may add support for a wchar_t * aware string class as well, as some external api libraries may require * ucs-2 or 4 encoded strings. * @file ucommon/unicode.h */ /** * An example of some unicode-utf8 transcoding. * @example unicode.cpp */ #ifndef _UCOMMON_UNICODE_H_ #define _UCOMMON_UNICODE_H_ #ifndef _UCOMMON_STRING_H_ #include #endif #ifdef nil #undef nil #endif namespace ucommon { /** * 32 bit unicode character code. We may extract this from a ucs2 or utf8 * string. */ typedef int32_t ucs4_t; /** * 16 bit unicode character code. Java and some api's like these. */ typedef int16_t ucs2_t; /** * Resolves issues where wchar_t is not defined. */ typedef void *unicode_t; /** * A core class of ut8 encoded string functions. This is a foundation for * all utf8 string processing. * @author David Sugar */ class __EXPORT utf8 { public: /** * Size of "unicode_t" character codes, may not be ucs4_t size. */ static const unsigned ucsize; /** * A convenient NULL pointer value. */ static const char *nil; /** * Compute character size of utf8 string codepoint. * @param codepoint in string. * @return size of codepoint as utf8 encoded data, 0 if invalid. */ static unsigned size(const char *codepoint); /** * Count ut8 encoded ucs4 codepoints in string. * @param string of utf8 data. * @return codepount count, 0 if empty or invalid. */ static size_t count(const char *string); /** * Get codepoint offset in a string. * @param string of utf8 data. * @param position of codepoint in string, negative offsets are from tail. * @return offset of codepoint or NULL if invalid. */ static char *offset(char *string, ssize_t position); /** * Convert a utf8 encoded codepoint to a ucs4 character value. * @param encoded utf8 codepoint. * @return ucs4 string or 0 if invalid. */ static ucs4_t codepoint(const char *encoded); /** * How many chars requires to encode a given wchar string. * @param string of ucs4 data. * @return number of chars required to encode given string. */ static size_t chars(const unicode_t string); /** * How many chars requires to encode a given unicode character. * @param character to encode. * @return number of chars required to encode given character. */ static size_t chars(ucs4_t character); /** * Convert a unicode string into utf8. * @param string of unicode data to pack * @param buffer of character protocol to put data into. * @return number of code points converted. */ static size_t unpack(const unicode_t string, CharacterProtocol& buffer); /** * Convert a utf8 string into a unicode data buffer. * @param unicode data buffer. * @param buffer of character protocol to pack from. * @param size of unicode data buffer in codepoints. * @return number of code points converted. */ static size_t pack(unicode_t unicode, CharacterProtocol& buffer, size_t size); /** * Dup a utf8 string into a ucs4_t string. */ static ucs4_t *udup(const char *string); /** * Dup a utf8 string into a ucs2_t representation. */ static ucs2_t *wdup(const char *string); /** * Find first occurance of character in string. * @param string to search in. * @param character code to search for. * @param start offset in string in codepoints. * @return pointer to first instance or NULL if not found. */ static const char *find(const char *string, ucs4_t character, size_t start = 0); /** * Find last occurrence of character in string. * @param string to search in. * @param character code to search for. * @param end offset to start from in codepoints. * @return pointer to last instance or NULL if not found. */ static const char *rfind(const char *string, ucs4_t character, size_t end = (size_t)-1l); /** * Count occurrences of a unicode character in string. * @param string to search in. * @param character code to search for. * @return count of occurrences. */ static unsigned ccount(const char *string, ucs4_t character); /** * Get a unicode character from a character protocol. * @param buffer of character protocol to read from. * @return unicode character or EOF error. */ static ucs4_t get(CharacterProtocol& buffer); /** * Push a unicode character to a character protocol. * @param character to push to file. * @param buffer of character protocol to push character to. * @return unicode character or EOF on error. */ static ucs4_t put(ucs4_t character, CharacterProtocol& buffer); }; /** * A copy-on-write utf8 string class that operates by reference count. This * is derived from the classic uCommon String class by adding operations that * are utf8 encoding aware. * @author David Sugar */ class __EXPORT UString : public String, public utf8 { protected: /** * Create a new empty utf8 aware string object. */ UString(); /** * Create an empty string with a buffer pre-allocated to a specified size. * @param size of buffer to allocate. */ UString(strsize_t size); /** * Create a utf8 aware string for a null terminated unicode string. * @param text of ucs4 encoded data. */ UString(const unicode_t text); /** * Create a string from null terminated text up to a maximum specified * size. * @param text to use for string. * @param size limit of new string. */ UString(const char *text, strsize_t size); /** * Create a string for a substring. The end of the substring is a * pointer within the substring itself. * @param text to use for string. * @param end of text in substring. */ UString(const unicode_t *text, const unicode_t *end); /** * Construct a copy of a string object. Our copy inherits the same * reference counted instance of cstring as in the original. * @param existing string to copy from. */ UString(const UString& existing); /** * Destroy string. De-reference cstring. If last reference to cstring, * then also remove cstring from heap. */ virtual ~UString(); /** * Get a new string object as a substring of the current object. * @param codepoint offset of substring. * @param size of substring in codepoints or 0 if to end. * @return string object holding substring. */ UString get(strsize_t codepoint, strsize_t size = 0) const; /** * Extract a unicode byte sequence from utf8 object. * @param unicode data buffer. * @param size of data buffer. * @return codepoints copied. */ size_t get(unicode_t unicode, size_t size) const; /** * Set a utf8 encoded string based on unicode data. * @param unicode text to set. */ void set(const unicode_t unicode); /** * Add (append) unicode to a utf8 encoded string. * @param unicode text to add. */ void add(const unicode_t unicode); /** * Return unicode character found at a specific codepoint in the string. * @param position of codepoint in string, negative values computed from end. * @return character code at specified position in string. */ ucs4_t at(int position) const; /** * Extract a unicode byte sequence from utf8 object. * @param unicode data buffer. * @param size of data buffer. * @return codepoints copied. */ inline size_t operator()(unicode_t unicode, size_t size) const {return get(unicode, size);} /** * Get a new substring through object expression. * @param codepoint offset of substring. * @param size of substring or 0 if to end. * @return string object holding substring. */ UString operator()(int codepoint, strsize_t size) const; /** * Convenience method for left of string. * @param size of substring to gather in codepoints. * @return string object holding substring. */ inline UString left(strsize_t size) const {return operator()(0, size);} /** * Convenience method for right of string. * @param offset of substring from right in codepoints. * @return string object holding substring. */ inline UString right(strsize_t offset) const {return operator()(-((int)offset), 0);} /** * Convenience method for substring extraction. * @param offset into string. * @param size of string to return. * @return string object holding substring. */ inline UString copy(strsize_t offset, strsize_t size) const {return operator()((int)offset, size);} /** * Cut (remove) text from string using codepoint offsets. * @param offset to start of text field to remove. * @param size of text field to remove or 0 to remove to end of string. */ void cut(strsize_t offset, strsize_t size = 0); /** * Insert (paste) text into string using codepoint offsets. * @param offset to start paste. * @param text to paste. * @param size of text to paste. */ void paste(strsize_t offset, const char *text, strsize_t size = 0); /** * Reference a string in the object by codepoint offset. Positive * offsets are from the start of the string, negative from the * end. * @param offset to string position. * @return pointer to string data or NULL if invalid offset. */ const char *operator()(int offset) const; /** * Reference a unicode character in string object by array offset. * @param position of codepoint offset to character. * @return character value at offset. */ inline ucs4_t operator[](int position) const {return UString::at(position);} /** * Count codepoints in current string. * @return count of codepoints. */ inline strsize_t count(void) const {return (strsize_t)utf8::count(str->text);} /** * Count occurrences of a unicode character in string. * @param character code to search for. * @return count of occurrences. */ unsigned ccount(ucs4_t character) const; /** * Find first occurrence of character in string. * @param character code to search for. * @param start offset in string in codepoints. * @return pointer to first instance or NULL if not found. */ const char *find(ucs4_t character, strsize_t start = 0) const; /** * Find last occurrence of character in string. * @param character code to search for. * @param end offset to start from in codepoints. * @return pointer to last instance or NULL if not found. */ const char *rfind(ucs4_t character, strsize_t end = npos) const; }; /** * Pointer to utf8 encoded character data. This is a kind of "char *" for * utf8 text. * @author David Sugar */ class __EXPORT utf8_pointer { protected: uint8_t *text; public: /** * Create a utf8 pointer set to NULL. */ utf8_pointer(); /** * Create a utf8 pointer for an existing char pointer. * @param string pointer to use. */ utf8_pointer(const char *string); /** * Create a utf8 pointer as a copy of existing utf8 pointer. * @param copy of object to use. */ utf8_pointer(const utf8_pointer& copy); /** * Iterative increment of a utf8 pointer to prior codepoint. * @return object incremented. */ utf8_pointer& operator ++(); /** * Iterative decrement of a utf8 pointer to next codepoint. * @return object decremented. */ utf8_pointer& operator --(); /** * Adjust utf8 pointer by specified codepoints forward. * @param offset to increment by. * @return object incremented. */ utf8_pointer& operator +=(long offset); /** * Adjust utf8 pointer by specified codepoints backward. * @param offset to decrement by. * @return object decremented. */ utf8_pointer& operator -=(long offset); /** * Get new utf8 string after adding a codepoint offset. * @param offset to add. * @return new utf8 pointer pointing to specified offset. */ utf8_pointer operator+(long offset) const; /** * Get new utf8 string after subtracting a codepoint offset. * @param offset to subtract. * @return new utf8 pointer pointing to specified offset. */ utf8_pointer operator-(long offset) const; /** * Check if text is valid pointer. * @return true if not NULL. */ inline operator bool() const {return text != NULL;} /** * Check if text is an invalid pointer. * @return false if not NULL. */ inline bool operator!() const {return text == NULL;} /** * Extract a unicode character from a specified codepoint. * @param codepoint offset to extract character from. * @return unicode character or 0. */ ucs4_t operator[](long codepoint) const; /** * Assign a utf8 string to point to. * @param string to point to. * @return current object after set to string. */ utf8_pointer& operator=(const char *string); /** * Iterative increment of a utf8 pointer to next codepoint. */ void inc(void); /** * Iterative decrement of a utf8 pointer to prior codepoint. */ void dec(void); /** * check if pointer equals another string. * @param string to check. * @return true if same memory address. */ inline bool operator==(const char *string) const {return (const char *)text == string;} /** * check if pointer does not equal another string. * @param string to check. * @return false if same memory address. */ inline bool operator!=(const char *string) const {return (const char *)text != string;} /** * Get unicode character pointed to by pointer. * @return unicode character we are pointing to. */ inline ucs4_t operator*() const {return utf8::codepoint((const char *)text);} /** * Get c string we point to. * @return string we point to. */ inline char *c_str(void) const {return (char *)text;} /** * Convert utf8 pointer to a generic string pointer. * @return generic string pointer. */ inline operator char*() const {return (char *)text;} /** * Get length of null terminated utf8 string in codepoints. * @return codepoint length of string. */ inline size_t len(void) const {return utf8::count((const char *)text);} }; inline ucs4_t *strudup(const char *string) {return utf8::udup(string);} inline ucs2_t *strwdup(const char *string) {return utf8::wdup(string);} __EXPORT unicode_t unidup(const char *string); template<> inline void dupfree(ucs2_t *string) {::free(string);} template<> inline void dupfree(ucs4_t *string) {::free(string);} template<> inline void dupfree(unicode_t string) {::free(string);} /** * Convenience type for utf8 encoded strings. */ typedef UString ustring_t; /** * Convenience type for utf8_pointer strings. */ typedef utf8_pointer utf8_t; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/counter.h0000664000175000017500000001301412537554527014221 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Support for various automatic counting objects. * This header defines templates for various kinds of automatic counting * and sequencing objects. Templates are used to allow manipulation of * various numerical-like types. * @file ucommon/counter.h */ #ifndef _UCOMMON_COUNTER_H_ #define _UCOMMON_COUNTER_H_ #ifndef _UCOMMON_CONFIG_H_ #include #endif namespace ucommon { /** * Automatic integer counting class. This is an automatic counting object * that is used to retrieve a new integer value between 0 and n each time * the object is referenced. When reaching the last n value, the object * restarts at 0, and so is used to retrieve a sequence of values in order. * @author David Sugar */ class __EXPORT counter { private: unsigned value, cycle; public: /** * Initialize integer counter of unknown size. */ counter(); /** * Initialize integer counter for a range of values. * @param limit before recycling to zero. */ counter(unsigned limit); /** * Get the next counter value. * @return next counter value. */ unsigned get(void); /** * Get the range of values before recycling. * @return counter limit. */ inline unsigned range(void) { return cycle; } /** * Reference next counter value through pointer operation. * @return next counter value. */ inline unsigned operator*() { return get(); } /** * Reference next counter value by casting to integer. * @return next counter value. */ inline operator unsigned() { return get(); } /** * Assign the value of the counter. * @param value to assign. */ void operator=(unsigned value); }; /** * Automatically return a sequence of untyped objects. This is an automatic * counter based class which returns the next pointer in an array of pointers * and restarts the list when reaching the end. This is used to support the * sequence template. * @author David Sugar */ class __EXPORT SeqCounter : protected counter { private: void *item; size_t offset; protected: SeqCounter(void *start, size_t size, unsigned count); void *get(void); void *get(unsigned idx); public: /** * Used to directly assign sequence position in template. * @param inc_offset in sequence to reset sequencing to. */ inline void operator=(unsigned inc_offset) { counter::operator=(inc_offset); } }; /** * Automatically toggle a bool on each reference. * @author David Sugar */ class __EXPORT toggle { private: bool value; public: inline toggle() { value = false; } bool get(void); inline bool operator*() { return get(); } inline void operator=(bool v) { value = v; } inline operator bool() { return get(); } }; /** * A template to return a sequence of objects of a specified type. * This is used to return a different member in a sequence of objects of * a specified type during each reference to the sequencer. * @author David Sugar */ template class sequence : public SeqCounter { protected: inline T *get(unsigned idx) { return static_cast(SeqCounter::get(idx)); } public: /** * Create a template auto-sequence from a list of typed pointers. * @param array of typed values to sequence on reference. * @param size of list of typed values. */ inline sequence(T *array, unsigned size) : SeqCounter(array, sizeof(T), size) {} /** * Return next typed member of the sequence. * @return next typed member of sequence. */ inline T* get(void) { return static_cast(SeqCounter::get()); } /** * Return next typed member of the sequence by pointer reference. * @return next typed member of sequence. */ inline T& operator*() { return reference_cast(SeqCounter::get()); } /** * Return next typed member of the sequence by casted reference. * @return next typed member of sequence. */ inline operator T&() { return reference_cast(SeqCounter::get()); } /** * Return a specific typed member from the sequence list. * @param offset of member to return. * @return typed value at the specified offset. */ inline T& operator[](unsigned offset) { return reference_cast(get(offset)); } }; /** * A convenience typecast for integer counters. */ typedef counter counter_t; /** * A convenience typecast for auto-toggled bools. */ typedef toggle toggle_t; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/platform.h0000664000175000017500000003043512555666525014376 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Various miscellaneous platform specific headers and defines. * This is used to support ucommon on different platforms. The ucommon * library assumes at least a real posix threading library is present or * will build thread support native on Microsoft Windows legacy platform. * This header also deals with issues related to common base types. * @file ucommon/platform.h */ #include #if defined(sun) && defined(unix) #include #endif #ifndef _UCOMMON_PLATFORM_H_ #define _UCOMMON_PLATFORM_H_ #define UCOMMON_ABI 6 #ifndef UCOMMON_SYSRUNTIME #ifndef NEW_STDCPP #define NEW_STDCPP #endif #define _UCOMMON_EXTENDED_ #endif /** * Common namespace for all ucommon objects. * We are using a common namespace to easily separate ucommon from other * libraries. This namespace usage is set to the package name and controlled * by macros so future changes will be hidden from user applications so long * as the namespace macros (UCOMMON_NAMESPACE, NAMESPACE_UCOMMON, * END_NAMESPACE) are used in place of direct namespace declarations. * @namespace ucommon */ #define UCOMMON_NAMESPACE ucommon #define NAMESPACE_UCOMMON namespace ucommon { #define END_NAMESPACE } #ifndef _REENTRANT #define _REENTRANT 1 #endif #ifndef __PTH__ #ifndef _THREADSAFE #define _THREADSAFE 1 #endif #ifndef _POSIX_PTHREAD_SEMANTICS #define _POSIX_PTHREAD_SEMANTICS #endif #endif #if !defined(__GNUC__) && !defined(__has_feature) && !defined(_MSC_VER) #define UCOMMON_RTTI 1 #endif #if __GNUC__ > 3 && defined(__GXX_RTTI) #define UCOMMON_RTTI 1 #endif #if defined(_MSC_VER) && defined(_CPPRTTI) #define UCOMMON_RTTI 1 #endif #if defined(__has_feature) #if __has_feature(cxx_rtti) #define UCOMMON_RTTI 1 #endif #endif #if defined(__GNUC__) && (__GNUC < 3) && !defined(_GNU_SOURCE) #define _GNU_SOURCE #endif #if __GNUC__ > 3 || (__GNUC__ == 3 && (__GNU_MINOR__ > 3)) #define __PRINTF(x,y) __attribute__ ((format (printf, x, y))) #define __SCANF(x, y) __attribute__ ((format (scanf, x, y))) #define __MALLOC __attribute__ ((malloc)) #endif #ifndef __MALLOC #define __PRINTF(x, y) #define __SCANF(x, y) #define __MALLOC #endif #ifndef DEBUG #ifndef NDEBUG #define NDEBUG #endif #endif #ifdef DEBUG #ifdef NDEBUG #undef NDEBUG #endif #endif // see if targeting legacy Microsoft windows platform #if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) #define _MSWINDOWS_ #if defined(_MSC_VER) #define NOMINMAX #endif #if defined(_M_X64) || defined(_M_ARM) #define _MSCONDITIONALS_ #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0600 #endif #endif //#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0501 //#undef _WIN32_WINNT //#define _WIN32_WINNT 0x0501 //#endif //#ifndef _WIN32_WINNT //#define _WIN32_WINNT 0x0501 //#endif #ifdef _MSC_VER #pragma warning(disable: 4251) #pragma warning(disable: 4996) #pragma warning(disable: 4355) #pragma warning(disable: 4290) #pragma warning(disable: 4291) #endif #if defined(__BORLANDC__) && !defined(__MT__) #error Please enable multithreading #endif #if defined(_MSC_VER) && !defined(_MT) #error Please enable multithreading (Project -> Settings -> C/C++ -> Code Generation -> Use Runtime Library) #endif // Require for compiling with critical sections. #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0501 #endif // Make sure we're consistent with _WIN32_WINNT #ifndef WINVER #define WINVER _WIN32_WINNT #endif #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #if defined(_MSC_VER) typedef int socksize_t; typedef int socklen_t; typedef signed long ssize_t; typedef int pid_t; #else typedef size_t sockword_t; typedef size_t socksize_t; #endif #include #ifndef __EXPORT #ifdef UCOMMON_STATIC #define __EXPORT #else #define __EXPORT __declspec(dllimport) #endif #endif #define __LOCAL // if runtime mode then non-runtime libraries are static on windows... #if defined(UCOMMON_RUNTIME) || defined(UCOMMON_STATIC) #define __SHARED #else #define __SHARED __EXPORT #endif #else typedef size_t socksize_t; #define __EXPORT __attribute__ ((visibility("default"))) #define __LOCAL __attribute__ ((visibility("hidden"))) #define __SHARED __attribute__ ((visibility("default"))) #endif #ifdef _MSWINDOWS_ #define _UWIN #include #include // gcc c++11 support on mingw requires pthread support library #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7)) && !defined(UCOMMON_SYSRUNTIME) && defined(__MINGW_WINPTHREAD__) #include // gnu libstdc++ now requires a win pthread #undef _MSCONDITIONALS_ typedef size_t stacksize_t; #else #define _MSTHREADS_ typedef DWORD pthread_t; typedef unsigned stacksize_t; typedef CRITICAL_SECTION pthread_mutex_t; #endif typedef char *caddr_t; typedef HANDLE fd_t; typedef SOCKET socket_t; #ifdef _MSC_VER typedef struct timespec { time_t tv_sec; long tv_nsec; } timespec_t; #endif inline void sleep(int seconds) {::Sleep((seconds * 1000l));} extern "C" { #define SERVICE_MAIN(id, argc, argv) void WINAPI service_##id(DWORD argc, LPSTR *argv) typedef LPSERVICE_MAIN_FUNCTION cpr_service_t; #ifdef _MSTHREADS_ inline void pthread_exit(void *p) {_endthreadex((DWORD)0);} inline pthread_t pthread_self(void) {return (pthread_t)GetCurrentThreadId();} inline int pthread_mutex_init(pthread_mutex_t *mutex, void *x) {InitializeCriticalSection(mutex); return 0;} inline void pthread_mutex_destroy(pthread_mutex_t *mutex) {DeleteCriticalSection(mutex);} inline void pthread_mutex_lock(pthread_mutex_t *mutex) {EnterCriticalSection(mutex);} inline void pthread_mutex_unlock(pthread_mutex_t *mutex) {LeaveCriticalSection(mutex);} #endif inline char *strdup(const char *s) {return _strdup(s);} inline int stricmp(const char *s1, const char *s2) {return _stricmp(s1, s2);} inline int strnicmp(const char *s1, const char *s2, size_t l) {return _strnicmp(s1, s2, l);} } #elif defined(__PTH__) #include #include typedef size_t stacksize_t; typedef int socket_t; typedef int fd_t; #define INVALID_SOCKET -1 #define INVALID_HANDLE_VALUE -1 #include #define pthread_mutex_t pth_mutex_t #define pthread_cond_t pth_cond_t #define pthread_t pth_t inline int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {return pth_sigmask(how, set, oset);}; inline void pthread_exit(void *p) {pth_exit(p);}; inline void pthread_kill(pthread_t tid, int sig) {pth_raise(tid, sig);}; inline int pthread_mutex_init(pthread_mutex_t *mutex, void *x) {return pth_mutex_init(mutex) != 0;}; inline void pthread_mutex_destroy(pthread_mutex_t *mutex) {}; inline void pthread_mutex_lock(pthread_mutex_t *mutex) {pth_mutex_acquire(mutex, 0, NULL);}; inline void pthread_mutex_unlock(pthread_mutex_t *mutex) {pth_mutex_release(mutex);}; inline void pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {pth_cond_await(cond, mutex, NULL);}; inline void pthread_cond_signal(pthread_cond_t *cond) {pth_cond_notify(cond, FALSE);}; inline void pthread_cond_broadcast(pthread_cond_t *cond) {pth_cond_notify(cond, TRUE);}; #else #include typedef size_t stacksize_t; typedef int socket_t; typedef int fd_t; #define INVALID_SOCKET -1 #define INVALID_HANDLE_VALUE -1 #include #endif #ifdef _MSC_VER typedef signed __int8 int8_t; typedef unsigned __int8 uint8_t; typedef signed __int16 int16_t; typedef unsigned __int16 uint16_t; typedef signed __int32 int32_t; typedef unsigned __int32 uint32_t; typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; typedef char *caddr_t; #include #define snprintf(p, s, f, ...) _snprintf_s(p, s, _TRUNCATE, f, __VA_ARGS__) #define vsnprintf(p, s, f, a) _vsnprintf_s(p, s, _TRUNCATE, f, a) #else #include #include #include #include #include #endif #undef getchar #undef putchar #ifndef _GNU_SOURCE typedef void (*sighandler_t)(int); /**< Convenient typedef for signal handlers. */ #endif typedef unsigned long timeout_t; #include #include #include #ifndef UCOMMON_RUNTIME #include #endif #ifdef _MSWINDOWS_ #ifndef ENETDOWN #define ENETDOWN ((int)(WSAENETDOWN)) #endif #ifndef EINPROGRESS #define EINPROGRESS ((int)(WSAEINPROGRESS)) #endif #ifndef ENOPROTOOPT #define ENOPROTOOPT ((int)(WSAENOPROTOOPT)) #endif #ifndef EADDRINUSE #define EADDRINUSE ((int)(WSAEADDRINUSE)) #endif #ifndef EADDRNOTAVAIL #define EADDRNOTAVAIL ((int)(WSAEADDRNOTAVAIL)) #endif #ifndef ENETUNREACH #define ENETUNREACH ((int)(WSAENETUNREACH)) #endif #ifndef EHOSTUNREACH #define EHOSTUNREACH ((int)(WSAEHOSTUNREACH)) #endif #ifndef EHOSTDOWN #define EHOSTDOWN ((int)(WSAEHOSTDOWN)) #endif #ifndef ENETRESET #define ENETRESET ((int)(WSAENETRESET)) #endif #ifndef ECONNABORTED #define ECONNABORTED ((int)(WSAECONNABORTED)) #endif #ifndef ECONNRESET #define ECONNRESET ((int)(WSAECONNRESET)) #endif #ifndef EISCONN #define EISCONN ((int)(WSAEISCONN)) #endif #ifndef ENOTCONN #define ENOTCONN ((int)(WSAENOTCONN)) #endif #ifndef ESHUTDOWN #define ESHUTDOWN ((int)(WSAESHUTDOWN)) #endif #ifndef ETIMEDOUT #define ETIMEDOUT ((int)(WSAETIMEDOUT)) #endif #ifndef ECONNREFUSED #define ECONNREFUSED ((int)(WSAECONNREFUSED)) #endif #endif #ifndef DEBUG #ifndef NDEBUG #define NDEBUG #endif #endif #ifdef DEBUG #ifdef NDEBUG #undef NDEBUG #endif #endif #ifndef PROGRAM_MAIN #define PROGRAM_MAIN(argc, argv) extern "C" int main(int argc, char **argv) #define PROGRAM_EXIT(code) return code #endif #ifndef SERVICE_MAIN #define SERVICE_MAIN(id, argc, argv) void service_##id(int argc, char **argv) typedef void (*cpr_service_t)(int argc, char **argv); #endif #include #ifdef DEBUG #define crit(x, text) assert(x) #else #define crit(x, text) if(!(x)) cpr_runtime_error(text) #endif /** * Template function to initialize memory by invoking default constructor. * If NULL is passed, then NULL is returned without any constructor called. * @param memory to initialize. * @return memory initialized. */ template inline T *init(T *memory) {return ((memory) ? new(((void *)memory)) T : NULL);} typedef long Integer; typedef unsigned long Unsigned; typedef double Real; typedef uint8_t ubyte_t; /** * Matching function for strdup(). * @param string to release from allocated memory. */ inline void strfree(char *str) {::free(str);} template inline T polypointer_cast(S *s) { #if defined(DEBUG) && defined(UCOMMON_RTTI) assert(dynamic_cast(s) != NULL); // rtti for debug only... #endif return static_cast(s); } template inline T polyconst_cast(S *s) { return const_cast(polypointer_cast(s)); } template inline T polystatic_cast(S *s) { return static_cast(s); } template inline T polydynamic_cast(S *s) { #if defined(UCOMMON_RTTI) return dynamic_cast(s); #else return static_cast(s); #endif } template inline T& polyreference_cast(S *s) { #if defined(DEBUG) && defined(UCOMMON_RTTI) assert(dynamic_cast(s) != NULL); // rtti for debug only... #endif return *(static_cast(s)); } template inline T& reference_cast(T *pointer) { #ifdef DEBUG assert(pointer != NULL); #endif return *pointer; } template inline const T immutable_cast(T p) { return static_cast(p); } #endif ucommon-6.4.4/inc/ucommon/containers.h0000664000175000017500000005536012537554527014721 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Threadsafe object containers. This is used to better define * object containers and manipulating classes which can be presumed to be * fully threadsafe and thread-aware. This has to be defined separately * to assure correct order of preceeding headers as well as to better * organize the library for clarity. Most of these classes and templates * work with classes derived from Object and LinkedObject and make use of * conditional for time constrained acquisition of managed objects. * @file ucommon/containers.h */ #ifndef _UCOMMON_CONTAINERS_H_ #define _UCOMMON_CONTAINERS_H_ #ifndef _UCOMMON_CONFIG_H_ #include #endif #ifndef _UCOMMON_PROTOCOLS_H_ #include #endif #ifndef _UCOMMON_LINKED_H_ #include #endif #ifndef _UCOMMON_MEMORY_H_ #include #endif #ifndef _UCOMMON_THREAD_H_ #include #endif namespace ucommon { /** * Linked allocator helper for linked_allocator template. This is used * to alloc an array of typed objects tied to a free list in a single * operation. * @author David Sugar */ class __EXPORT LinkedAllocator : private Conditional { protected: LinkedObject *freelist; LinkedAllocator(); LinkedObject *get(void); LinkedObject *get(timeout_t timeout); void release(LinkedObject *node); public: /** * Test if there is still objects in the free list. * @return true if there are objects. */ operator bool() const; /** * Test if the free list is empty. * @return true if the free list is empty. */ bool operator!() const; }; /** * A thread-safe buffer for serializing and streaming class data. While * the queue and stack operate by managing lists of reference pointers to * objects of various mixed kind, the buffer holds physical copies of objects * that being passed through it, and all must be the same size. For this * reason the buffer is normally used through the bufferof template * rather than stand-alone. The buffer is accessed in fifo order. * @author David Sugar */ class __EXPORT Buffer : protected Conditional { private: size_t bufsize, objsize; caddr_t buf, head, tail; unsigned objcount, limit; protected: /** * Create a buffer to hold a series of objects. * @param size of each object in buffer. * @param count of objects in the buffer. */ Buffer(size_t typesize, size_t count); /** * Deallocate buffer and unblock any waiting threads. */ virtual ~Buffer(); /** * Get the next object from the buffer. * @param timeout to wait when buffer is empty in milliseconds. * @return pointer to next object in the buffer or NULL if timed out. */ void *get(timeout_t timeout); /** * Get the next object from the buffer. This blocks until an object * becomes available. * @return pointer to next object from buffer. */ void *get(void); /** * Put (copy) an object into the buffer. This blocks while the buffer * is full. * @param data to copy into the buffer. */ void put(void *data); /** * Put (copy) an object into the buffer. * @param data to copy into the buffer. * @param timeout to wait if buffer is full. * @return true if copied, false if timed out while full. */ bool put(void *data, timeout_t timeout); /** * Release must be called when we get an object from the buffer. This * is because the pointer we return is a physical pointer to memory * that is part of the buffer. The object we get cannot be removed or * the memory modified while the object is being used. */ void release(void); /** * Copy the next object from the buffer. This blocks until an object * becomes available. Buffer is auto-released. * @param data pointer to copy into. */ void copy(void *data); /** * Copy the next object from the buffer. Buffer is auto-released. * @param data pointer to copy into. * @param timeout to wait when buffer is empty in milliseconds. * @return true if object copied, or false if timed out. */ bool copy(void *data, timeout_t timeout); /** * Peek at pending data in buffer. This returns a pointer to * objects relative to the head. In effect it is the same as * get() for item = 0. * @param item to examine in buffer. * @return pointer to item or NULL if invalid item number. */ void *peek(unsigned item); virtual void *invalid(void) const; public: /** * Get the size of the buffer. * @return size of the buffer. */ unsigned size(void) const; /** * Get the number of objects in the buffer currently. * @return number of objects buffered. */ unsigned count(void) const; /** * Test if there is data waiting in the buffer. * @return true if buffer has data. */ operator bool() const; /** * Test if the buffer is empty. * @return true if the buffer is empty. */ bool operator!() const; }; /** * Manage a thread-safe queue of objects through reference pointers. This * can be particularly interesting when used to enqueue/dequeue reference * counted managed objects. Thread-safe access is managed through a * conditional. Both lifo and fifo forms of queue access may be used. A * pool of self-managed member objects are used to operate the queue. This * queue is optimized for fifo access; while lifo is supported, it will be * slow. If you need primarily lifo, you should use stack instead. * @author David Sugar */ class __EXPORT Queue : protected OrderedIndex, protected Conditional { private: mempager *pager; LinkedObject *freelist; size_t used; class __LOCAL member : public OrderedObject { public: member(Queue *q, ObjectProtocol *obj); ObjectProtocol *object; }; friend class member; protected: size_t limit; virtual ObjectProtocol *invalid(void) const; public: /** * Create a queue that uses a memory pager for internally managed * member objects for a specified maximum number of object pointers. * @param pager to use for internal member object or NULL to use heap. * @param number of pointers that can be in the queue or 0 for unlimited. * size limit. */ Queue(mempager *pager = NULL, size_t number = 0); /** * Destroy queue. If no mempager is used, then frees heap. */ ~Queue(); /** * Remove a specific object pointer for the queue. This can remove * a member from any location in the queue, whether beginning, end, or * somewhere in the middle. This also releases the object. * @param object to remove. * @return true if object was removed, false if not found. */ bool remove(ObjectProtocol *object); /** * Post an object into the queue by it's pointer. This can wait for * a specified timeout if the queue is full, for example, for another * thread to remove an object pointer. This also retains the object. * @param object to post. * @param timeout to wait if queue is full in milliseconds. * @return true if object posted, false if queue full and timeout expired. */ bool post(ObjectProtocol *object, timeout_t timeout = 0); /** * Examine pending existing object in queue. Does not remove it. * @param number of elements back. * @return object in queue or NULL if invalid value. */ ObjectProtocol *get(unsigned offset = 0); /** * Get and remove last object posted to the queue. This can wait for * a specified timeout of the queue is empty. The object is still * retained and must be released or deleted by the receiving function. * @param timeout to wait if empty in milliseconds. * @return object from queue or NULL if empty and timed out. */ ObjectProtocol *fifo(timeout_t timeout = 0); /** * Get and remove first object posted to the queue. This can wait for * a specified timeout of the queue is empty. The object is still * retained and must be released or deleted by the receiving function. * @param timeout to wait if empty in milliseconds. * @return object from queue or NULL if empty and timed out. */ ObjectProtocol *lifo(timeout_t timeout = 0); /** * Get number of object points currently in the queue. * @return number of objects in queue. */ size_t count(void) const; }; /** * Manage a thread-safe stack of objects through reference pointers. This * Thread-safe access is managed through a conditional. This differs from * the queue in lifo mode because delinking the last object is immediate, * and because it has much less overhead. A pool of self-managed * member objects are used to operate the stack. * @author David Sugar */ class __EXPORT Stack : protected Conditional { private: LinkedObject *freelist, *usedlist; mempager *pager; size_t used; class __LOCAL member : public LinkedObject { public: member(Stack *s, ObjectProtocol *obj); ObjectProtocol *object; }; friend class member; protected: size_t limit; virtual ObjectProtocol *invalid(void) const; public: /** * Create a stack that uses a memory pager for internally managed * member objects for a specified maximum number of object pointers. * @param pager to use for internal member object or NULL to use heap. * @param number of pointers that can be in the stack or 0 if unlimited. */ Stack(mempager *pager = NULL, size_t number = 0); /** * Destroy queue. If no pager is used, then frees heap. */ virtual ~Stack(); /** * Remove a specific object pointer for the queue. This can remove * a member from any location in the queue, whether beginning, end, or * somewhere in the middle. This also releases the object. * @param object to remove. * @return true if object was removed, false if not found. */ bool remove(ObjectProtocol *object); /** * Push an object into the stack by it's pointer. This can wait for * a specified timeout if the stack is full, for example, for another * thread to remove an object pointer. This also retains the object. * @param object to push. * @param timeout to wait if stack is full in milliseconds. * @return true if object pushed, false if stack full and timeout expired. */ bool push(ObjectProtocol *object, timeout_t timeout = 0); /** * Get and remove last object pushed on the stack. This can wait for * a specified timeout of the stack is empty. The object is still * retained and must be released or deleted by the receiving function. * @param timeout to wait if empty in milliseconds. * @return object pulled from stack or NULL if empty and timed out. */ ObjectProtocol *pull(timeout_t timeout = 0); /** * Examine an existing object on the stack. * @param offset to stack entry. * @return object examined. */ ObjectProtocol *get(unsigned offset = 0); /** * Get number of object points currently in the stack. * @return number of objects in stack. */ size_t count(void) const; const ObjectProtocol *peek(timeout_t timeout = 0); }; /** * Linked allocator template to gather linked objects. This allocates the * object pool in a single array as a single heap allocation, and releases * the whole pool with a single delete when done. It is also threadsafe. * The types used must be derived of LinkedObject. * @author David Sugar */ template class linked_allocator : public LinkedAllocator { private: T* array; public: inline linked_allocator(size_t size) : LinkedAllocator() { array = new T[size]; for(unsigned i = 0; i < size; ++i) array[i].enlist(&freelist); } ~linked_allocator() { delete[] array; } inline T *get(void) { return polypointer_cast(LinkedAllocator::get()); } inline T *get(timeout_t timeout) { return polypointer_cast(LinkedAllocator::get(timeout)); } inline void release(T *node) { LinkedAllocator::release(node); } }; /** * A templated typed class for buffering of objects. This operates as a * fifo buffer of typed objects which are physically copied into the buffer. * The objects that are buffered are accessed from allocated buffer space. * As designed this may be used with multiple producer threads and one * consumer thread. To use multiple consumers, one can copy the typed object * from the buffer through the get pointer and then call release. The * copied object can then be used safely. This is what the copy method is * used for. * @author David Sugar */ template class bufferof : public Buffer { public: /** * Create a buffer to hold a series of typed objects. * @param count of typed objects in the buffer. */ inline bufferof(unsigned capacity) : Buffer(sizeof(T), capacity) {} /** * Get the next typed object from the buffer. This blocks until an object * becomes available. * @return pointer to next typed object from buffer. */ inline T *get(void) { return static_cast(get()); } /** * Get the next typed object from the buffer. * @param timeout to wait when buffer is empty in milliseconds. * @return pointer to next typed object in the buffer or NULL if timed out. */ inline T *get(timeout_t timeout) { return static_cast(get(timeout)); } /** * Put (copy) a typed object into the buffer. This blocks while the buffer * is full. * @param object to copy into the buffer. */ inline void put(T *object) { put(object); } /** * Put (copy) an object into the buffer. * @param object to copy into the buffer. * @param timeout to wait if buffer is full. * @return true if copied, false if timed out while full. */ inline bool put(T *object, timeout_t timeout) { return put(object, timeout); } /** * Copy the next typed object from the buffer. This blocks until an object * becomes available. * @param object pointer to copy typed object into. */ inline void copy(T *object) { copy(object); } /** * Copy the next typed object from the buffer. * @param object pointer to copy typed object into. * @param timeout to wait when buffer is empty in milliseconds. * @return true if object copied, or false if timed out. */ inline bool get(T *object, timeout_t timeout) { return copy(object, timeout); } /** * Examine past item in the buffer. This is a typecast of the peek * operation. * @param item in buffer. * @return item pointer if valid or NULL. */ inline const T& at(unsigned item) { return static_cast(Buffer::peek(item)); } /** * Examine past item in the buffer. This is a typecast of the peek * operation. * @param item in buffer. * @return item pointer if valid or NULL. */ inline T&operator[](unsigned item) { return static_cast(Buffer::peek(item)); } inline T* operator()(unsigned offset = 0) { return static_cast(Buffer::peek(offset)); } }; /** * A templated typed class for thread-safe stack of object pointers. This * allows one to use the stack class in a typesafe manner for a specific * object type derived from Object rather than generically for any derived * object class. * @author David Sugar */ template class stackof : public Stack { public: /** * Create templated stack of typed objects. * @param memory pool for internal use of stack. * @param size of stack to construct. Uses 0 if no size limit. */ inline stackof(mempager *memory, size_t size = 0) : Stack(memory, size) {} /** * Remove a specific typed object pointer for the stack. This can remove * a member from any location in the stack, whether beginning, end, or * somewhere in the middle. This releases the object. * @param object to remove. * @return true if object was removed, false if not found. */ inline bool remove(T *object) { return Stack::remove(polypointer_cast(object)); } /** * Push a typed object into the stack by it's pointer. This can wait for * a specified timeout if the queue is full, for example, for another * thread to remove an object pointer. This retains the object. * @param object to push. * @param timeout to wait if queue is full in milliseconds. * @return true if object pushed, false if queue full and timeout expired. */ inline bool push(T *object, timeout_t timeout = 0) { return Stack::push(polypointer_cast(object), timeout); } /** * Get and remove last typed object posted to the stack. This can wait for * a specified timeout of the stack is empty. The object is still retained * and must be released or deleted by the receiving function. * @param timeout to wait if empty in milliseconds. * @return object from queue or NULL if empty and timed out. */ inline T *pull(timeout_t timeout = 0) { return polypointer_cast(Stack::pull(timeout)); } /** * Examine last typed object posted to the stack. This can wait for * a specified timeout of the stack is empty. * @param timeout to wait if empty in milliseconds. * @return object in queue or NULL if empty and timed out. */ inline const T *peek(timeout_t timeout = 0) { return polypointer_cast(Stack::peek(timeout)); } inline T* operator()(unsigned offset = 0) { return polypointer_cast(Stack::get(offset)); } /** * Examine past item in the stack. This is a typecast of the peek * operation. * @param offset in stack. * @return item pointer if valid or NULL. */ inline const T& at(unsigned offset = 0) { return polyreference_cast(Stack::get(offset)); } /** * Examine past item in the stack. This is a typecast of the peek * operation. * @param offset in stack. * @return item pointer if valid or NULL. */ inline const T& operator[](unsigned offset) { return polyreference_cast(Stack::get(offset)); } }; /** * A templated typed class for thread-safe queue of object pointers. This * allows one to use the queue class in a typesafe manner for a specific * object type derived from Object rather than generically for any derived * object class. * @author David Sugar */ template class queueof : public Queue { public: /** * Create templated queue of typed objects. * @param memory pool for internal use by queue. * @param size of queue to construct. Uses 0 if no size limit. */ inline queueof(mempager *memory, size_t size = 0) : Queue(memory, size) {} /** * Remove a specific typed object pointer for the queue. This can remove * a member from any location in the queue, whether beginning, end, or * somewhere in the middle. This releases the object. * @param object to remove. * @return true if object was removed, false if not found. */ inline bool remove(T *object) { return Queue::remove(polypointer_cast(object)); } /** * Post a typed object into the queue by it's pointer. This can wait for * a specified timeout if the queue is full, for example, for another * thread to remove an object pointer. This retains the object. * @param object to post. * @param timeout to wait if queue is full in milliseconds. * @return true if object posted, false if queue full and timeout expired. */ inline bool post(T *object, timeout_t timeout = 0) { return Queue::post(polypointer_cast(object), timeout); } /** * Get and remove first typed object posted to the queue. This can wait for * a specified timeut of the queue is empty. The object is still retained * and must be released or deleted by the receiving function. * @param timeout to wait if empty in milliseconds. * @return object from queue or NULL if empty and timed out. */ inline T *fifo(timeout_t timeout = 0) { return polypointer_cast(Queue::fifo(timeout)); } /** * Get and remove last typed object posted to the queue. This can wait for * a specified timeout of the queue is empty. The object is still retained * and must be released or deleted by the receiving function. * @param timeout to wait if empty in milliseconds. * @return object from queue or NULL if empty and timed out. */ inline T *lifo(timeout_t timeout = 0) { return polypointer_cast(Queue::lifo(timeout)); } /** * Examine past item in the queue. This is a typecast of the peek * operation. * @param offset in queue. * @return item pointer if valid or NULL. */ inline const T& at(unsigned offset = 0) { return polyreference_cast(Queue::get(offset)); } /** * Examine past item in the queue. This is a typecast of the peek * operation. * @param offset in queue. * @return item pointer if valid or NULL. */ inline T& operator[](unsigned offset) { return polyreference_cast(Queue::get(offset)); } inline T* operator()(unsigned offset = 0) { return polypointer_cast(Queue::get(offset)); } }; /** * Convenience type for using thread-safe object stacks. */ typedef Stack stack_t; /** * Convenience type for using thread-safe object fifo (queue). */ typedef Queue fifo_t; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/datetime.h0000664000175000017500000006307012537554527014345 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Basic classes for manipulating time and date based data, particularly * that may be in strings. * @file ucommon/datetime.h */ /** * Example of date & time manipulation. * @example datetime.cpp */ #ifndef _UCOMMON_DATETIME_H_ #define _UCOMMON_DATETIME_H_ #ifndef _UCOMMON_CONFIG_H_ #include #endif #ifndef _UCOMMON_NUMBERS_H_ #include #endif #ifndef _UCOMMON_STRING_H_ #include #endif #ifndef _MSWINDOWS_ #include #include #endif #include #define DATE_STRING_SIZE 10 #define DATE_BUFFER_SIZE 11 #define TIME_STRING_SIZE 8 #define TIME_BUFFER_SIZE 9 #define DATETIME_STRING_SIZE 19 #define DATETIME_BUFFER_SIZE 20 /** * Convenience type for struct tm. */ typedef struct tm tm_t; namespace ucommon { #ifdef __BORLANDC__ using std::tm; using std::time_t; #endif /** * The Date class uses a julian date representation of the current * year, month, and day. This is then manipulated in several forms * and may be exported as needed. * * @author David Sugar * @short julian number based date class. */ class __EXPORT Date { protected: long julian; void set(long year, long month, long day); /** * A method to use to "post" any changed values when shadowing * a mixed object class. This is used by DateNumber and string classes. */ virtual void update(void); public: /** * Size of date string field. */ static const size_t sz_string; /** * Create a julian date from a time_t type. * @param value from time() */ Date(time_t value); /** * Create a julian date from a local or gmt date and time. * @param object from DateTime::glt() or gmt(). */ Date(const struct tm *object); /** * Create a julian date from a ISO date string of a specified size. * @param pointer to ISO date string. * @param size of date field if not null terminated. */ Date(const char *pointer, size_t size = 0); /** * Create a julian date from an arbitrary year, month, and day. * @param year of date. * @param month of date (1-12). * @param day of month (1-31). */ Date(int year, unsigned month, unsigned day); /** * Create a julian date object from another object. * @param object to copy. */ Date(const Date& object); /** * Construct a new julian date with today's date. */ Date(); /** * Destroy julian date object. */ virtual ~Date(); /** * Get the year of the date. * @return year of the date */ int year(void) const; /** * Get the month of the date (1-12). * @return month of year */ unsigned month(void) const; /** * Get the day of the month of the date. * @return day of month */ unsigned day(void) const; /** * Get the day of the week (0-7). * @return day of week */ unsigned dow(void) const; /** * Get a ISO string representation of the date (yyyy-mm-dd). * @param buffer to store string. * @return string representation. */ const char *put(char *buffer) const; /** * Get a time_t for the julian date if in time_t epoch. * @return time_t or -1 if out of range. */ time_t timeref(void) const; /** * Get the date as a number for the object or 0 if invalid. * @return date as number. */ long get(void) const; /** * Set (update) the date with current date. */ void set(void); /** * Set the julian date based on an ISO date string of specified size. * @param pointer to date string field. * @param size of field if not null terminated. */ void set(const char *pointer, size_t size = 0); /** * Check if date is valid. * @return true if julian date is valid. */ bool is_valid(void) const; /** * Casting operator to return date as number. * @return julian number. */ inline operator long() const { return get(); } /** * Access julian value. * @return julian number of object. */ inline long operator*() const { return get(); } /** * Expression operator to return an ISO date string for the current * julian date. * @return ISO date string. */ String operator()() const; /** * Increment date by one day. * @return instance of current date object. */ Date& operator++(); /** * Decrement date by one day. * @return instance of current date object. */ Date& operator--(); /** * Increment date by offset. * @param offset to add to julian date. * @return instance of current date object. */ Date& operator+=(long offset); /** * Decrement date by offset. * @param offset to subtract from julian date. * @return instance of current date object. */ Date& operator-=(long offset); /** * Add days to julian date in an expression. * @param days to add. * @return new date object with modified days. */ Date operator+(long days); /** * Subtract days from a julian date in an expression. * @param days to subtract. * @return new date object with modified days. */ Date operator-(long days); /** * Operator to compute number of days between two dates. * @param date offset for computation. * @return number of days difference. */ inline long operator-(const Date &date) { return (julian - date.julian); } /** * Assign date from another date object. * @param date object to assign from. * @return current modified date object. */ Date& operator=(const Date& date); /** * Compare julian dates if same date. * @param date to compare with. * @return true if same. */ bool operator==(const Date& date) const; /** * Compare julian dates if not same date. * @param date to compare with. * @return true if not same. */ bool operator!=(const Date& date) const; /** * Compare julian date if earlier than another date. * @param date to compare with. * @return true if earlier. */ bool operator<(const Date& date) const; /** * Compare julian date if earlier than or equal to another date. * @param date to compare with. * @return true if earlier or same. */ bool operator<=(const Date& date) const; /** * Compare julian date if later than another date. * @param date to compare with. * @return true if later. */ bool operator>(const Date& date) const; /** * Compare julian date if later than or equal to another date. * @param date to compare with. * @return true if later or same. */ bool operator>=(const Date& date) const; /** * Check if julian date is not valid. * @return true if date is invalid. */ inline bool operator!() const { return !is_valid(); } /** * Check if julian date is valid for is() expression. * @return true if date is valid. */ inline operator bool() const { return is_valid(); } }; /** * The Time class uses a integer representation of the current * time. This is then manipulated in several forms and may be * exported as needed. The time object can represent an instance in * time (hours, minutes, and seconds) in a 24 hour period or can * represent a duration. Millisecond accuracy can be offered. * * @author Marcelo Dalmas and David Sugar * @short Integer based time class. */ class __EXPORT Time { protected: long seconds; protected: virtual void update(void); public: void set(int hour, int minute = 0, int second = 0); /** * Constant for number of seconds in a day. */ static const long c_day; /** * Constant for number of seconds in a hour. */ static const long c_hour; /** * Constant for number of seconds in a week. */ static const long c_week; /** * Size of time string field. */ static const size_t sz_string; /** * Create a time from the time portion of a time_t. * @param value of time_t to use. */ Time(const time_t value); /** * Create a time from the time portion of a date and time object. * @param object from DateTime::glt() or gmt(). */ Time(const tm_t *object); /** * Create a time from a hh:mm:ss formatted time string. * @param pointer to formatted time field. * @param size of field if not null terminated. */ Time(const char *pointer, size_t size = 0); /** * Create a time from hours (0-23), minutes (0-59), and seconds (0-59). * @param hour of time. * @param minute of time. * @param second of time. */ Time(int hour, int minute, int second); /** * Create a time object from another object. * @param object to copy. */ Time(const Time& object); /** * Create a time from current time. */ Time(); /** * Destroy time object. */ virtual ~Time(); /** * Get current time in seconds from midnight. * @return seconds from midnight. */ long get(void) const; /** * Get hours from midnight. * @return hours from midnight. */ int hour(void) const; /** * Get minutes from current hour. * @return minutes from current hour. */ int minute(void) const; /** * Get seconds from current minute. * @return seconds from current minute. */ int second(void) const; /** * Get a hh:mm:ss formatted string for current time. * @param buffer to store time string in. * @return time string buffer or NULL if invalid. */ const char *put(char *buffer) const; /** * Set (update) the time with current time. */ void set(void); /** * Set time from a hh:mm:ss formatted string. * @param pointer to time field. * @param size of field if not null terminated. */ void set(const char *pointer, size_t size = 0); /** * Check if time object had valid value. * @return true if object is valid. */ bool is_valid(void) const; /** * Check if time object has valid value for is() operator. * @return true if object is valid. */ inline operator bool() const { return is_valid(); } /** * Check if time object has valid value for ! operator. * @return true if object is not valid. */ inline bool operator!() const { return !is_valid(); } /** * Get difference (in seconds) between two times. * @param reference time to get difference from. * @return difference in seconds. */ long operator-(const Time &reference); /** * Add seconds to the current time, wrap if 24 hours. * @param seconds to add. * @return new time object with modified value. */ Time operator+(long seconds); /** * Subtract seconds to the current time, wrap if 24 hours. * @param seconds to subtract. * @return new time object with modified value. */ Time operator-(long seconds); /** * Get time in seconds. * @return seconds. */ inline operator long() const { return get(); } /** * Get object time in seconds. * @return time in seconds. */ inline long operator*() const { return get(); } /** * Convert to standard 24 hour time string. * @return time string. */ String operator()() const; /** * Incrememnt time by 1 second, wrap on 24 hour period. * @return modified instance of current time object. */ Time& operator++(); /** * Decrement time by 1 second, wrap on 24 hour period. * @return modified instance of current time object. */ Time& operator--(); /** * Assign a time as a copy of another time. * @param time to assign from. * @return time object that was assigned. */ Time& operator=(const Time& time); /** * Increment time by specified seconds. Wraps on 24 hour period. * @param seconds to add to current time. * @return modified instance of current time object. */ Time& operator+=(long seconds); /** * Decrement time by specified seconds. Wraps on 24 hour period. * @param seconds to subtract from current time. * @return modified instance of current time object. */ Time& operator-=(long seconds); /** * Compare time with another time to see if same time. * @param time to compare with. * @return true if same time. */ bool operator==(const Time &time) const; /** * Compare time with another time to see if not same time. * @param time to compare with. * @return true if not same time. */ bool operator!=(const Time &time) const; /** * Compare time if earlier than another time. * @param time object to compare with. * @return true if earlier than object. */ bool operator<(const Time &time) const; /** * Compare time if earlier than or equal to another time. * @param time object to compare with. * @return true if earlier or same as object. */ bool operator<=(const Time &time) const; /** * Compare time if later than another time. * @param time object to compare with. * @return true if later than object. */ bool operator>(const Time &time) const; /** * Compare time if later than or equal to another time. * @param time object to compare with. * @return true if later than or same as object. */ bool operator>=(const Time &time) const; }; /** * The Datetime class uses a julian date representation of the current * year, month, and day and a integer representation of the current * time. This is then manipulated in several forms * and may be exported as needed. * * @author Marcelo Dalmas * @short Integer based time class. */ class __EXPORT DateTime : public Date, public Time { protected: void update(void); public: /** * Size of datetime string field. */ static const size_t sz_string; /** * Construct a date and time from C library time_t type. * @param time type to make date and time from. */ DateTime(const time_t time); /** * Construct a date and time from C library time structure. * @param tm structure from C library (from glt or gmt). */ DateTime(const tm_t *tm); /** * Construct a date and time from ISO string buffer. * @param pointer to string field holding date and time. * @param size of field if not null terminated string. */ DateTime(const char *pointer, size_t size = 0); /** * Construct a date and time object from explicit date and time values. * @param year of object. * @param month of object (1-12). * @param day of month of object (1-31). * @param hour of object (0-23). * @param minute of object (0-59). * @param second of object (0-59). */ DateTime(int year, unsigned month, unsigned day, int hour = 0, int minute = 0, int second = 0); /** * Create a datetime object from another object. * @param object to copy. */ DateTime(const DateTime& object); /** * Construct a new date and time object with current date and time. */ DateTime(); /** * Destroy date and time object. */ virtual ~DateTime(); /** * Get a ISO formatted date and time string for current object. * @param buffer to store date and time in (yyyy-mm-dd hh:mm:ss). * @return string buffer if object is valid. */ const char *put(char *buffer) const; /** * Get C library time_t type if object in C library epoch range. * @return time in seconds from epoch or ~0l if out of range. */ time_t get(void) const; /** * Test if object is valid. * @return true if object is valid. */ bool is_valid(void) const; /** * Operator to compute number of days between two dates. * @param datetime to offset from for computation. * @return number of days difference. */ long operator-(const DateTime &datetime); /** * Assign date and time from another datetime object. * @param datetime object to assign from. * @return assigned datetime object. */ DateTime& operator=(const DateTime& datetime); /** * Add seconds to the current datetime object. Day overflows update * julian date. * @param seconds to add to object. * @return modified datetime object. */ DateTime& operator+=(long seconds); /** * Subtract seconds from current datetime object. Day underflows * update julian date. * @param seconds to subtract from object. * @return modified datetime object. */ DateTime& operator-=(long seconds); /** * Add seconds to datetime in an expression. Day overflows update * julian date. * @param seconds to add to datetime. * @return new modified datetime object. */ DateTime operator+(long seconds); /** * Subtract seconds from datetime in an expression. Day underflows * update julian date. * @param seconds to subtract from datetime. * @return new modified datetime object. */ DateTime operator-(long seconds); /** * Add a day from the current date and time. * @return datetime object reference that was modified. */ DateTime& operator++(); /** * Subtract a day from the current date and time. * @return datetime object reference that was modified. */ DateTime& operator--(); /** * Compare date and time with another date and time to see if the same. * @param datetime to compare with. * @return true if equal. */ bool operator==(const DateTime& datetime) const; /** * Compare date and time with another date and time to see if not same. * @param datetime to compare with. * @return true if not equal. */ bool operator!=(const DateTime& datetime) const; /** * Compare date and time with another date and time to see if earlier. * @param datetime to compare with. * @return true if earlier. */ bool operator<(const DateTime& datetime) const; /** * Compare date and time with another date and time to see if earlier or * the same. * @param datetime to compare with. * @return true if earlier or equal. */ bool operator<=(const DateTime& datetime) const; /** * Compare date and time with another date and time to see if later. * @param datetime to compare with. * @return true if later. */ bool operator>(const DateTime& datetime) const; /** * Compare date and time with another date and time to see if later or * the same. * @param datetime to compare with. * @return true if later or equal. */ bool operator>=(const DateTime& datetime) const; /** * Check if date and time is not valid. * @return true if not valid. */ bool operator!() const; /** * Test is date and time is valid for is() operator. * @return true if object is valid. */ operator bool() const; /** * Casting operator to return date as number. * @return date as a number. */ inline operator long() const { return Date::get(); } /** * Set (update) the date and time with current date and time. */ void set(void); /** * Convert date and time to julian day number. * @return julian day number as a double. */ operator double() const; /** * Return date and time formatted using strftime format values. * @param strftime format to use. * @return String object with formatted time. */ String format(const char *strftime) const; /** * Fetch an instance of time converted to local time. If the localtime * abi is not re-entrant, than a lock is held, otherwise a unique * object is returned. In either case, when you are done, you must * release the object. * @param time object or NULL if using current time. * @return locked instance of struct tm object. */ static tm_t *local(const time_t *time = NULL); /** * Fetch an instance of time converted to gmt. If the gmtime abi * is not re-entrant, than a lock is held, otherwise a unique * object is returned. In either case, when you are done, you must * release the object. * @param time object or NULL if using current time. * @return locked instance of struct tm object. */ static tm_t *gmt(const time_t *time = NULL); /** * Release a struct tm object from glt or gmt. * @param object to release. */ static void release(tm_t *object); }; /** * A DateTime string class. This can be used to access the date and time * as a standard string without requiring an external buffer. * * @author David Sugar * @short a datetime class that returns strings. */ class __EXPORT DateTimeString : public DateTime { public: /** * Specify string buffer mode. By default we form a string with date * and time. */ typedef enum { DATE, TIME, BOTH } mode_t; private: char buffer[DATETIME_BUFFER_SIZE]; mode_t mode; protected: void update(void); public: /** * Construct a date and time from C libraray time_t type. * @param time type to make date and time from. */ DateTimeString(const time_t time); /** * Construct a date and time from C library time structure. * @param tm structure from C library (from glt or gmt). */ DateTimeString(const tm_t *tm); /** * Construct a date and time from ISO string buffer. * @param pointer to string field holding date and time. * @param size of field if not null terminated string. */ DateTimeString(const char *pointer, size_t size = 0); /** * Construct a date and time object from explicit date and time values. * @param year of object. * @param month of object (1-12). * @param day of month of object (1-31). * @param hour of object (0-23). * @param minute of object (0-59). * @param second of object (0-59). */ DateTimeString(int year, unsigned month, unsigned day, int hour = 0, int minute = 0, int second = 0); /** * Create a datetime object from another object. * @param object to copy. */ DateTimeString(const DateTimeString& object); /** * Construct a new date and time object with current date and time. */ DateTimeString(mode_t string = DateTimeString::BOTH); /** * Destroy date time string. */ virtual ~DateTimeString(); /** * Extract char from string. * * @return string of datetime. */ inline const char *c_str(void) const { return buffer; } /** * Cast to string. * * @return string of datetime. */ inline operator const char *(void) const { return buffer; } /** * Set (update) the date and time with current date and time. */ void set(void); /** * Set the string mode. * @param string mode to use. */ void set(mode_t string); }; /** * A number class that manipulates a string buffer that is also a date. * * @author David Sugar * @short a number that is also a date string. */ class __EXPORT DateNumber : public Number, public Date { protected: void update(void); public: /** * Create a date number tied to a refreshed string buffer. * @param pointer to string buffer to rewrite. */ DateNumber(char *pointer); /** * Release a datenumber object. */ virtual ~DateNumber(); /** * Set date number to current date. */ void set(void); }; class __EXPORT isotime : public PrintProtocol, public InputProtocol { private: Date *d; Time *t; enum { DATE, TIME, DATETIME } mode; char buf[32]; unsigned pos; protected: const char *_print(void) const; int _input(int code); public: isotime(Date& date, Time& time); isotime(Date& date); isotime(Time& time); }; /** * Convenience type for using DateTime object. */ typedef DateTime datetime_t; /** * Convenience type for using DateTimeString object. */ typedef DateTimeString datetimestring_t; /** * Convenience type for using Date object. */ typedef Date date_t; /** * Convenience type for using Time object. */ typedef Time tod_t; } // namespace ucommon extern "C" { __EXPORT long tzoffset(struct timezone *tz = NULL); } #endif ucommon-6.4.4/inc/ucommon/protocols.h0000664000175000017500000004550312504226676014571 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Abstract interfaces and support. This is a set of "protocols", a concept * borrowed from other object oriented languages, to define interfaces for * low level services. By using a protocol base class which offers both * virtuals and support methods only, one can easily stack and share these * as common base classes without having to consider when the final derived * object implements them. Core protocol methods always are tagged with a * _ prefix to make it easier to track their derivation. * @file ucommon/protocols.h * @author David Sugar */ #ifndef _UCOMMON_PROTOCOLS_H_ #define _UCOMMON_PROTOCOLS_H_ #ifndef _UCOMMON_CPR_H_ #include #endif namespace ucommon { class String; class StringPager; class __EXPORT MemoryProtocol { protected: friend class MemoryRedirect; /** * Protocol to allocate memory from the pager heap. The size of the * request must be less than the size of the memory page used. The * actual method is in a derived or stacked object. * @param size of memory request. * @return allocated memory or NULL if not possible. */ virtual void *_alloc(size_t size) = 0; /** * Allocation failure handler. */ virtual void fault(void) const; public: virtual ~MemoryProtocol(); /** * Convenience function. * @param size of memory request. * @return alocated memory or NULL if not possible. */ inline void *alloc(size_t size) {return _alloc(size);} /** * Allocate memory from the pager heap. The size of the request must be * less than the size of the memory page used. The memory is initialized * to zero. This uses alloc. * @param size of memory request. * @return allocated memory or NULL if not possible. */ void *zalloc(size_t size); /** * Duplicate NULL terminated string into allocated memory. This uses * alloc. * @param string to copy into memory. * @return allocated memory with copy of string or NULL if cannot allocate. */ char *dup(const char *string); /** * Duplicate existing memory block into allocated memory. This uses alloc. * @param memory to data copy from. * @param size of memory to allocate. * @return allocated memory with copy or NULL if cannot allocate. */ void *dup(void *memory, size_t size); }; /** * A redirection base class for the memory protocol. This is used because * sometimes we choose a common memory pool to manage different objects. * @author David Sugar */ class __EXPORT MemoryRedirect : public MemoryProtocol { private: MemoryProtocol *target; public: MemoryRedirect(MemoryProtocol *protocol); virtual void *_alloc(size_t size); }; /** * Common locking protocol. This is used for objects that may internally * have sync'd functions, directly or in a derived class, that lock the * current object. The default handlers do nothing but offer the virtuals * as a stub. * @author David Sugar */ class __EXPORT LockingProtocol { protected: virtual void _lock(void); virtual void _unlock(void); public: virtual ~LockingProtocol(); }; /** * Used for forming stream output. We would create a derived class who's * constructor creates an internal string object, and a single method to * extract that string. * @author David Sugar */ class __EXPORT PrintProtocol { public: virtual ~PrintProtocol(); /** * Extract formatted string for object. */ virtual const char *_print(void) const = 0; }; /** * Used for processing input. We create a derived class that processes a * single character of input, and returns a status value. EOF means it * accepts no more input and any value other than 0 is a character to also * unget. Otherwise 0 is good to accept more input. The constructor is * used to reference a final destination object in the derived class. * @author David Sugar */ class __EXPORT InputProtocol { public: virtual ~InputProtocol(); /** * Extract formatted string for object. * @param character code we are pushing. * @return 0 to keep processing, EOF if done, or char to unget. */ virtual int _input(int code) = 0; }; /** * Common character processing protocol. This is used to access a character * from some type of streaming buffer or memory object. * @author David Sugar */ class __EXPORT CharacterProtocol { protected: const char *eol; int back; CharacterProtocol(); /** * Get the next character. * @return next character or EOF. */ virtual int _getch(void) = 0; /** * Put the next character. * @param code to put. * @return code or EOF if cannot put. */ virtual int _putch(int code) = 0; /** * Write to back buffer. Mostly used for input format processing. * @param code to write into backbuffer. */ inline void putback(int code) {back = code;} /** * Set end of line marker. Normally this is set to cr & lf, which * actually supports both lf alone and cr/lf termination of lines. * However, putline() will always add the full cr/lf if this mode is * used. This option only effects getline() and putline(). * @param string for eol for getline and putline. */ inline void seteol(const char *string) {eol = string;} public: virtual ~CharacterProtocol(); /** * Get the next character. * @return next character or EOF. */ inline int getchar(void) {return _getch();} /** * Put the next character. * @param code to put. * @return code or EOF if cannot put. */ inline int putchar(int code) {return _putch(code);} size_t print(const PrintProtocol& format); size_t input(InputProtocol& format); /** * Get text as a line of input from the buffer. The eol character(s) * are used to mark the end of a line. Because the end of line character * is stripped, the length of the string may be less than the actual * count read. If at the end of the file buffer and unable to read more * data an error occured then 0 is returned. * @param string to save input into. * @param size limit of string to save. * @return count of characters actually read or 0 if at end of data. */ size_t getline(char *string, size_t size); /** * Get a string as a line of input from the buffer. The eol character(s) * are used to mark the end of a line. Because the end of line character * is stripped, the length of the string may be less than the actual * count read. If at the end of the file buffer and unable to read more * data an error occured then 0 is returned. * @param buffer to save input into. * @return count of characters actually read or 0 if at end of data. */ size_t getline(String& buffer); /** * Put a string as a line of output to the buffer. The eol character is * appended to the end. * @param string to write. * @return total characters successfully written, including eol chars. */ size_t putline(const char *string); size_t putchars(const char *string, size_t count = 0); /** * Load input to a string list. The string list filter method is used to * control loading. * @param list to load into. * @return number of items loaded. */ size_t load(StringPager *list); /** * Save output from a string list. * @param list to save from. * @return number of items loaded. */ size_t save(const StringPager *list); }; /** * Common buffer protocol class. This is used to create objects which will * stream character data as needed. This class can support bidirectional * streaming as may be needed for serial devices, sockets, and pipes. The * buffering mechanisms are hidden from derived classes, and two virtuals * are used to communicate with the physical transport. * @author David Sugar */ class __EXPORT BufferProtocol : public CharacterProtocol { public: typedef enum {RDONLY, WRONLY, RDWR} mode_t; private: char *buffer; char *input, *output; size_t bufsize, bufpos, insize, outsize; bool end; protected: const char *format; /** * Construct an empty (unallocated) buffer. */ BufferProtocol(); /** * Construct a buffer of pre-allocated size and access type. * @param size of buffer to allocate. * @param access mode of buffer. */ BufferProtocol(size_t size, mode_t access = RDWR); /** * Destroy object by releasing buffer memory. */ virtual ~BufferProtocol(); /** * Allocation error handler. */ virtual void fault(void) const; /** * Allocate I/O buffer(s) of specified size. If a buffer is currently * allocated, it is released. * @param size of buffer to allocate. * @param access mode of buffer. */ void allocate(size_t size, mode_t access = RDWR); /** * Release (free) buffer memory. */ void release(void); /** * Request workspace in output buffer. This returns a pointer to * memory from the output buffer and advances the output position. * This is sometimes used for a form of zero copy write. * @param size of request area. * @return data pointer or NULL if not available. */ char *request(size_t size); /** * Gather returns a pointer to contiguous input of specified size. * This may require moving the input data in memory. * @param size of gather space. * @return data pointer to gathered data or NULL if not available. */ char *gather(size_t size); /** * Method to push buffer into physical i/o (write). The address is * passed to this virtual since it is hidden as private. * @param address of data to push. * @param size of data to push. * @return number of bytes written, 0 on error. */ virtual size_t _push(const char *address, size_t size) = 0; /** * Method to pull buffer from physical i/o (read). The address is * passed to this virtual since it is hidden as private. * @param address of buffer to pull data into. * @param size of buffer area being pulled.. * @return number of read written, 0 on error or end of data. */ virtual size_t _pull(char *address, size_t size) = 0; /** * Method to get low level i/o error. * @return error from low level i/o methods. */ virtual int _err(void) const = 0; /** * Method to clear low level i/o error. */ virtual void _clear(void) = 0; /** * Return true if blocking. */ virtual bool _blocking(void); /** * Check if data is pending. */ virtual bool _pending(void); /** * Flush buffer to physical i/o. */ virtual bool _flush(void); virtual int _getch(void); virtual int _putch(int ch); /** * Get current input position. Sometimes used to help compute and report * a "tell" offset. * @return offset of input buffer. */ inline size_t input_pending(void) const {return bufpos;} /** * Get current output position. Sometimes used to help compute a * "trunc" operation. */ inline size_t output_waiting(void) const {return outsize;} public: const char *endl(void) const {return eol;} /** * Put memory into the buffer. If count is 0 then put as NULL * terminated string. * @param address of characters to put into buffer. * @param count of characters to put into buffer. * @return number of characters actually written. */ size_t put(const void *address, size_t count); /** * Get memory from the buffer. * @param address of characters save from buffer. * @param count of characters to get from buffer. * @return number of characters actually copied. */ size_t get(void *address, size_t count); /** * Print formatted string to the buffer. The maximum output size is * the buffer size, and the operation flushes the buffer. * @param format string. * @return number of bytes written. */ size_t printf(const char *format, ...) __PRINTF(2, 3); /** * Flush buffered memory to physical I/O. * @return true on success, false if not active or fails. */ inline bool flush(void) {return _flush();} /** * Purge any pending input or output buffer data. */ void purge(void); /** * Reset input buffer state. Drops any pending input. */ void reset(void); /** * Check if at end of input. * @return true if end of data, false if input still buffered. */ bool eof(void); /** * See if buffer open. * @return true if buffer active. */ inline operator bool() const {return buffer != NULL;} /** * See if buffer closed. * @return true if buffer inactive. */ inline bool operator!() const {return buffer == NULL;} /** * See if buffer open. * @return true if buffer active. */ inline bool is_open(void) const {return buffer != NULL;} /** * See if input active. * @return true if input active. */ inline bool is_input(void) const {return input != NULL;} /** * See if output active. * @return true if output active. */ inline bool is_output(void) const {return output != NULL;} /** * See if pending input. * @return true if input pending. */ inline bool is_pending(void) {return _pending();} /** * Set eof flag. */ inline void seteof(void) {end = true;} inline int err(void) const {return _err();} template inline size_t write(const T& data) {return put(&data, sizeof(T));} template inline size_t read(T& data) {return get(&data, sizeof(T));} template inline size_t write(const T* data, unsigned count) {return put(data, sizeof(T) * count) / sizeof(T);} template inline size_t read(T* data, unsigned count) {return get(data, sizeof(T) * count) / sizeof(T);} }; /** * A common base class for all managed objects. This is used to manage * objects that might be linked or reference counted. The base class defines * only core virtuals some common public methods that should be used by * all inherited object types. * @author David Sugar */ class __EXPORT ObjectProtocol { public: /** * Method to retain (or increase retention) of an object. */ virtual void retain(void) = 0; /** * Method to release (or decrease retention) of an object. */ virtual void release(void) = 0; /** * Required virtual destructor. */ virtual ~ObjectProtocol(); /** * Retain (increase retention of) object when copying. */ ObjectProtocol *copy(void); /** * Increase retention operator. */ inline void operator++(void) {retain();}; /** * Decrease retention operator. */ inline void operator--(void) {release();}; }; /** * Key data protocol used for things like maps and ordered lists. */ class __EXPORT KeyProtocol { protected: virtual int keytype(void) const = 0; /** * Size of key data. */ virtual size_t keysize(void) const = 0; /** * Buffer of key value. */ virtual const void *keydata(void) const = 0; virtual bool equal(const KeyProtocol& compare) const; inline bool operator!=(const KeyProtocol& compare) const { return !equal(compare); } virtual ~KeyProtocol(); }; /** * At least with gcc, linking of stream operators was broken. This provides * an auxillory class to solve the issue. */ class __EXPORT _character_operators { private: inline _character_operators() {} public: static CharacterProtocol& print(CharacterProtocol& p, const char *s); static CharacterProtocol& print(CharacterProtocol& p, const char& ch); static CharacterProtocol& input(CharacterProtocol& p, char& ch); static CharacterProtocol& input(CharacterProtocol& p, String& str); static CharacterProtocol& print(CharacterProtocol& p, const long& value); static CharacterProtocol& input(CharacterProtocol& p, long& value); static CharacterProtocol& print(CharacterProtocol& p, const double& value); static CharacterProtocol& input(CharacterProtocol& p, double& value); }; inline CharacterProtocol& operator<< (CharacterProtocol& p, const char *s) {return _character_operators::print(p, s);} inline CharacterProtocol& operator<< (CharacterProtocol& p, const char& ch) {return _character_operators::print(p, ch);} inline CharacterProtocol& operator>> (CharacterProtocol& p, char& ch) {return _character_operators::input(p, ch);} inline CharacterProtocol& operator>> (CharacterProtocol& p, String& str) {return _character_operators::input(p, str);} inline CharacterProtocol& operator<< (CharacterProtocol& p, const PrintProtocol& format) {p.print(format); return p;} inline CharacterProtocol& operator>> (CharacterProtocol& p, InputProtocol& format) {p.input(format); return p;} inline CharacterProtocol& operator<< (CharacterProtocol& p, const StringPager& list) {p.save(&list); return p;} inline CharacterProtocol& operator>> (CharacterProtocol& p, StringPager& list) {p.load(&list); return p;} inline CharacterProtocol& operator<< (CharacterProtocol& p, const long& value) {return _character_operators::print(p, value);} inline CharacterProtocol& operator>> (CharacterProtocol& p, long& value) {return _character_operators::input(p, value);} inline CharacterProtocol& operator<< (CharacterProtocol& p, const double& value) {return _character_operators::print(p, value);} inline CharacterProtocol& operator>> (CharacterProtocol& p, double& value) {return _character_operators::input(p, value);} } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/timers.h0000664000175000017500000002622312504227034014033 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Realtime timers and timer queues. * This offers ucommon support for realtime high-resolution threadsafe * timers and timer queues. Threads may be scheduled by timers and timer * queues may be used to inject timer events into callback objects or through * virtuals. * @file ucommon/timers.h */ #ifndef _UCOMMON_TIMERS_H_ #define _UCOMMON_TIMERS_H_ #ifndef _UCOMMON_LINKED_H_ #include #endif #ifndef _MSWINDOWS_ #include #include #endif #include namespace ucommon { /** * Timer class to use when scheduling realtime events. The timer generally * uses millisecond values but has a microsecond accuracy. On platforms that * support it, the timer uses posix realtime monotonic clock extensions, * otherwise lower accuracy timer systems might be used. */ class __EXPORT Timer { private: friend class Conditional; friend class Semaphore; friend class Event; #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) timespec timer; #else #undef POSIX_TIMERS // make sure not used if no support timeval timer; #endif bool updated; protected: /** * Check if timer has been updated since last check. * @return true if updated. */ bool update(void); /** * Check if timer active. * @return true if active. */ bool is_active(void) const; public: #if _MSC_VER > 1400 // windows broken dll linkage issue... static const timeout_t inf = ((timeout_t)(-1)); static const time_t reset = ((time_t)(0)); #else static const timeout_t inf; /**< A value to use for infinite time */ static const time_t reset; /**< A value to use when resetting */ #endif #ifdef _MSWINDOWS_ typedef unsigned __int64 tick_t; #else typedef uint64_t tick_t; #endif /** * Construct an untriggered timer set to the time of creation. */ Timer(); /** * Construct a triggered timer that expires at specified offset. * @param offset to expire in milliseconds. */ Timer(timeout_t offset); /** * Construct a triggered timer that expires at specified offset. * @param offset to expire in seconds. */ Timer(time_t offset); /** * Construct a timer from a copy of another timer. * @param copy of timer to construct from. */ Timer(const Timer& copy); /** * Set the timer to expire. * @param expire time in milliseconds. */ void set(timeout_t expire); /** * Set the timer to expire. * @param expire time in seconds. */ void set(time_t expire); /** * Set (update) the timer with current time. */ void set(void); /** * Clear pending timer, has no value. */ void clear(void); /** * Get remaining time until the timer expires. * @return 0 if expired or milliseconds still waiting. */ timeout_t get(void) const; /** * Get remaining time until timer expires by reference. * @return 0 if expired or milliseconds still waiting. */ inline timeout_t operator*() const {return get();} /** * Check if timer has expired. * @return true if timer still pending. */ bool operator!() const; /** * Check if timer expired for is() expression. * @return true if timer expired. */ operator bool() const; /** * Set timer expiration. * @param expire timer in specified seconds. */ Timer& operator=(time_t expire); /** * Set timer expiration. * @param expire timer in milliseconds. */ Timer& operator=(timeout_t expire); /** * Adjust timer expiration. * @param expire time to add in seconds. */ Timer& operator+=(time_t expire); /** * Adjust timer expiration. * @param expire time to add in milliseconds. */ Timer& operator+=(timeout_t expire); /** * Adjust timer expiration. * @param expire time to subtract in seconds. */ Timer& operator-=(time_t expire); /** * Adjust timer expiration. * @param expire time to subtract in milliseconds. */ Timer& operator-=(timeout_t expire); /** * Compute difference between two timers. * @param timer to use for difference. * @return difference in milliseconds. */ timeout_t operator-(const Timer& timer); /** * Compare timers if same timeout. * @param timer to compare with. * @return true if same. */ bool operator==(const Timer& timer) const; /** * Compare timers if not same timeout. * @param timer to compare with. * @return true if not same. */ bool operator!=(const Timer& timer) const; /** * Compare timers if earlier timeout than another timer. * @param timer to compare with. * @return true if earlier. */ bool operator<(const Timer& timer) const; /** * Compare timers if earlier than or equal to another timer. * @param timer to compare with. * @return true if earlier or same. */ bool operator<=(const Timer& timer) const; /** * Compare timers if later timeout than another timer. * @param timer to compare with. * @return true if later. */ bool operator>(const Timer& timer) const; /** * Compare timers if later than or equal to another timer. * @param timer to compare with. * @return true if later or same. */ bool operator>=(const Timer& timer) const; /** * Sleep current thread until the specified timer expires. * @param timer to reference for sleep. */ static void sync(Timer &timer); /** * Get timer ticks since uuid epoch. * @return timer ticks in 100ns resolution. */ static tick_t ticks(void); }; /** * A timer queue for timer events. The timer queue is used to hold a * linked list of timers that must be processed together. The timer * queue processes the timer event list and calls an expired function * on events that have expired. The timer queue also determines the * wait time until the next timer will expire. When timer events are * modified, they can retrigger the queue to re-examine the list to * find when the next timer will now expire. * @author David Sugar */ class __EXPORT TimerQueue : public OrderedIndex { public: /** * A timer event object that lives on a timer queue. Timer events are * triggered through the timer queue's expire method. Timer events * also modify the queue when they are changed, particularly to force * re-evaluation of the expiration period. This class is not used by * itself but rather as a base class for a timer event object. * @author David Sugar */ class __EXPORT event : protected Timer, public LinkedList { protected: friend class TimerQueue; /** * Construct a timer event object and initially arm. * @param expire timer in specified milliseconds. */ event(timeout_t expire); /** * Construct an armed timer event object and attach to queue. * @param queue to add event to. * @param expire timer in specified milliseconds. */ event(TimerQueue *queue, timeout_t expire); /** * Event method to call in derived class when timer expires. */ virtual void expired(void) = 0; /** * Expected next timeout for the timer. This may be overriden * for strategy purposes when evaluted by timer queue's expire. * @return milliseconds until timer next triggers. */ virtual timeout_t timeout(void); public: /** * Detaches from queue when destroyed. */ virtual ~event(); /** * Attach event to a timer queue. Detaches from previous list if * already attached elsewhere. * @param queue to attach to. */ void attach(TimerQueue *queue); /** * Detach event from a timer queue. */ void detach(void); /** * Arm event to trigger at specified timeout. * @param timeout to expire and trigger. */ void arm(timeout_t timeout); /** * Disarm event. */ void disarm(void); /** * Time remaining until expired. * @return milliseconds until timer expires. */ inline timeout_t get(void) const {return Timer::get();} /** * Notify timer queue that the timer has been updated. */ void update(void); /** * Get the timer queue we are attached to. * @return timer queue or NULL if not attached. */ inline TimerQueue *list(void) const {return static_cast(Root);} }; protected: friend class event; /** * Called in derived class when the queue is being modified. * This is often used to lock the list. */ virtual void modify(void) = 0; /** * Called in derived class after the queue has been modified. This often * releases a lock that modify set and to wakeup a timer thread to * evaluate when the next timer will now expire. */ virtual void update(void) = 0; public: /** * Create an empty timer queue. */ TimerQueue(); /** * Destroy queue, does not remove event objects. */ virtual ~TimerQueue(); /** * Add a timer event to the timer queue. * @param timer event to add. */ void operator+=(event &timer); /** * Remove a timer event from the timer queue. * @param timer event to remove. */ void operator-=(event &timer); /** * Process timer queue and find when next event triggers. This function * will call the expired methods on expired timers. Normally this function * will be called in the context of a timer thread which sleeps for the * timeout returned unless it is awoken on an update event. * @return timeout until next timer expires in milliseconds. */ timeout_t expire(); }; /** * A convenience type for timer queue timer events. */ typedef TimerQueue::event TQEvent; /** * A convenience type for timers. */ typedef Timer timer_t; } // namespace ucommon extern "C" { #if defined(WIN32) __EXPORT int gettimeofday(struct timeval *tv, void *tz); #endif } #endif ucommon-6.4.4/inc/ucommon/memory.h0000664000175000017500000012145312555235012014042 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Private heaps, pools, and associations. * Private heaps often can reduce locking contention in threaded applications * since they do not require using the global "malloc" function. Private * heaps also can be used as auto-release heaps, where all memory allocated * and handled out for small objects can be automatically released all at once. * Pager pools are used to optimize system allocation around page boundaries. * Associations allow private memory to be tagged and found by string * identifiers. * @file ucommon/memory.h */ #ifndef _UCOMMON_MEMORY_H_ #define _UCOMMON_MEMORY_H_ #ifndef _UCOMMON_CONFIG_H_ #include #endif #ifndef _UCOMMON_PROTOCOLS_H_ #include #endif #ifndef _UCOMMON_LINKED_H_ #include #endif #ifndef _UCOMMON_STRING_H_ #include #endif namespace ucommon { class PagerPool; /** * A memory protocol pager for private heap manager. This is used to allocate * in an optimized manner, as it assumes no mutex locks are held or used as * part of it's own internal processing. It also is designed for optimized * performance. * @author David Sugar */ class __EXPORT memalloc : public MemoryProtocol { private: friend class bufpager; // disabled... inline memalloc(const memalloc& copy) {}; size_t pagesize, align; unsigned count; typedef struct mempage { struct mempage *next; union { void *memalign; unsigned used; }; } page_t; page_t *page; protected: unsigned limit; /** * Acquire a new page from the heap. This is mostly used internally. * @return page structure of the newly acquired memory page. */ page_t *pager(void); /** * Report runtime memory exhaustion. */ virtual void fault(void) const; public: /** * Construct a memory pager. * @param page size to use or 0 for OS allocation size. */ memalloc(size_t page = 0); /** * Destroy a memory pager. Release all pages back to the heap at once. */ virtual ~memalloc(); /** * Get the number of pages that have been allocated from the real heap. * @return pages allocated from heap. */ inline unsigned pages(void) const {return count;} /** * Get the maximum number of pages that are permitted. One can use a * derived class to set and enforce a maximum limit to the number of * pages that will be allocated from the real heap. This is often used * to detect and bring down apps that are leaking. * @return page allocation limit. */ inline unsigned max(void) const {return limit;} /** * Get the size of a memory page. * @return size of each pager heap allocation. */ inline unsigned size(void) const {return (unsigned)pagesize;} /** * Determine fragmentation level of acquired heap pages. This is * represented as an average % utilization (0-100) and represents the * used portion of each allocated heap page verse the page size. Since * requests that cannot fit on an already allocated page are moved into * a new page, there is some unusable space left over at the end of the * page. When utilization approaches 100, this is good. A low utilization * may suggest a larger page size should be used. * @return pager utilization. */ unsigned utilization(void) const; /** * Purge all allocated memory and heap pages immediately. */ void purge(void); protected: /** * Allocate memory from the pager heap. The size of the request must be * less than the size of the memory page used. This implements the * memory protocol allocation method. * @param size of memory request. * @return allocated memory or NULL if not possible. */ virtual void *_alloc(size_t size); public: /** * Assign foreign pager to us. This relocates the heap references * to our object, clears the other object. */ void assign(memalloc& source); inline memalloc& operator=(memalloc& source) { assign(source); return *this; } }; /** * A managed private heap for small allocations. This is used to allocate * a large number of small objects from a paged heap as needed and to then * release them together all at once. This pattern has significantly less * overhead than using malloc and offers less locking contention since the * memory pager can also have it's own mutex. Pager pool allocated memory * is always aligned to the optimal data size for the cpu bus and pages are * themselves created from memory aligned allocations. A page size for a * memory pager should be some multiple of the OS paging size. * * The mempager uses a strategy of allocating fixed size pages as needed * from the real heap and allocating objects from these pages as needed. * A new page is allocated from the real heap when there is insufficient * space in the existing page to complete a request. The largest single * memory allocation one can make is restricted by the page size used, and * it is best to allocate objects a significant fraction smaller than the * page size, as fragmentation occurs at the end of pages when there is * insufficient space in the current page to complete a request. * @author David Sugar */ class __EXPORT mempager : public memalloc, public LockingProtocol { private: mutable pthread_mutex_t mutex; inline mempager(const mempager& copy) {}; protected: /** * Lock the memory pager mutex. It will be more efficient to lock * the pager and then call the locked allocator than using alloc which * separately locks and unlocks for each request when a large number of * allocation requests are being batched together. */ virtual void _lock(void); /** * Unlock the memory pager mutex. */ virtual void _unlock(void); public: /** * Construct a memory pager. * @param page size to use or 0 for OS allocation size. */ mempager(size_t page = 0); /** * Destroy a memory pager. Release all pages back to the heap at once. */ virtual ~mempager(); /** * Determine fragmentation level of acquired heap pages. This is * represented as an average % utilization (0-100) and represents the * used portion of each allocated heap page verse the page size. Since * requests that cannot fit on an already allocated page are moved into * a new page, there is some unusable space left over at the end of the * page. When utilization approaches 100, this is good. A low utilization * may suggest a larger page size should be used. * @return pager utilization. */ unsigned utilization(void); /** * Purge all allocated memory and heap pages immediately. */ void purge(void); /** * Return memory back to pager heap. This actually does nothing, but * might be used in a derived class to create a memory heap that can * also receive (free) memory allocated from our heap and reuse it, * for example in a full private malloc implementation in a derived class. * @param memory to free back to private heap. */ virtual void dealloc(void *memory); protected: /** * Allocate memory from the pager heap. The size of the request must be * less than the size of the memory page used. This impliments the * memory protocol with mutex locking for thread safety. * is locked during this operation and then released. * @param size of memory request. * @return allocated memory or NULL if not possible. */ virtual void *_alloc(size_t size); public: /** * Assign foreign pager to us. This relocates the heap references * to our object, clears the other object. */ void assign(mempager& source); inline mempager& operator=(mempager& source) { assign(source); return *this; } }; class __EXPORT ObjectPager : protected memalloc { public: class __EXPORT member : public LinkedObject { private: void *mem; protected: friend class ObjectPager; inline void set(member *node) {Next = node;} inline void *get(void) const {return mem;} member(LinkedObject **root); member(); public: inline void *operator*() const {return mem;} }; private: unsigned members; LinkedObject *root; size_t typesize; member *last; void **index; inline ObjectPager(const ObjectPager& ref) {}; protected: ObjectPager(size_t objsize, size_t pagesize = 256); /** * Get object from list. This is useful when objectpager is * passed as a pointer and hence inconvenient for the [] operator. * @param item to access. * @return pointer to text for item, or NULL if out of range. */ void *get(unsigned item) const; /** * Add object to list. * @param object to add. */ void *add(void); void *push(void); /** * Remove element from front of list. Does not release memory. * @return object removed. */ void *pull(void); /** * Remove element from back of list. Does not release memory. * @return object removed. */ void *pop(void); /** * Invalid object... * @return typically NULL. */ void *invalid(void) const; public: /** * Purge all members and release pager member. The list can then * be added to again. */ void clear(void); /** * Get root of pager list. This is useful for externally enumerating * the list of strings. * @return first member of list or NULL if empty. */ inline ObjectPager::member *begin(void) {return static_cast(root);} inline operator bool() const {return members > 0;} inline bool operator!() const {return !members;} /** * Get the number of items in the pager string list. * @return number of items stored. */ inline unsigned count(void) const {return members;} /** * Convenience typedef for iterative pointer. */ typedef linked_pointer iterator; inline size_t size(void) {return memalloc::size();} inline unsigned pages(void) {return memalloc::pages();} protected: /** * Gather index list. * @return index. */ void **list(void); public: /** * Assign foreign pager to us. This relocates the heap references * to our object, clears the other object. */ void assign(ObjectPager& source); inline ObjectPager& operator=(ObjectPager& source) { assign(source); return *this; } }; /** * String pager for storing lists of NULL terminated strings. This is * used for accumulating lists which can be destroyed all at once. * @author David Sugar */ class __EXPORT StringPager : protected memalloc { private: unsigned members; LinkedObject *root; inline StringPager(const StringPager& copy) {}; protected: virtual const char *invalid(void) const; public: /** * Filter text in a derived class. The base class filter removes * newlines at end of text and filters out empty strings. * @param text to filter. * @param size of text buffer for transforms. * @return false if end of data. */ virtual bool filter(char *text, size_t size); /** * Member of string list. This is exposed so that the list of strings * can be externally enumerated with linked_pointer * if so desired, through the begin() method. * @author David Sugar */ class __EXPORT member : public LinkedObject { private: const char *text; protected: friend class StringPager; inline void set(member *node) {Next = node;} member(LinkedObject **root, const char *data); member(const char *data); public: inline const char *operator*() const {return text;} inline const char *get(void) const {return text;} }; /** * Create a pager with a maximum page size. * @param size of pager allocation pages. */ StringPager(size_t pagesize = 256); StringPager(char **list, size_t pagesize = 256); /** * Get the number of items in the pager string list. * @return number of items stored. */ inline unsigned count(void) const {return members;} /** * Get string item from list. This is useful when StringPager is * passed as a pointer and hence inconvenient for the [] operator. * @param item to access. * @return pointer to text for item, or NULL if out of range. */ const char *get(unsigned item) const; /** * Replace string item in list. * @param item to replace. * @param string to replace with. */ void set(unsigned item, const char *string); /** * Add text to list. * @param text to add. */ void add(const char *text); /** * Add text to front of list. * @param text to add. */ void push(const char *text); /** * Add text list to front of list. * @param text to add. */ void push(char **text); /** * Remove element from front of list. Does not release memory. * @return text removed. */ const char *pull(void); /** * Remove element from back of list. Does not release memory. * @return text removed. */ const char *pop(void); /** * Add list to list. This is a list of string pointers terminated with * NULL. * @param list of text to add. */ void add(char **list); /** * Set list to list. This is a list of string pointers terminated with * NULL. * @param list of text to set. */ void set(char **list); /** * Purge all members and release pager member. The list can then * be added to again. */ void clear(void); /** * Return specified member from pager list. This is a convenience * operator. * @param item to access. * @return text of item or NULL if invalid. */ inline const char *operator[](unsigned item) const {return get(item);} inline const char *at(unsigned item) const {return get(item);} /** * Get root of pager list. This is useful for externally enumerating * the list of strings. * @return first member of list or NULL if empty. */ inline StringPager::member *begin(void) const {return static_cast(root);} /** * Convenience operator to add to pager and auto-sort. * @param text to add to list. */ inline void operator+=(const char *text) {add(text);} /** * Convenience operator to add to pager. * @param text to add to list. */ inline StringPager& operator<<(const char *text) {add(text); return *this;} inline StringPager& operator>>(const char *text) {push(text); return *this;} /** * Sort members. */ void sort(void); /** * Gather index list. * @return index. */ char **list(void); /** * Tokenize a string and add each token to the StringPager. * @param text to tokenize. * @param list of characters to use as token separators. * @param quote pairs of characters for quoted text or NULL if not used. * @param end of line marker characters or NULL if not used. * @return number of tokens parsed. */ unsigned token(const char *text, const char *list, const char *quote = NULL, const char *end = NULL); unsigned split(const char *text, const char *string, unsigned flags = 0); unsigned split(stringex_t& expr, const char *string, unsigned flags = 0); String join(const char *prefix = NULL, const char *middle = NULL, const char *suffix = NULL); inline operator bool() {return members > 0;} inline bool operator!() {return !members;} inline StringPager& operator=(char **list) {set(list); return *this;} inline const char *operator*() {return pull();} inline operator char **() {return list();} /** * Convenience typedef for iterative pointer. */ typedef linked_pointer iterator; inline size_t size(void) const {return memalloc::size();} inline unsigned pages(void) const {return memalloc::pages();} private: member *last; char **index; public: /** * Assign foreign pager to us. This relocates the heap references * to our object, clears the other object. */ void assign(StringPager& source); inline StringPager& operator=(StringPager& source) { assign(source); return *this; } }; /** * Directory pager is a paged string list for directory file names. * This protocol is used to convert a directory into a list of filenames. * As a protocol it offers a filtering method to select which files to * include in the list. * @author David Sugar */ class __EXPORT DirPager : protected StringPager { private: DirPager(const DirPager& copy) {}; protected: const char *dir; /** * Filter filenames in a derived class. The default filter * drops "." special files. * @param filename to filter. * @param size of filename buffer. * @return true if include in final list. */ virtual bool filter(char *filename, size_t size); /** * Load a directory path. * @param path to load. * @return true if valid. */ bool load(const char *path); public: DirPager(); DirPager(const char *path); void operator=(const char *path); inline const char *operator*() const {return dir;} inline operator bool() const {return dir != NULL;} inline bool operator!() const {return dir == NULL;} inline unsigned count(void) const {return StringPager::count();} /** * Return specified filename from directory list. This is a convenience * operator. * @param item to access. * @return text of item or NULL if invalid. */ inline const char *operator[](unsigned item) const {return StringPager::get(item);} inline const char *get(unsigned item) const {return StringPager::get(item);} inline const char *at(unsigned item) const {return StringPager::get(item);} inline size_t size(void) const {return memalloc::size();} inline unsigned pages(void) const {return memalloc::pages();} public: /** * Assign foreign pager to us. This relocates the heap references * to our object, clears the other object. */ void assign(DirPager& source); inline DirPager& operator=(DirPager& source) { assign(source); return *this; } }; /** * Buffered pager for storing paged strings for character protocol. * @author David Sugar */ class __EXPORT bufpager : public memalloc, public CharacterProtocol { private: typedef struct cpage { struct cpage *next; char *text; unsigned size, used; } cpage_t; cpage_t *first, *last, *current, *freelist; unsigned cpos; unsigned long ccount; bool eom; /* null written or out of memory */ virtual int _getch(void); virtual int _putch(int code); protected: virtual void *_alloc(size_t size); public: /** * Reset pager text buffer protocol. */ void reset(void); /** * Rewind to start of text buffer protocol. */ void rewind(void); /** * Create an output string from buffer. * @return output string allocated. */ char *dup(void); /** * Set text of string buffer. * @param text to set. */ void set(const char *text); /** * Add text to string buffer. * @param text to add. */ void add(const char *text); /** * Get string from buffer. * @param text to save into. * @param size of buffer. * @return count of characters copied. */ size_t get(char *text, size_t size); /** * Put memory string into buffer including NULL byte. * @param text to add. * @param size of text to add. */ void put(const char *text, size_t size); /** * Get total size. * @return number of characters in buffer. */ inline unsigned long used(void) const {return ccount;} /** * Convenience operator to get text. * @return text string of buffer. */ inline char *operator *() {return dup();} /** * Convenience operator to add to pager. * @param text to add to list. */ inline bufpager& operator<<(const char *text) {add(text); return *this;} bufpager(size_t page = 0); /** * Request character buffer to write into directly. * @param iosize made available. * @return pointer to buffer or NULL if out of memory. */ char *request(size_t *iosize); /** * Get pointer to copy character data. The memory pointer is * positioned at the next chunk automatically. * @param iosize of data you can copy. * @return to data from buffer or NULL if past end. */ char *copy(size_t *iosize); /** * Used to complete a request method. * @param size of data actually written. */ void update(size_t size); /** * Check if can still save into buffer. * @return true if buffer is full. */ inline bool operator!() const {return eom;} /** * Check if can still save into buffer. Used for is() function. * @return true if pager can still store more. */ inline operator bool() const {return !eom;} /** * Assign foreign pager to us. This relocates the heap references * to our object, clears the other object. */ void assign(bufpager& source); inline bufpager& operator=(bufpager& source) { assign(source); return *this; } }; /** * Create a linked list of auto-releasable objects. LinkedObject derived * objects can be created that are assigned to an autorelease object list. * When the autorelease object falls out of scope, all the objects listed' * with it are automatically deleted. * @author David Sugar */ class __EXPORT autorelease { private: LinkedObject *pool; public: /** * Create an initially empty autorelease pool. */ autorelease(); /** * Destroy an autorelease pool and delete member objects. */ ~autorelease(); /** * Destroy an autorelease pool and delete member objects. This may be * used to release an existing pool programmatically when desired rather * than requiring the object to fall out of scope. */ void release(void); /** * Add a linked object to the autorelease pool. * @param object to add to pool. */ void operator+=(LinkedObject *object); }; /** * This is a base class for objects that may be created in pager pools. * This is also used to create objects which can be maintained as managed * memory and returned to a pool. The linked list is used when freeing * and re-allocating the object. These objects are reference counted * so that they are returned to the pool they come from automatically * when falling out of scope. This can be used to create automatic * garbage collection pools. * @author David Sugar */ class __EXPORT PagerObject : public LinkedObject, public CountedObject { protected: friend class PagerPool; PagerPool *pager; /** * Create a pager object. This is object is constructed by a PagerPool. */ PagerObject(); /** * Reset state of object. */ void reset(void); /** * Release a pager object reference. */ void release(void); /** * Return the pager object back to it's originating pool. */ void dealloc(void); }; /** * Pager pool base class for managed memory pools. This is a helper base * class for the pager template and generally is not used by itself. If * different type pools are intended to use a common memory pager then * you will need to mixin a memory protocol object that performs * redirection such as the MemoryRedirect class. * @author David Sugar */ class __EXPORT PagerPool : public MemoryProtocol { private: LinkedObject *freelist; mutable pthread_mutex_t mutex; protected: PagerPool(); virtual ~PagerPool(); PagerObject *get(size_t size); public: /** * Return a pager object back to our free list. * @param object to return to pool. */ void put(PagerObject *object); }; class __EXPORT charmem : public CharacterProtocol { protected: char *buffer; size_t inp, out, size; bool dynamic; int _getch(void); int _putch(int code); public: charmem(char *mem, size_t size); charmem(size_t size); charmem(); virtual ~charmem(); void release(void); void set(char *mem, size_t size); void set(size_t size); inline void reset(void) {inp = out = 0;} inline void rewind(void) {inp = 0;} }; class __EXPORT chartext : public CharacterProtocol { private: char *pos; size_t max; int _putch(int code); int _getch(void); public: chartext(); chartext(char *buf); chartext(char *buf, size_t size); virtual ~chartext(); }; /** * A class to hold memory pointers referenced by string names. This is * used to form a typeless data pointer that can be associated and * referenced by string/logical name. The memory used for forming * the string names can itself be managed in reusable memory pools and * the entire structure uses it's own private pager heap. This allows * new string named pointers to be added and deleted at runtime in a thread- * safe manner. This might typically be used as a session id manager or for * symbol tables. * @author David Sugar */ class __EXPORT keyassoc : protected mempager { private: /** * Internal paged memory residing data class for name associated pointers. */ class __LOCAL keydata : public NamedObject { public: void *data; char text[8]; keydata(keyassoc *assoc, const char *id, unsigned max, unsigned bufsize); }; friend class keydata; unsigned keycount; unsigned paths; size_t keysize; NamedObject **root; LinkedObject **list; protected: /** * Allocate object stored in pager also. * @param name of object entry. * @param size of object to allocate. * @return pointer to allocated object or NULL on failure. */ void *allocate(const char *name, size_t size); public: /** * Create a key associated memory pointer table. * @param indexing size for hash map. * @param max size of a string name if names are in reusable managed memory. * @param page size of memory pager. */ keyassoc(unsigned indexing = 177, size_t max = 0, size_t page = 0); /** * Destroy association object. Release all pages back to the heap. */ ~keyassoc(); /** * Get the number of associations we have in our object. * @return number of associations stored. */ inline unsigned count(void) const {return keycount;} /** * Lookup the data pointer of a string by direct operation. * @param name to lookup. * @return pointer to data or NULL if not found. */ inline void *operator()(const char *name) {return locate(name);} /** * Purge all associations and return allocated pages to heap. */ void purge(void); /** * Lookup the data pointer by the string name given. * @param name to lookup. * @return pointer to data or NULL if not found. */ void *locate(const char *name); /** * Assign a name to a data pointer. If the name exists, it is re-assigned * with the new pointer value, otherwise it is created. * @param name to assign. * @param pointer value to assign with name. * @return false if failed because name is too long for managed table. */ bool assign(const char *name, void *pointer); /** * Create a new name in the association table and assign it's value. * @param name to create. * @param pointer value to assign with name. * @return false if already exists or name is too long for managed table. */ bool create(const char *name, void *pointer); /** * Remove a name and pointer association. If managed key names are used * then the memory allocated for the name will be re-used. * @param name to remove. * @return pointer value of the name or NULL if not found. */ void *remove(const char *name); }; template class listof : private ObjectPager { public: inline listof() : ObjectPager(sizeof(T), P) {} inline T& operator[](unsigned item) const {return (T&)ObjectPager::get(item);} inline T* operator()(unsigned item) const {return (T*)ObjectPager::get(item);} inline const T& at(unsigned item) const {return (const T&)ObjectPager::get(item);} inline T* pull(void) {return (T*)ObjectPager::pull();} inline T* pop(void) {return (T*)ObjectPager::pop();} inline operator T**() {return (T**)ObjectPager::list();} inline T** list(void) {return (T**)ObjectPager::list();} inline T* operator++(void) {T* tmp = ObjectPager::add(); if(tmp) new((caddr_t)tmp) T; return tmp;} inline T* add(const T& object) {T* tmp = ObjectPager::add(); if(tmp) new((caddr_t)tmp) T(object); return tmp;} inline T* push(const T& object) {T* tmp = ObjectPager::push(); if(tmp) new((caddr_t)tmp) T(object); return tmp;} inline listof& operator<<(const T& object) {T* tmp = ObjectPager::add(); if(tmp) new((caddr_t)tmp) T(object); return *this;} inline listof& operator>>(const T& object) {T* tmp = ObjectPager::push(); if(tmp) new((caddr_t)tmp) T(object); return *this;} }; template class mapof : private keyassoc { public: /** * Construct an associated pointer hash map based on the class template. */ inline mapof() : keyassoc(I, M, P) {} /** * Get the count of typed objects stored in our hash map. * @return typed objects in map. */ inline unsigned count(void) const {return keyassoc::count();} /** * Purge the hash map of typed objects. */ inline void purge(void) {keyassoc::purge();} /** * Lookup a typed object by name. * @param name of typed object to locate. * @return typed object pointer or NULL if not found. */ inline T *locate(const char *name) {return static_cast(keyassoc::locate(name));} inline T *operator[](const char *name) {return static_cast(keyassoc::locate(name));} /** * Reference a typed object directly by name. * @param name of typed object to locate. * @return typed object pointer or NULL if not found. */ inline T *operator()(const char *name) {return locate(name);} /** * Create mapped entry from scratch. * @param name to assign. */ inline T *map(const char *name) {T *tmp = keyassoc::allocate(name, sizeof(T)); if(tmp) new((caddr_t)tmp) T;} /** * Remove a name and typed pointer association. If managed key names are * used then the memory allocated for the name will be re-used. * @param name to remove. */ inline void unmap(const char *name) {keyassoc::remove(name);} /** * Access to pager utilization stats. This is needed because we * inherit keyassoc privately. * @return pager utilization, 0-100. */ inline unsigned utilization(void) const {return mempager::utilization();} /** * Access to number of pages allocated from heap for our associated * index pointer. This is needed because we inherit keyassoc * privately. * @return count of heap pages used. */ inline unsigned pages(void) const {return mempager::pages();} }; /** * A typed template for using a key association with typed objects. * This essentially forms a form of "smart pointer" that is a reference * to specific typed objects by symbolic name. This is commonly used as * for associated indexing of typed objects. * @author David Sugar */ template class assoc_pointer : private keyassoc { public: /** * Construct an associated pointer hash map based on the class template. */ inline assoc_pointer() : keyassoc(I, M, P) {} /** * Get the count of typed objects stored in our hash map. * @return typed objects in map. */ inline unsigned count(void) const {return keyassoc::count();} /** * Purge the hash map of typed objects. */ inline void purge(void) {keyassoc::purge();} /** * Lookup a typed object by name. * @param name of typed object to locate. * @return typed object pointer or NULL if not found. */ inline T *locate(const char *name) {return static_cast(keyassoc::locate(name));} inline T *operator[](const char *name) {return static_cast(keyassoc::locate(name));} /** * Reference a typed object directly by name. * @param name of typed object to locate. * @return typed object pointer or NULL if not found. */ inline T *operator()(const char *name) {return locate(name);} /** * Assign a name for a pointer to a typed object. If the name exists, * it is re-assigned with the new pointer value, otherwise it is created. * @param name to assign. * @param pointer of typed object to assign with name. * @return false if failed because name is too long for managed table. */ inline bool assign(char *name, T *pointer) {return keyassoc::assign(name, pointer);} /** * Create a new name in the association table and assign typed object. * @param name to create. * @param pointer of typed object to assign with name. * @return false if already exists or name is too long for managed table. */ inline bool create(char *name, T *pointer) {return keyassoc::create(name, pointer);} /** * Remove a name and typed pointer association. If managed key names are * used then the memory allocated for the name will be re-used. * @param name to remove. */ inline void remove(char *name) {keyassoc::remove(name);} /** * Access to pager utilization stats. This is needed because we * inherit keyassoc privately. * @return pager utilization, 0-100. */ inline unsigned utilization(void) const {return mempager::utilization();} /** * Access to number of pages allocated from heap for our associated * index pointer. This is needed because we inherit keyassoc * privately. * @return count of heap pages used. */ inline unsigned pages(void) const {return mempager::pages();} }; /** * Mempager managed type factory for pager pool objects. This is used to * construct a type factory that creates and manages typed objects derived * from PagerObject which can be managed through a private heap. * @author David Sugar */ template class pager : private MemoryRedirect, private PagerPool { public: /** * Construct a pager and optionally assign a private pager heap. * @param heap pager to use. If NULL, uses global heap. */ inline pager(mempager *heap = NULL) : MemoryRedirect(heap), PagerPool() {} /** * Create a managed object by casting reference. * @return pointer to typed managed pager pool object. */ inline T *operator()(void) {return new(get(sizeof(T))) T;} /** * Create a managed object by pointer reference. * @return pointer to typed managed pager pool object. */ inline T *operator*() {return new(get(sizeof(T))) T;} }; /** * A template class for a hash pager. This creates objects from a pager * pool when they do not already exist in the hash map. * @author David Sugar */ template class keypager : public mempager { private: NamedObject *idx[M]; public: /** * Create the object cache. * @param size of allocation units. */ inline keypager(size_t size) : mempager(size) {} /** * Destroy the hash pager by purging the index chains and memory pools. */ inline ~keypager() {NamedObject::purge(idx, M); mempager::purge();} /** * Find a typed object derived from NamedObject in the hash map by name. * If the object is not found, it is created from the memory pool. * @param name to search for. * @return typed object if found through map or NULL. */ inline T *get(const char *name) const { T *node = (static_cast(NamedObject::map(idx, name, M))); if(!node) { node = init(static_cast(mempager::_alloc(sizeof(T)))); node->NamedObject::add(idx, name, M); } return node; } /** * Test if a name exists in the pool. * @param name to test. * @return true if found. */ bool test(const char *name) const {return NamedObject::map(idx, name, M) != NULL;} /** * Find a typed object derived from NamedObject in the hash map by name. * If the object is not found, it is created from the pager pool. * @param name to search for. * @return typed object if found through map or NULL. */ inline T *operator[](const char *name) const {return get(name);} /** * Find first typed object in hash map to iterate. * @return first typed object or NULL if nothing in list. */ inline T *begin(void) const {return static_cast(NamedObject::skip(idx, NULL, M));} /** * Find next typed object in hash map for iteration. * @param current typed object we are referencing. * @return next iterative object or NULL if past end of map. */ inline T *next(T *current) const {return static_cast(NamedObject::skip(idx, current, M));} /** * Count the number of typed objects in our hash map. * @return count of typed objects. */ inline unsigned count(void) const {return NamedObject::count(idx, M);} /** * Convert our hash map into a linear object pointer array. The * object pointer array is created from the heap and must be deleted * when no longer used. * @return array of typed named object pointers. */ inline T **index(void) const {return NamedObject::index(idx, M);} /** * Convert our hash map into an alphabetically sorted linear object * pointer array. The object pointer array is created from the heap * and must be deleted when no longer used. * @return sorted array of typed named object pointers. */ inline T **sort(void) const {return NamedObject::sort(NamedObject::index(idx, M));} /** * Convenience typedef for iterative pointer. */ typedef linked_pointer iterator; }; /** * A convenience type for paged string lists. */ typedef StringPager stringlist_t; /** * A convenience type for paged string list items. */ typedef StringPager::member stringlistitem_t; /** * A convenience type for using DirPager directly. */ typedef DirPager dirlist_t; inline const char *shift(stringlist_t& list) {return list.pull();} inline void unshift(stringlist_t& list, const char *text) {list.push(text);} inline String str(StringPager& list, const char *prefix = NULL, const char *middle = NULL, const char *suffix = NULL) {return list.join(prefix, middle, suffix);} } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/Makefile.in0000664000175000017500000004430312557431663014440 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015 Cherokees of Idaho. # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = inc/ucommon DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(pkginclude_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/ucommon-config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(pkgincludedir)" HEADERS = $(pkginclude_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) pkgincludedir = $(includedir)/ucommon ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CHECKFLAGS = @CHECKFLAGS@ CMAKE_CURRENT_SOURCE_DIR = @CMAKE_CURRENT_SOURCE_DIR@ CMAKE_INSTALL_FULL_DATADIR = @CMAKE_INSTALL_FULL_DATADIR@ CMAKE_INSTALL_FULL_INCLUDEDIR = @CMAKE_INSTALL_FULL_INCLUDEDIR@ CMAKE_INSTALL_FULL_LIBDIR = @CMAKE_INSTALL_FULL_LIBDIR@ CMAKE_INSTALL_PREFIX = @CMAKE_INSTALL_PREFIX@ COMPAT = @COMPAT@ COMPAT_CONFIG = @COMPAT_CONFIG@ COMPAT_PC = @COMPAT_PC@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_VERSION = @LT_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MODULE_FLAGS = @MODULE_FLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OPENSSL_CFLAGS = @OPENSSL_CFLAGS@ OPENSSL_LIBS = @OPENSSL_LIBS@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PKG_SECURE_LIBS = @PKG_SECURE_LIBS@ PKG_UCOMMON_FLAGS = @PKG_UCOMMON_FLAGS@ PKG_UCOMMON_INCLUDES = @PKG_UCOMMON_INCLUDES@ PKG_UCOMMON_LIBS = @PKG_UCOMMON_LIBS@ RANLIB = @RANLIB@ SECURE = @SECURE@ SECURE_LIBS = @SECURE_LIBS@ SECURE_LOCAL = @SECURE_LOCAL@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ UCOMMON_CFGPATH = @UCOMMON_CFGPATH@ UCOMMON_FLAGS = @UCOMMON_FLAGS@ UCOMMON_INCLUDES = @UCOMMON_INCLUDES@ UCOMMON_LIBC = @UCOMMON_LIBC@ UCOMMON_LIBS = @UCOMMON_LIBS@ UCOMMON_LINKED = @UCOMMON_LINKED@ UCOMMON_LOCALE = @UCOMMON_LOCALE@ UCOMMON_PREFIX = @UCOMMON_PREFIX@ UCOMMON_VARPATH = @UCOMMON_VARPATH@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ includes = @includes@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ libs = @libs@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ MAINTAINERCLEANFILES = Makefile.in Makefile RELEASE = $(LT_VERSION) -release $(LT_RELEASE) AM_CXXFLAGS = $(UCOMMON_FLAGS) pkginclude_HEADERS = cpr.h object.h linked.h string.h counter.h vector.h \ bitmap.h timers.h socket.h access.h export.h thread.h mapped.h \ keydata.h memory.h platform.h fsys.h xml.h ucommon.h stream.h \ persist.h shell.h protocols.h atomic.h buffer.h numbers.h file.h \ datetime.h unicode.h secure.h generics.h containers.h stl.h typeref.h all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu inc/ucommon/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu inc/ucommon/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgincludeHEADERS: $(pkginclude_HEADERS) @$(NORMAL_INSTALL) @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \ done uninstall-pkgincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(HEADERS) installdirs: for dir in "$(DESTDIR)$(pkgincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgincludeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-pkgincludeHEADERS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool cscopelist-am ctags ctags-am distclean \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-pkgincludeHEADERS install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am \ uninstall-pkgincludeHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ucommon-6.4.4/inc/ucommon/Makefile.am0000664000175000017500000000177512555173716014435 00000000000000# Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015 Cherokees of Idaho. # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. MAINTAINERCLEANFILES = Makefile.in Makefile RELEASE = $(LT_VERSION) -release $(LT_RELEASE) AM_CXXFLAGS = $(UCOMMON_FLAGS) pkgincludedir = $(includedir)/ucommon pkginclude_HEADERS = cpr.h object.h linked.h string.h counter.h vector.h \ bitmap.h timers.h socket.h access.h export.h thread.h mapped.h \ keydata.h memory.h platform.h fsys.h xml.h ucommon.h stream.h \ persist.h shell.h protocols.h atomic.h buffer.h numbers.h file.h \ datetime.h unicode.h secure.h generics.h containers.h stl.h typeref.h ucommon-6.4.4/inc/ucommon/file.h0000664000175000017500000001443612544454312013457 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Adaption of C runtime FILE processing. * @file ucommon/file.h */ #ifndef _UCOMMON_FILE_H_ #define _UCOMMON_FILE_H_ #ifndef _UCOMMON_CONFIG_H_ #include #endif #ifndef _UCOMMON_PROTOCOLS_H_ #include #endif #ifndef _UCOMMON_THREAD_H_ #include #endif #ifndef _UCOMMON_STRING_H_ #include #endif #ifndef _UCOMMON_MEMORY_H_ #include #endif #ifndef _UCOMMON_FSYS_H_ #include #endif #include namespace ucommon { /** * Access standard files through character protocol. This can also be * used as an alternative means to access files that manages file pointers. * @author David Sugar */ class __EXPORT file : public CharacterProtocol { private: FILE *fp; #ifdef _MSWINDOWS_ HANDLE pid; #else pid_t pid; #endif char *tmp; int _putch(int code); int _getch(void); public: typedef ::fpos_t bookmark_t; static file cin; static file cout; static file cerr; /** * Construct a file from an existing FILE pointer. * @param file to use. */ file(FILE *file); /** * Construct an open file based on a path and mode. * @param path of file to open. * @param mode of file. * @param size of buffer, 0 = none, 1 = line mode, 2 = default */ file(const char *path, const char *mode, size_t size = 2); /** * Construct an open file based on a pipe. * @param path of file to pipe. * @param argv of executable. * @param mode of file. * @param envp to give executable. */ file(const char *path, char **argv, const char *mode, char **envp = NULL); /** * Construct an unopened file. */ file(); /** * Destroy object and close associated file. */ ~file(); /** * Test if file is opened. * @return true if opened. */ inline operator bool() const { return fp != NULL; } /** * Test if file is not opened. * @return true if not opened. */ inline bool operator !() const { return fp == NULL; } inline operator FILE *() const { return fp; } /** * Open file path. If a file is already opened, it is closed. * @param path of file to open. * @param mode of file to open. * @param size of buffering, 0 = none, 1 = line mode. */ void open(const char *path, const char *mode, size_t size = 2); /** * Open an executable path. * @param path of executable. * @param argv to pass to executable. * @param mode of pipe (only "r" and "w" are valid). */ void open(const char *path, char **argv, const char *mode, char **envp = NULL); /** * Close an open file. * @return process exit code if pipe. */ int close(void); /** * Clear error state. */ inline void clear(void) { if(fp) clearerr(fp); } /** * Check if file is good, no error or eof... * @return bool if file stream is good. */ bool good(void) const; /** * Cancel pipe and close file. * @return process exit code if pipe. */ int cancel(void); inline size_t put(const void *data, size_t size) { return fp == NULL ? 0 : fwrite(data, 1, size, fp); } inline size_t get(void *data, size_t size) { return fp == NULL ? 0 : fread(data, 1, size, fp); } inline int put(char value) { return fp == NULL ? EOF : fputc(value, fp); } inline int get(void) { return fp == NULL ? EOF : fgetc(fp); } inline int push(char value) { return fp == NULL ? EOF : ungetc(value, fp); } inline int puts(const char *data) { return fp == NULL ? 0 : fputs(data, fp); } inline char *gets(char *data, size_t size) { return fp == NULL ? NULL : fgets(data, (socksize_t)size, fp); } template inline size_t read(T* data, size_t count) { return fp == NULL ? 0 : fread(data, sizeof(T), count, fp); } template inline size_t write(const T* data, size_t count) { return fp == NULL ? 0 : fwrite(data, sizeof(T), count, fp); } template inline size_t read(T& data) { return fp == NULL ? 0 : fread(data, sizeof(T), 1, fp); } template inline size_t write(const T& data) { return fp == NULL ? 0 : fwrite(data, sizeof(T), 1, fp); } inline void get(bookmark_t& pos) { if(fp) fsetpos(fp, &pos); } inline void set(bookmark_t& pos) { if(fp) fgetpos(fp, &pos); } int err(void) const; bool eof(void) const; template inline void offset(long pos) { if(fp) fseek(fp, sizeof(const T) * pos, SEEK_CUR); } inline void seek(long offset) { if(fp) fseek(fp, offset, SEEK_SET); } inline void move(long offset) { if(fp) fseek(fp, offset, SEEK_CUR); } inline void append(void) { if (fp) fseek(fp, 0l, SEEK_END); } inline void rewind(void) { if(fp) ::rewind(fp); } inline void flush(void) { if(fp) ::fflush(fp); } size_t printf(const char *format, ...) __PRINTF(2, 3); size_t scanf(const char *format, ...) __SCANF(2, 3); bool is_tty(void) const; }; /** * Convience type for file. */ typedef file file_t; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/shell.h0000664000175000017500000006251112504226724013644 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Generic shell parsing and application services. * @file ucommon/shell.h */ /** * Example of shell parsing. * @example shell.cpp */ #ifndef _UCOMMON_STRING_H_ #include #endif #ifndef _UCOMMON_MEMORY_H_ #include #endif #ifndef _UCOMMON_BUFFER_H_ #include #endif #ifndef _UCOMMON_SHELL_H_ #define _UCOMMON_SHELL_H_ #ifdef _MSWINDOWS_ #define INVALID_PID_VALUE INVALID_HANDLE_VALUE #else #define INVALID_PID_VALUE -1 #endif #ifdef ERR #undef ERR #endif namespace ucommon { /** * A utility class for generic shell operations. This includes utilities * to parse and expand arguments, and to call system shell services. This * also includes a common shell class to parse and process command line * arguments which are managed through a local heap. * @author David Sugar */ class __EXPORT shell : public mempager { private: char **_argv; unsigned _argc; char *_argv0; char *_exedir; LinkedObject *_syms; class __LOCAL args : public OrderedObject { public: char *item; }; class __LOCAL syms : public LinkedObject { public: const char *name; const char *value; }; /** * Collapse argument list. This is used internally to collapse args * that are created in a pool heap when they need to be turned into * an argv style array. */ void collapse(LinkedObject *first); /** * Set argv0. This gets the simple filename of argv[0]. */ void set0(char *argv0); public: /** * Error table index. */ typedef enum {NOARGS = 0, NOARGUMENT, INVARGUMENT, BADOPTION, OPTION_USED, BAD_VALUE, NUMERIC_SET} errmsg_t; /** * Type of error logging we are using. */ typedef enum {NONE = 0, CONSOLE_LOG, USER_LOG, SYSTEM_LOG, SECURITY_LOG} logmode_t; /** * Level of error logging. */ typedef enum {FAIL = 0, ERR, WARN, NOTIFY, INFO, DEBUG0} loglevel_t; /** * Numeric mode of parser. */ typedef enum {NO_NUMERIC, NUMERIC_PLUS, NUMERIC_DASH, NUMERIC_ALL} numeric_t; /** * Path types to retrieve. */ typedef enum { PROGRAM_CONFIG, SERVICE_CONFIG, USER_DEFAULTS, SERVICE_CONTROL, USER_HOME = USER_DEFAULTS + 3, SERVICE_DATA, SYSTEM_TEMP, USER_CACHE, SERVICE_CACHE, USER_DATA, USER_CONFIG, SYSTEM_CFG, SYSTEM_ETC, SYSTEM_VAR, SYSTEM_PREFIX, SYSTEM_SHARE, PROGRAM_PLUGINS, PROGRAM_TEMP} path_t; /** * Log process handler. */ typedef bool (*logproc_t)(loglevel_t level, const char *text); /** * Main handler. */ typedef cpr_service_t mainproc_t; /** * Exit handler. */ typedef void (*exitproc_t)(void); #ifdef _MSWINDOWS_ typedef HANDLE pid_t; #else /** * Standard type of process id for shell class. */ typedef int pid_t; #endif /** * This can be used to get internationalized error messages. The internal * text for shell parser errors are passed through here. * @param id of error message to use. * @return published text of error message. */ static const char *errmsg(errmsg_t id); /** * This is used to set internationalized error messages for the shell * parser. * @param id of message to set. * @param text for error message. */ static void errmsg(errmsg_t id, const char *text); /** * A class to redefine error messages. This can be used as a statically * initialized object to remap error messages for easier * internationalization. * @author David Sugar */ class __EXPORT errormap { public: inline errormap(errmsg_t id, const char *text) {shell::errmsg(id, text);} }; /** * A base class used to create parsable shell options. The virtual * is invoked when the shell option is detected. Both short and long * forms of argument parsing are supported. An instance of a derived * class is created to perform the argument parsing. * @author David Sugar */ class __EXPORT Option : public LinkedObject { public: char short_option; const char *long_option; const char *uses_option; const char *help_string; bool trigger_option; /** * Construct a shell parser option. * @param short_option for single character code. * @param long_option for extended string. * @param value_type if -x value or -long=yyy. * @param help string, future use. */ Option(char short_option = 0, const char *long_option = NULL, const char *value_type = NULL, const char *help = NULL); virtual ~Option(); static LinkedObject *first(void); /** * Disable a option. Might happen if argv0 name suggests an * option is no longer actively needed. */ void disable(void); /** * Used to send option into derived receiver. * @param value option that was received. * @return NULL or error string to use. */ virtual const char *assign(const char *value) = 0; static void reset(void); }; /** * Flag option for shell parsing. This offers a quick-use class * to parse a shell flag, along with a counter for how many times * the flag was selected. The counter might be used for -vvvv style * verbose options, for example. * @author David Sugar */ class __EXPORT flagopt : public Option { private: unsigned counter; bool single; virtual const char *assign(const char *value); public: flagopt(char short_option, const char *long_option = NULL, const char *help = NULL, bool single_use = true); inline operator bool() const {return counter > 0;} inline bool operator!() const {return counter == 0;} inline operator unsigned() const {return counter;} inline unsigned operator*() const {return counter;} inline void set(unsigned value = 1) {counter = value;} }; /** * Grouping option. This is used to create a grouping entry in * the shell::help() listing. * @author David Sugar */ class __EXPORT groupopt : public Option { private: virtual const char *assign(const char *value); public: groupopt(const char *help); }; /** * Text option for shell parsing. This offers a quick-use class * to parse a shell flag, along with a numeric text that may be * saved and a use counter, as multiple invocations is an error. * @author David Sugar */ class __EXPORT stringopt : public Option { private: bool used; protected: const char *text; virtual const char *assign(const char *value); public: stringopt(char short_option, const char *long_option = NULL, const char *help = NULL, const char *type = "text", const char *def_text = NULL); inline void set(const char *string) {text = string;} inline operator bool() const {return used;} inline bool operator!() const {return !used;} inline operator const char *() const {return text;} inline const char *operator*() const {return text;} }; /** * Character option for shell parsing. This offers a quick-use class * to parse a shell flag, along with a character code that may be * saved. Multiple invocations is an error. * @author David Sugar */ class __EXPORT charopt : public Option { private: bool used; protected: char code; virtual const char *assign(const char *value); public: charopt(char short_option, const char *long_option = NULL, const char *help = NULL, const char *type = "char", char default_code = ' '); inline void set(char value) {code = value;} inline operator bool() const {return used;} inline bool operator!() const {return !used;} inline operator char() const {return code;} inline char operator*() const {return code;} }; /** * Numeric option for shell parsing. This offers a quick-use class * to parse a shell flag, along with a numeric value that may be * saved and a use counter, as multiple invocations is an error. * @author David Sugar */ class __EXPORT numericopt : public Option { private: bool used; protected: long number; virtual const char *assign(const char *value); public: numericopt(char short_option, const char *long_option = NULL, const char *help = NULL, const char *type = "numeric", long def_value = 0); inline void set(long value) {number = value;} inline operator bool() const {return used;} inline bool operator!() const {return !used;} inline operator long() const {return number;} inline long operator*() const {return number;} }; /** * Counter option for shell parsing. This offers a quick-use class * to parse a shell flag, along with a numeric value that may be * saved and a use counter, as multiple invocations is an error. Unlike * numeric options, the short mode flag is a trigger option, and each * use of the short flag is considered a counter increment. * @author David Sugar */ class __EXPORT counteropt : public Option { private: bool used; protected: long number; virtual const char *assign(const char *value); public: counteropt(char short_option, const char *long_option = NULL, const char *help = NULL, const char *type = "numeric", long def_value = 0); inline void set(long value) {number = value;} inline operator bool() const {return used;} inline bool operator!() const {return !used;} inline operator long() const {return number;} inline long operator*() const {return number;} }; /** * Construct a shell argument list by parsing a simple command string. * This separates a string into a list of command line arguments which * can be used with exec functions. * @param string to parse. * @param pagesize for local heap. */ shell(const char *string, size_t pagesize = 0); /** * Construct a shell argument list from existing arguments. This * copies and on some platforms expands the argument list originally * passed to main. * @param argc from main. * @param argv from main. * @param pagesize for local heap. */ shell(int argc, char **argv, size_t pagesize = 0); /** * Construct an empty shell parser argument list. * @param pagesize for local heap. */ shell(size_t pagesize = 0); static void setNumeric(numeric_t); static long getNumeric(void); /** * Display shell options. */ static void help(void); /** * A shell system call. This uses the native system shell to invoke the * command. * @param command string.. * @param env array to optionally use. * @return error code of child process. */ static int system(const char *command, const char **env = NULL); /** * A shell system call that can be issued using a formatted string. This * uses the native system shell to invoke the command. * @param format of/command string. * @return error code of child process. */ static int systemf(const char *format, ...) __PRINTF(1,2); /** * Set relative prefix. Used for OS/X relocatable applications. * @param argv0 path of executable. */ static void relocate(const char *argv0); /** * Get a system path. This is used to get directories for application * specific data stores and default paths for config keys. * @param id of path to return. * @return path string or emptry string if not supported. */ static String path(path_t id); /** * Get the system login id. * @return login id. */ static String userid(void); /** * Get a merged path. If the path requested is a full path, then * the prefix is ignored. * @param id of prefix. * @param directory path to merge with prefix. */ static String path(path_t id, const char *directory); /** * Join a prefix with a path. * @param prefix to merge with. * @param directory or file path to merge. */ static String path(String& prefix, const char *directory); /** * Bind application to text domain for internationalization. This * is useful if the argv0 argument can vary because of a symlinked * executable. This is the name of the .po/.mo message files for * your application. If bind is not called before shell processing, * then the argv0 is used as the bind name. Bind can be called * multiple times to change the default message catalog name of the * application, and this usage may be needed for plugins, though it's * generally recommended to use only once, and at the start of main(). * @param name of text domain for the application. */ static void bind(const char *name); /** * Rebind is used to change the text domain. This may be needed in * applications which have separately built plugins that have thier * own message catalogs. Normally the plugin would call bind itself * at initialization, and then use rebind to select either the * application's domain, or the plugins. On systems without * internationalization, this has no effect. * @param name of text domain of plugin or NULL to restore application. */ static void rebind(const char *name = NULL); /** * Parse a string as a series of arguments for use in exec calls. * @param string to parse. * @return argument array. */ char **parse(const char *string); /** * Parse the command line arguments using the option table. File * arguments will be expanded for wildcards on some platforms. * The argv will be set to the first file argument after all options * are parsed. * @param argc from main. * @param argv from main. */ void parse(int argc, char **argv); /** * Get an environment variable. This creates a local copy of the * variable in pager memory. * @param name of symbol. * @param value of symbol if not found. * @return value of symbol. */ const char *env(const char *name, const char *value = NULL); inline const char *getenv(const char *name, const char *value = NULL) {return env(name, value);} /** * Get a local symbol. This uses getenv if no local symbol is found. * @param name of symbol. * @param value of symbol if not found. * @return value of symbol. */ const char *get(const char *name, const char *value = NULL); inline const char *getsym(const char *name, const char *value = NULL) {return get(name, value);} /** * Set a local symbol. * @param name of symbol to set. * @param value of symbol to set. */ void set(const char *name, const char *value); inline void setsym(const char *name, const char *value) {return set(name, value);} /** * Test if symbol exists. * @param name of symbol. * @return true if found. */ bool is_sym(const char *name) const; /** * Parse and extract the argv0 filename alone. * @param argv from main. * @return argv0 simple path name. */ char *getargv0(char **argv); /** * Get the argument list by parsing options, and return the remaining * file arguments. This is used by parse, and can be fed by main by * posting ++argv. * @param argv of first option. * @return argv of non-option file list. */ char **getargv(char **argv); /** * Execute front-end like gdb based on stripped first argument. * @param argv0 of our executable. * @param argv to pass to child. * @param list of arguments to execute in front of argv. */ void restart(char *argv0, char **argv, char **list); /** * Get program name (argv0). */ inline const char *argv0() const {return _argv0;} /** * Get the exec directory. */ inline const char *execdir() const {return _exedir;} /** * Print error message and continue. * @param format string to use. */ static void error(const char *format, ...) __PRINTF(1, 2); /** * Print error message and exit. Ignored if exitcode == 0. * @param exitcode to return to parent process. * @param format string to use. */ static void errexit(int exitcode, const char *format = NULL, ...) __PRINTF(2, 3); /** * Convert condition to exit code if true. * @param test condition. * @param exitcode to use if true. */ static inline int condition(bool test, int exitcode) { return (test) ? exitcode : 0;} /** * Print a debug message by debug level. * @param level of debug message. * @param format string to use. */ static void debug(unsigned level, const char *format, ...) __PRINTF(2, 3); /** * Print generic error message at specific error level. * @param level of error condition. * @param format string to use. */ static void log(loglevel_t level, const char *format, ...) __PRINTF(2, 3); /** * Print security error message at specific error level. * @param level of error condition. * @param format string to use. */ static void security(loglevel_t level, const char *format, ...) __PRINTF(2, 3); /** * Set logging level and state. * @param name of logging entity. * @param level of error conditions to log. * @param mode of logging. * @param handler for log messages. */ static void log(const char *name, loglevel_t level = ERR, logmode_t mode = USER_LOG, logproc_t handler = (logproc_t)NULL); /** * Print to standard output. * @param format string to use. */ static size_t printf(const char *format, ...) __PRINTF(1, 2); static size_t readln(char *address, size_t size); static size_t writes(const char *string); static size_t read(String& string); inline static size_t write(String& string) {return writes(string.c_str());} /** * Get saved internal argc count for items. This may be items that * remain after shell expansion and options have been parsed. * @return count of remaining arguments. */ inline unsigned argc(void) const {return _argc;} /** * Get saved internal argv count for items in this shell object. This * may be filename items only that remain after shell expansion and * options that have been parsed. * @return list of remaining arguments. */ inline char **argv(void) const {return _argv;} /** * Return parser argv element. * @param offset into array. * @return argument string. */ inline const char *operator[](unsigned offset) {return _argv[offset];} static void exiting(exitproc_t); /** * Detach current process to daemon for service entry. */ void detach(mainproc_t mainentry = (mainproc_t)NULL); /** * Make current process restartable. */ void restart(void); /** * Spawn a child process. This creates a new child process. If * the executable path is a pure filename, then the $PATH will be * used to find it. The argv array may be created from a string * with the shell string parser. * @param path to executable. * @param argv list of command arguments for the child process. * @param env of child process can be explicitly set. * @param stdio handles for stdin, stdout, and stderr. * @return process id of child or INVALID_PID_VALUE if fails. */ static shell::pid_t spawn(const char *path, char **argv, char **env = NULL, fd_t *stdio = NULL); /** * Set priority level and enable priority scheduler. This activates the * realtime priority scheduler when a priority > 0 is requested for the * process, assuming scheduler support exists and the process is * sufficiently privileged. Negative priorities are essentially the * same as nice. * @param pri level for process. */ static void priority(int pri = 1); /** * Create a detached process. This creates a new child process that * is completely detached from the current process. * @param path to executable. * @param argv list of command arguments for the child process. * @param env of child process can be explicitly set. * @param stdio handles for stdin, stdout, and stderr. * @return 0 if success, -1 on error. */ static int detach(const char *path, char **argv, char **env = NULL, fd_t *stdio = NULL); /** * Detach and release from parent process with exit code. * @param exit_code to send to parent process. */ static void release(int exit_code = 0); /** * Wait for a child process to terminate. This operation blocks. * @param pid of process to wait for. * @return exit code of process, -1 if fails or pid is invalid. */ static int wait(shell::pid_t pid); /** * Cancel a child process. * @param pid of child process to cancel. * @return exit code of process, -1 if fails or pid is invalid. */ static int cancel(shell::pid_t pid); /** * Return argc count. * @return argc count. */ inline unsigned operator()(void) const {return _argc;} /** * Text translation and localization. This function does nothing but * return the original string if no internationalization support is * available. If internationalization support exists, then it may * return a substituted translation based on the current locale. This * offers a single function that can be safely used either when * internationalization support is present, or it is absent, eliminating * the need for the application to be coded differently based on * awareness of support. * @param string to translate. * @return translation if found or original text. */ static const char *text(const char *string); /** * Plural text translation and localization. This does nothing but * return single or plural forms if no internationalization is * enabled. Else it uses ngettext(). * @param singular string to translate. * @param plural string to translate. * @param count of objects. * @return string to use. */ static const char *texts(const char *singular, const char *plural, unsigned long count); /** * Get argc count for an existing array. * @param argv to count items in. * @return argc count of array. */ static unsigned count(char **argv); #ifdef _MSWINDOWS_ static inline fd_t input(void) {return GetStdHandle(STD_INPUT_HANDLE);} static inline fd_t output(void) {return GetStdHandle(STD_OUTPUT_HANDLE);} static inline fd_t error(void) {return GetStdHandle(STD_ERROR_HANDLE);} #else static inline fd_t input(void) {return 0;} static inline fd_t output(void) {return 1;} static inline fd_t error(void) {return 2;} #endif static int inkey(const char *prompt = NULL); static char *getpass(const char *prompt, char *buffer, size_t size); static char *getline(const char *prompt, char *buffer, size_t size); }; /** * Convenience type to manage and pass shell objects. */ typedef shell shell_t; /** * Abusive compilers... */ #undef _TEXT #undef _STR #define _STR(x) (const char *)(x) /** * Invoke translation lookup if available. This can also be used to * mark text constants that need to be translated. It should not be * used with pointer variables, which should instead call shell::text * directly. The primary purpose is to allow extraction of text to * be internationalized with xgettext "--keyword=_TEXT:1". */ inline const char *_TEXT(const char *s) {return shell::text(s);} } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/socket.h0000664000175000017500000020044012531603640014014 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Common socket class and address manipulation. * This offers a common socket base class that exposes socket functionality * based on what the target platform supports. Support for multicast, IPV6 * addressing, and manipulation of cidr policies are all supported here. * @file ucommon/socket.h */ #ifndef _UCOMMON_SOCKET_H_ #define _UCOMMON_SOCKET_H_ #ifndef _UCOMMON_TIMERS_H_ #include #endif #ifndef _UCOMMON_LINKED_H_ #include #endif #ifndef _UCOMMON_STRING_H_ #include #endif extern "C" { struct addrinfo; } #ifdef _MSWINDOWS_ #define SHUT_RDWR SD_BOTH #define SHUT_WR SD_SEND #define SHUT_RD SD_RECV typedef uint16_t in_port_t; typedef uint32_t in_addr_t; #else #include #include #include #include #include #endif #if defined(__ANDROID__) typedef uint16_t in_port_t; #endif #include #include #ifndef IPTOS_LOWDELAY #define IPTOS_LOWDELAY 0x10 #define IPTOS_THROUGHPUT 0x08 #define IPTOS_RELIABILITY 0x04 #define IPTOS_MINCOST 0x02 #endif #ifdef AF_UNSPEC #define DEFAULT_FAMILY AF_UNSPEC #else #define DEFAULT_FAMILY AF_INET #endif struct sockaddr_internet; typedef struct sockaddr *sockaddr_t; typedef struct sockaddr sockaddr_struct; // older gcc needs...? /** * An object that holds ipv4 or ipv6 binary encoded host addresses. */ typedef struct hostaddr_internet { union { struct in_addr ipv4; #ifdef AF_INET6 struct in6_addr ipv6; #endif }; } inethostaddr_t; #if defined(AF_INET6) || defined(__CYGWIN__) /** * An object that can hold a ipv4 or ipv6 socket address. This would be * used for tcpip socket connections. We do not use sockaddr_storage * because it is not present in pre ipv6 stacks, and because the storage * size also includes the size of the path of a unix domain socket on * posix systems. */ typedef struct sockaddr_internet { union { #ifdef AF_INET6 struct sockaddr_in6 ipv6; #endif struct sockaddr_in ipv4; struct sockaddr address; }; } inetsockaddr_t; #else typedef struct sockaddr_internet { union { struct sockaddr_in ipv4; struct sockaddr address; }; } inetsockaddr_t; struct sockaddr_storage { #ifdef AF_UNIX char sa_data[128]; #else char sa_data[sizeof(struct sockaddr_in)]; #endif }; #endif #ifndef SOCK_DCCP #define SOCK_DCCP 6 #endif #ifndef IPPROTO_DCCP #define IPPROTO_DCCP 23 #endif #ifndef SOL_DCCP #define SOL_DCCP 269 #endif #define DCCP_SOCKOPT_AVAILABLE_CCIDS 12 #define DCCP_SOCKOPT_CCID 13 #define DCCP_SOCKOPT_TX_CCID 14 #define DCCP_SOCKOPT_RX_CCID 15 namespace ucommon { /** * A class to hold internet segment routing rules. This class can be used * to provide a stand-alone representation of a cidr block of internet * addresses or chained together into some form of access control list. The * cidr class can hold segments for both IPV4 and IPV6 addresses. The class * accepts cidr's defined as C strings, typically in the form of address/bits * or address/submask. These routines auto-detect ipv4 and ipv6 addresses. * @author David Sugar */ class __EXPORT cidr : public LinkedObject { protected: int Family; inethostaddr_t Netmask, Network; char Name[16]; unsigned mask(const char *cp) const; inethostaddr_t broadcast(void) const; unsigned mask(void) const; public: /** * A convenience type for using a pointer to a linked list as a policy chain. */ typedef LinkedObject policy; /** * Create an uninitialized cidr. */ cidr(); /** * Create an unlinked cidr from a string. The string is typically in * the form base-host-address/range, where range might be a bit count * or a network mask. * @param string for cidr block. */ cidr(const char *string); /** * Create an unnamed cidr entry on a specified policy chain. * @param policy chain to link cidr to. * @param string for cidr block. */ cidr(policy **policy, const char *string); /** * Create a named cidr entry on a specified policy chain. * @param policy chain to link cidr to. * @param string for cidr block. * @param name of this policy object. */ cidr(policy **policy, const char *string, const char *name); /** * Construct a copy of an existing cidr. * @param existing cidr we copy from. */ cidr(const cidr& existing); /** * Find the smallest cidr entry in a list that matches the socket address. * @param policy chain to search. * @param address to search for. * @return smallest cidr or NULL if none match. */ static const cidr *find(const policy *policy, const struct sockaddr *address); /** * Get the largest container cidr entry in a list that matches the * socket address. * @param policy chain to search. * @param address to search for. * @return largest cidr or NULL if none match. */ static const cidr *container(const policy *policy, const struct sockaddr *address); /** * Get the saved name of our cidr. This is typically used with find * when the same policy name might be associated with multiple non- * overlapping cidr blocks. A typical use might to have a cidr * block like 127/8 named "localdomain", as well as the ipv6 "::1". * @return name of cidr. */ inline const char *getName(void) const {return Name;} /** * Get the address family of our cidr block object. * @return family of our cidr. */ inline int getFamily(void) const {return Family;} /** * Get the network host base address of our cidr block. * @return binary network host address. */ inline inethostaddr_t getNetwork(void) const {return Network;} /** * Get the effective network mask for our cidr block. * @return binary network mask for our cidr. */ inline inethostaddr_t getNetmask(void) const {return Netmask;} /** * Get the broadcast host address represented by our cidr. * @return binary broadcast host address. */ inline inethostaddr_t getBroadcast(void) const {return broadcast();} /** * Get the number of bits in the cidr bitmask. * @return bit mask of cidr. */ inline unsigned getMask(void) const {return mask();} /** * Set our cidr to a string address. Replaces prior value. * @param string to set for cidr. */ void set(const char *string); /** * Test if a given socket address falls within this cidr. * @param address of socket to test. * @return true if address is within cidr. */ bool is_member(const struct sockaddr *address) const; /** * Test if a given socket address falls within this cidr. * @param address of socket to test. * @return true if address is within cidr. */ inline bool operator==(const struct sockaddr *address) const {return is_member(address);} /** * Test if a given socket address falls outside this cidr. * @param address of socket to test. * @return true if address is outside cidr. */ inline bool operator!=(const struct sockaddr *address) const {return !is_member(address);} }; /** * A generic socket base class. This class can be used directly or as a * base class for building network protocol stacks. This common base tries * to handle UDP and TCP sockets, as well as support multicast, IPV4/IPV6 * addressing, and additional addressing domains (such as Unix domain sockets). * @author David Sugar */ class __EXPORT Socket { protected: socket_t so; int ioerr; timeout_t iowait; public: /** * Get an address list directly. This is used internally by some derived * socket types when generic address lists would be invalid. * @param host name in the form address or "address:port" * @param service id or port to use if not specified in host string. * @param type of service to get. * @param protocol of service to get. */ static struct addrinfo *query(const char *host, const char *service, int type = SOCK_STREAM, int protocol = 0); /** * Release an address list directly. This is used internally by some * derived socket types which do not use generic address lists. * @param list of addresses. */ static void release(struct addrinfo *list); /** * A generic socket address class. This class uses the addrinfo list * to store socket multiple addresses in a protocol and family * independent manner. Hence, this address class can be used for ipv4 * and ipv6 sockets, for assigning connections to multiple hosts, etc. * The address class will call the resolver when passed host names. * @author David Sugar */ class __EXPORT address { protected: struct addrinfo *list; public: /** * Construct a socket address. This is used to get an address to * bind a socket interface to. The address can be specified as the * ip address of the interface or as a "hostname". If a hostname * is used, then family should be specified for clarity. * @param family of socket address. Needed when host names are used. * @param address or hostname. * @param type of socket (stream, dgram, etc). * @param protocol number of socket. */ address(int family, const char *address, int type = SOCK_STREAM, int protocol = 0); /** * Construct a socket address for an existing socket. This can be the * name of a host or to perform a lookup in a domain for a service. * Family can be used to restrict the set of results returned, however * since things like connecto() already filter by family and create * will use family from the addrinfo, in most cases AF_UNSPEC can be * used. This may be depreciated in favor of the constructor that * matches a set() method. * @param family of hosts to filter by or AF_UNSPEC. * @param hostname or ip address. The socket family is used for hostnames. * @param service port or name we are referencing or NULL. */ address(int family, const char *hostname, const char *service = NULL); /** * Construct a socket address list for a service. * @param host address for service. * @param service name or port number. * @param type of service, stream, dgram, etc. */ address(const char *host, const char *service, int type = SOCK_STREAM); /** * Construct a socket address from host and service. This is primarily * used to construct a list of potential service connections by pure * port numbers or for host lookup only. * @param hostname or address to use. * @param service port or 0. */ address(const char *hostname, in_port_t port = 0); /** * Construct a socket address from an IPv4 address and a port number. */ address(const in_addr& address, in_port_t port = 0); /** * Construct a socket address from an IPv6 address and a port number. */ address(const in6_addr& address, in_port_t port = 0); /** * Construct a socket address from a sockaddr object. */ address(const sockaddr& address) : list(NULL) {insert(address);} /** * Construct a socket address from an addrinfo structure. */ address(const addrinfo* address) : list(NULL) {insert(address);} /** * Construct an empty address. */ address(); /** * Copy constructor. * @param reference to object to copy from. */ address(const address& reference); /** * Assignment operator. * @param reference to object to copy from. */ address& operator=(const address& rhs); /** * Destroy address. Deallocate addrinfo structure. */ ~address(); /** * Compare two address lists. * @return true if the two lists are the same (same addresses * in the same order). */ bool operator==(const address& other) const; inline bool operator!=(const address& other) const {return !(*this==other);} inline bool equals(const address& other) const {return *this == other;} /** * Get the first socket address in our address list. * @return first socket address or NULL if none. */ struct sockaddr *get(void) const; inline struct sockaddr *getAddr(void) const {return get();} inline struct sockaddr *operator()(void) const {return get();} /** * Get the first socket address by casted reference. * @return first socket address we resolved or NULL if none. */ inline operator struct sockaddr *() const {return get();} /** * Get the first socket address of specified family from our list. * @param family to seek. * @return first socket address of family or NULL if none. */ struct sockaddr *get(int family) const; inline struct sockaddr *operator()(int family) const {return get(family);} inline operator struct sockaddr_in *() const {return (struct sockaddr_in *)get(AF_INET);} #ifdef AF_INET6 inline operator struct sockaddr_in6 *() const {return (struct sockaddr_in6 *)get(AF_INET6);} #endif /** * Get the family of the first member in a list of services. * @return family of first socket address or 0 if none. */ int family(void) const; /** * Get the address size of the first address. * @return size in bytes of first socket address or 0 if none. */ inline size_t getLength(void) const {return len(get());} /** * Get the port of the first address . * @return port of first socket address or 0 if none. */ inline in_port_t getPort(void) const {return getPort(get());} /** * Set the port of all addresses in the list. * @param port the port to set. */ void setPort(in_port_t port); /** * Returns a copy of this address list with * the specified port set. */ address withPort(in_port_t port) const; /** * Find a specific socket address in our address list. * @return matching address from list or NULL if not found. */ struct sockaddr *find(const struct sockaddr *addr) const; /** * Get the full socket address list from the object. * @return addrinfo list we resolved or NULL if none. */ inline struct addrinfo *getList(void) const {return list;} /** * Get the full socket address list by casted reference. * @return addrinfo list we resolved or NULL if none. */ inline operator struct addrinfo *() const {return list;} /** * Return the full socket address list by pointer reference. * @return addrinfo list we resolved or NULL if none. */ inline struct addrinfo *operator*() const {return list;} /** * Print the first socket address as a human-readable string to the * provided buffer and returns the printed string length. * @param src Address to print. * @param dst Destination buffer to print the socket address on. * @param dst_sz Size of the provided buffer. Strongly recommended to be * at least INET6_ADDRSTRLEN (or INET_ADDRSTRLEN if compiled without IPv6). * @param port If true, print port number with address. * If true, ipv6_brackets will also be forced to true. * @param ipv6_brackets If true, force printing IPv6 brackets. Ignored if address is an IPv4. * @return length (in bytes) of the printed string, excluding trailing zero. */ size_t print(char* dst, size_t dst_sz, bool port=false, bool force_brackets=false) const {return print(get(), dst, dst_sz, port, force_brackets);} /** * Test if the address list is valid. * @return true if we have an address list. */ inline operator bool() const {return list != NULL;} /** * Test if we have no address list. * @return true if we have no address list. */ inline bool operator!() const {return list == NULL;} /** * Test if the first socket address is ADDR_ANY: * 0.0.0.0 or ::0 * @return true if the address is one of the above. */ inline bool isAny() const {return isAny(get());} /** * Clear the address list and set the first address to be the * ADDR_ANY of the current family, or of the specified family * (if set). * @param family: address family to set. */ void setAny(int family = AF_UNSPEC); /** * Test if the first socket address is ADDR_LOOPBACK: * 127.0.0.1 or ::1 * @return true if the address is one of the above. */ inline bool isLoopback() const {return isLoopback(get());} /** * Clear the address list and set the first address to be the * ADDR_LOOPBACK of the current family, or of the specified family * (if set). * @param family: address family to set. */ void setLoopback(int family = AF_UNSPEC); /** * Clear current object. */ void clear(void); /** * Set the host addresses to form a new list. * @param hostname or address to resolve. * @param service name or port number, or NULL if not used. * @param type of socket (stream or dgram) to filter list by. */ void set(const char *hostname, const char *service = NULL, int type = SOCK_STREAM); /** * Append additional host addresses to our list. * @param hostname or address to resolve. * @param service name or port number, or NULL if not used. * @param type of socket (stream or dgram). */ void add(const char *hostname, const char *service = NULL, int type = SOCK_STREAM); /** * Set an entry for host binding. * @param family of socket address. Needed when hostnames are used. * @param address or hostname. * @param type of socket (stream, dgram, etc). * @param protocol number of socket. */ void set(int family, const char *address, int type = SOCK_STREAM, int protocol = 0); /** * Add an individual socket address to our address list. * @param address to add. */ void add(sockaddr *address); /** * Insert unique members from another socket address list to ours. * @param address list to insert into list. * @return count of addresses added. */ unsigned insert(const struct addrinfo *address); /** * Remove members from another socket address list from ours. * @param address list to remove from list. * @return count of addresses removed. */ unsigned remove(const struct addrinfo *address); /** * Remove an individual socket address from our address list. * @param address to remove. * @return true if found and removed, false if not found. */ bool remove(const struct sockaddr *address); /** * Insert an individual socket address to our address list only if * unique. * @param address to insert into list. * @return true if inserted, false if duplicate. */ bool insert(const struct sockaddr *address); inline bool insert(const struct sockaddr& address) {return insert(&address);} /** * Copy an existing addrinfo into our object. This is also used * to support the copy constructor. * @param address list to copy from. */ void copy(const struct addrinfo *address); /** * Set an individual socket address for our address list. * @param address to add. */ void set(struct sockaddr *address); /** * Set a socket address from host and service. * @param hostname or address to use. * @param service port or 0. */ void set(const char *hostname, in_port_t service = 0); /** * Returns the size of the socket address according to the family. * @return size in bytes of the valid part of the socket address. */ static size_t getLength(const struct sockaddr *address) {return len(address);} /** * Returns the port of the socket address. * @return port associated to the socket address. */ static in_port_t getPort(const struct sockaddr *address); /** * Set the port of the socket address. * @param address to edit. * @param port to associate to the socket address. */ static void setPort(struct sockaddr *address, in_port_t port); /** * Test if the socket address is ADDR_ANY: * 0.0.0.0 or ::0 * @return true if the address is one of the above. */ static bool isAny(const struct sockaddr *address); /** * Set the socket address to ADDR_ANY: * 0.0.0.0 or ::0 */ static void setAny(struct sockaddr *sa); /** * Get a ADDR_ANY socket address of the given family. */ static sockaddr_storage any(int family); /** * Test if the socket address is ADDR_LOOPBACK: * 127.0.0.1 or ::1 * @return true if the address is one of the above. */ static bool isLoopback(const struct sockaddr *address); /** * Set the socket address to ADDR_LOOPBACK: * 127.0.0.1 or ::1 * depending on the family of the pointed address. */ static void setLoopback(struct sockaddr *sa); /** * Get a ADDR_LOOPBACK socket address of the given family. */ static sockaddr_storage loopback(int family); /** * Duplicate a socket address. * @param address to duplicate. * @return duplicate address object. */ static struct sockaddr *dup(struct sockaddr *address); /** * Convert address object into ipv4 address. * @param address to convert. * @return new ipv4 address or NULL if not ipv4. */ static struct sockaddr_in *ipv4(struct sockaddr *address); #ifdef AF_INET6 /** * Convert address object into ipv6 address. * @param address to convert. * @return new ipv6 address or NULL if not ipv6. */ static struct sockaddr_in6 *ipv6(struct sockaddr *address); #endif /** * Print socket address as a human-readable string to the provided * buffer and returns the printed string length. * @param src Address to print. * @param dst Destination buffer to print the socket address on. * @param dst_sz Size of the provided buffer. Strongly recommended to be * at least INET6_ADDRSTRLEN (or INET_ADDRSTRLEN if compiled without IPv6). * @param port If true, print port number with address. * If true, ipv6_brackets will also be forced to true. * @param ipv6_brackets If true, force printing IPv6 brackets. Ignored if address is an IPv4. * @return length (in bytes) of the printed string, excluding trailing zero. */ static size_t print(const struct sockaddr *src, char* dst, size_t dst_sz, bool port=false, bool ipv6_brackets=false); }; friend class address; /** * Create a socket object for use. */ Socket(); /** * Create socket as duped handle of existing socket. * @param existing socket to dup. */ Socket(const Socket& existing); /** * Create socket from existing socket descriptor. * @param socket descriptor to use. */ Socket(socket_t socket); /** * Create and connect a socket to an address from an address list. The * type of socket created is based on the type we are connecting to. * @param address list to connect with. */ Socket(const struct addrinfo *address); /** * Create an unbound socket of a specific type. * @param family of our new socket. * @param type (stream, udp, etc) of our new socket. * @param protocol number of our new socket.' */ Socket(int family, int type, int protocol = 0); /** * Create a bound socket. If one wishes to listen for connections on * a protocol, then ListenSocket should be used instead. * @param address to bind or "*" for all. * @param port number of service to bind. * @param family to bind as. * @param type of socket to bind (stream, udp, etc). * @param protocol of socket to bind. */ Socket(const char *address, const char *port, int family = AF_UNSPEC, int type = 0, int protocol = 0); /** * Shutdown, close, and destroy socket. */ virtual ~Socket(); /** * Cancel pending i/o by shutting down the socket. */ void cancel(void); /** * Cancel pending i/o by shutting down the socket. * @param socket to shutdown. */ static void cancel(socket_t socket); /** * Shutdown and close the socket. */ void release(void); /** * Get error code. */ inline int err(void) const {return ioerr;} /** * See the number of bytes in the receive queue. * @param value to test for. * @return true if at least that many bytes waiting in receive queue. */ bool is_pending(unsigned value); /** * Test if socket is connected. * @return true if connected. */ bool connected(void) const; /** * Test for pending input data. This function can wait up to a specified * timeout for data to appear. * @param timeout or 0 if none. * @return true if input data waiting. */ bool wait(timeout_t timeout = 0) const; /** * Set nodelay option for tcp socket. * @return 0 if successful, -1 on error. */ inline int nodelay(void) const {return nodelay(so);} /** * Test for pending input data. This function can wait up to a specified * timeout for data to appear. * @param socket to test. * @param timeout or 0 if none. * @return true if input data waiting. */ static bool wait(socket_t socket, timeout_t timeout = 0); /** * Test for output data sent. This function can wait up to a specified * timeout for data to appear sent. * @param timeout or 0 if none. * @return false if cannot send more output/out of buffer space. */ bool waitSending(timeout_t timeout = 0) const; /** * Get the number of bytes of data in the socket receive buffer. * @return bytes pending. */ inline unsigned pending(void) const {return pending(so);} /** * Set socket for unicast mode broadcasts. * @param enable broadcasting if true. * @return 0 on success, -1 if error. */ inline int broadcast(bool enable) {return broadcast(so, enable);} /** * Set socket for keepalive packets. * @param enable keep-alive if true. * @return 0 on success, -1 if error. */ inline int keepalive(bool enable) {return keepalive(so, enable);} /** * Set socket blocking I/O mode. * @param enable true for blocking I/O. * @return 0 on success, -1 if error. */ inline int blocking(bool enable) {return blocking(so, enable);} /** * Set multicast mode and multicast broadcast range. * @param ttl to set for multicast socket or 0 to disable multicast. * @return 0 on success, -1 if error. */ inline int multicast(unsigned ttl = 1) {return multicast(so, ttl);} /** * Set loopback to read multicast packets we broadcast. * @param enable true to loopback, false to ignore. * @return 0 on success, -1 if error. */ inline int loopback(bool enable) {return loopback(so, enable);} /** * Get socket error code. * @return socket error code. */ inline int getError(void) {return error(so);} /** * Set the time to live before packets expire. * @param time to live to set. * @return 0 on success, -1 on error. */ inline int ttl(unsigned char time) {return ttl(so, time);} /** * Set the size of the socket send buffer. * @param size of send buffer to set. * @return 0 on success, -1 on error. */ inline int sendsize(unsigned size) {return sendsize(so, size);} /** * Set the size to wait before sending. * @param size of send wait buffer to set. * @return 0 on success, -1 on error. */ inline int sendwait(unsigned size) {return sendwait(so, size);} /** * Set the size of the socket receive buffer. * @param size of recv buffer to set. * @return 0 on success, -1 on error. */ inline int recvsize(unsigned size) {return recvsize(so, size);} /** * Get the type of a socket. * @param socket descriptor. * @return socket type. */ static int type(socket_t socket); /** * Set segment size and get MTU. * @param socket to modify. * @param size of segment or zero to not set. * @return mtu size of socket. */ static unsigned segsize(socket_t socket, unsigned size = 0); /** * Set congestion control id. * @param socket to modify. * @param ccid value to set. * @return true if success, false if not dccp or not supported ccid used. */ static bool ccid(socket_t socket, uint8_t id); /** * Get the type of a socket. * @return socket type. */ inline int type(void) {return type(so);} /** * Set segment size and get mtu of a socket. * @param size of segment or 0 to leave unchanged. * @return mtu size. */ inline unsigned segsize(unsigned size) {return segsize(so, size);} /** * Set ccid of dccp socket. * @param ccid to set. * @return true if success, false if not dccp or not supported ccid used. */ inline bool ccid(uint8_t id) {return ccid(so, id);} /** * Set the type of service field of outgoing packets. Some useful * values include IPTOS_LOWDELAY to minimize delay for interactive * traffic, IPTOS_THROUGHPUT to optimize throughput, OPTOS_RELIABILITY * to optimize for reliability, and IPTOS_MINCOST for low speed use. * @param type of service value. * @return 0 on success or -1 on error. */ inline int tos(int type) {return tos(so, type);} /** * Set packet priority, 0 to 6 unless privileged. Should be set before * type-of-service. * @param scheduling priority for packet scheduling. * @return 0 on success, -1 on error. */ inline int priority(int scheduling) {return priority(so, scheduling);} /** * Shutdown the socket communication channel. */ inline void shutdown(void) {::shutdown(so, SHUT_RDWR);} /** * Connect our socket to a remote host from an address list. * For TCP (and DCCP) sockets, the entire list may be tried. For UDP, * connect is only a state and the first valid entry in the list is used. * @param list of addresses to connect to. * @return 0 on success or error. */ int connectto(struct addrinfo *list); /** * Disconnect a connected socket. Depending on the implementation, this * might be done by connecting to AF_UNSPEC, connecting to a 0 address, * or connecting to self. * @return 0 on success or error. */ int disconnect(void); /** * Join socket to multicast group. * @param list of groups to join. * @return 0 on success, -1 on error. */ int join(const struct addrinfo *list, const int ifindex = 0); /** * Drop socket from multicast group. * @param list of groups to drop. * @return 0 on success, -1 on error. */ int drop(const struct addrinfo *list, const int ifindex = 0); /** * Socket i/o timer setting. * @param timeout to wait, inf for blocking, 0 pure non-blocking. * @return 0 on success or error code. */ int wait(timeout_t timeout = Timer::inf); /** * Peek at data waiting in the socket receive buffer. * @param data pointer to save data in. * @param number of bytes to peek. * @return number of bytes actually read, or 0 if no data waiting. */ size_t peek(void *data, size_t number) const; /** * Read data from the socket receive buffer. This will be used in abi 4. * @param data pointer to save data in. * @param number of bytes to read. * @param address of peer data was received from. * @return number of bytes actually read, 0 if none, -1 if error. */ size_t readfrom(void *data, size_t number, struct sockaddr_storage *address = NULL); /** * Write data to the socket send buffer. This will be used in abi 4. * @param data pointer to write data from. * @param number of bytes to write. * @param address of peer to send data to if not connected. * @return number of bytes actually sent, 0 if none, -1 if error. */ size_t writeto(const void *data, size_t number, const struct sockaddr *address = NULL); /** * Read a newline of text data from the socket and save in NULL terminated * string. This uses an optimized I/O method that takes advantage of * socket peeking. This presumes a connected socket on a streamble * protocol. Because the trailing newline is dropped, the return size * may be greater than the string length. If there was no data read * because of eof of data, an error has occured, or timeout without * input, then 0 will be returned. * @param data to save input line. * @param size of input line buffer. * @return number of bytes read, 0 if none, err() has error. */ size_t readline(char *data, size_t size); /** * Print formatted string to socket. * @param format string. * @return number of bytes sent. */ size_t printf(const char *format, ...) __PRINTF(2,3); /** * Read a string of input from the socket and strip trailing newline. * This uses an optimized I/O method that takes advantage of * socket peeking. This presumes a connected socket on a streamble * protocol. Because the trailing newline is dropped, the return size * may be greater than the string length. If there was no data read * because of eof of data, an error has occured, or timeout without * input, then 0 will be returned. * @param buffer to save input line. * @return number of bytes read, 0 if none, err() has error. */ size_t readline(String& buffer); /** * Read a newline of text data from the socket and save in NULL terminated * string. This uses an optimized I/O method that takes advantage of * socket peeking. As such, it has to be rewritten to be used in a ssl * layer socket. * @param socket to read from. * @param data to save input line. * @param size of input line buffer. * @param timeout to wait for a complete input line. * @return number of bytes read, 0 if none, -1 if error. */ static ssize_t readline(socket_t socket, char *data, size_t size, timeout_t timeout = Timer::inf); /** * Print formatted string to socket. * @param socket to write to. * @param format string. * @return number of bytes sent, -1 if error. */ static ssize_t printf(socket_t socket, const char *format, ...) __PRINTF(2,3); /** * Write a null terminated string to the socket. This exists because * we messed up consistency with the original puts() method. In the * future there will be a single puts() that has a NULL default. * @param string to write. * @return number of bytes sent, 0 if none, -1 if error. */ size_t writes(const char *string); /** * Test if socket is valid. * @return true if valid socket. */ operator bool(); /** * Test if socket is invalid. * @return true if socket is invalid. */ bool operator!() const; /** * Assign socket from a socket descriptor. Release existing socket if * one present. * @param socket descriptor to assign to object. */ Socket& operator=(socket_t socket); /** * Get the socket descriptor by casting. * @return socket descriptor of object. */ inline operator socket_t() const {return so;} /** * Get the socket descriptor by pointer reference. * @return socket descriptor of object. */ inline socket_t operator*() const {return so;} /** * Get the number of bytes pending in the receive buffer of a socket * descriptor. * @param socket descriptor. * @return number of pending bytes. */ static unsigned pending(socket_t socket); /** * Set the send size of a socket descriptor. * @param socket descriptor. * @param size of send buffer to set. * @return 0 on success, -1 on error. */ static int sendsize(socket_t socket, unsigned size); /** * Set the size to wait before sending. * @param socket descriptor. * @param size of send wait buffer to set. * @return 0 on success, -1 on error. */ static int sendwait(socket_t socket, unsigned size); /** * Set the receive size of a socket descriptor. * @param socket descriptor. * @param size of receive buffer to set. * @return 0 on success, -1 on error. */ static int recvsize(socket_t socket, unsigned size); /** * Connect socket descriptor to a remote host from an address list. * For TCP (and DCCP) sockets, the entire list may be tried. For UDP, * connect is only a state and the first valid entry in the list is used. * @param socket descriptor. * @param list of addresses to connect to. * @return 0 on success, -1 on error. */ static int connectto(socket_t socket, struct addrinfo *list); /** * Disconnect a connected socket descriptor. * @param socket descriptor. * @return 0 on success, -1 on error. */ static int disconnect(socket_t socket); /** * Drop socket descriptor from multicast group. * @param socket descriptor. * @param list of groups to drop. * @return 0 on success, -1 on error. */ static int drop(socket_t socket, const struct addrinfo *list, const int ifindex = 0); /** * Join socket descriptor to multicast group. * @param socket descriptor. * @param list of groups to join. * @return 0 on success, -1 on error. */ static int join(socket_t socket, const struct addrinfo *list, const int ifindex = 0); /** * Get socket error code of socket descriptor. * @param socket descriptor. * @return socket error code. */ static int error(socket_t socket); /** * Set multicast mode and multicast broadcast range for socket descriptor. * @param socket descriptor. * @param ttl to set for multicast socket or 0 to disable multicast. * @return 0 if success, -1 if error. */ static int multicast(socket_t socket, unsigned ttl = 1); /** * Set loopback to read multicast packets socket descriptor broadcasts. * @param socket descriptor. * @param enable true to loopback, false to ignore. * @return 0 if success, -1 if error. */ static int loopback(socket_t socket, bool enable); /** * Set socket blocking I/O mode of socket descriptor. * @param socket descriptor. * @param enable true for blocking I/O. * @return 0 if success, -1 if error. */ static int blocking(socket_t socket, bool enable); /** * Set socket for keepalive packets for socket descriptor. * @param socket descriptor. * @param enable keep-alive if true. * @return 0 if success, -1 if error. */ static int keepalive(socket_t socket, bool enable); /** * Set socket for unicast mode broadcasts on socket descriptor. * @param socket descriptor. * @param enable broadcasting if true. * @return 0 if success, -1 if error. */ static int broadcast(socket_t socket, bool enable); /** * Set tcp nodelay option on socket descriptor. * @param socket descriptor. * @return 0 if success, -1 if error. */ static int nodelay(socket_t socket); /** * Set packet priority of socket descriptor. * @param socket descriptor. * @param scheduling priority for packet scheduling. * @return 0 on success, -1 on error. */ static int priority(socket_t socket, int scheduling); /** * Set type of service of socket descriptor. * @param socket descriptor. * @param type of service. * @return 0 on success, -1 on error. */ static int tos(socket_t socket, int type); /** * Set the time to live for the socket descriptor. * @param socket descriptor. * @param time to live to set. * @return 0 on success, -1 on error. */ static int ttl(socket_t socket, unsigned char time); /** * Get the address family of the socket descriptor. * @return address family. */ static int family(socket_t socket); /** * Get the address family of a socket address object. * @param address to examine. * @return address family. */ inline static int family(const struct sockaddr_storage& address) {return ((const struct sockaddr *)&address)->sa_family;} /** * Get the address family of an internet socket address object. * @param address to examine. * @return address family. */ inline static int family(const struct sockaddr_internet& address) {return address.address.sa_family;} /** * Get data waiting in receive queue. * @param socket to get from. * @param buffer to save. * @param size of data buffer to request. * @param flags for i/o operation (MSG_OOB, MSG_PEEK, etc). * @param address of source. * @return number of bytes received, -1 if error. */ static ssize_t recvfrom(socket_t socket, void *buffer, size_t size, int flags = 0, struct sockaddr_storage *address = NULL); /** * Send data on socket. * @param socket to send to. * @param buffer to send. * @param size of data buffer to send. * @param flags for i/o operation (MSG_OOB, MSG_PEEK, etc). * @param address of destination, NULL if connected. * @return number of bytes sent, -1 if error. */ static ssize_t sendto(socket_t socket, const void *buffer, size_t size, int flags = 0, const struct sockaddr *address = NULL); /** * Send reply on socket. Used to reply to a recvfrom message. * @param socket to send to. * @param buffer to send. * @param size of data buffer to send. * @param flags for i/o operation (MSG_OOB, MSG_PEEK, etc). * @param address to reply to. * @return number of bytes sent, -1 if error. */ inline static ssize_t replyto(socket_t socket, const void *buffer, size_t size, int flags, const struct sockaddr_storage *address) {return sendto(socket, buffer, size, flags, (const struct sockaddr *)address);} /** * Send to internet socket. * @param socket to send to. * @param buffer to send. * @param size of data buffer to send. * @param flags for i/o operation (MSG_OOB, MSG_PEEK, etc). * @param address to send to. * @return number of bytes sent, -1 if error. */ inline static ssize_t sendinet(socket_t socket, const void *buffer, size_t size, int flags, const struct sockaddr_internet *address) {return sendto(socket, buffer, size, flags, (const struct sockaddr *)address);} /** * Get internet data waiting in receive queue. * @param socket to get from. * @param buffer to save. * @param size of data buffer to request. * @param flags for i/o operation (MSG_OOB, MSG_PEEK, etc). * @param address of source. * @return number of bytes received, -1 if error. */ static ssize_t recvinet(socket_t socket, void *buffer, size_t size, int flags = 0, struct sockaddr_internet *address = NULL); /** * Bind the socket descriptor to a known interface and service port. * @param socket descriptor to bind. * @param address to bind to or "*" for all. * @param service port to bind. * @param protocol to use or 0 if default. * @return 0 on success, -1 if error. */ static int bindto(socket_t socket, const char *address, const char *service, int protocol = 0); /** * Bind the socket descriptor to a known interface listen on service port. * @param socket descriptor to bind. * @param address of interface to bind to. * @param backlog for service. * @return 0 on success, -1 if error. */ static int listento(socket_t socket, const struct sockaddr *address, int backlog = 5); /** * Bind the socket descriptor to a known interface. * @param socket descriptor to bind. * @param address of interface to bind to. * @return 0 on success, -1 if error. */ static int bindto(socket_t socket, const struct sockaddr *address); /** * Accept a socket connection from a remote host. * @param socket descriptor to accept from. * @param address of socket accepting. * @return new socket accepted. */ static socket_t acceptfrom(socket_t socket, struct sockaddr_storage *address = NULL); /** * Create a socket object unbound. * @param family of socket. * @param type of socket. * @param protocol of socket. * @return socket descriptor created or INVALID_SOCKET. */ static socket_t create(int family, int type, int protocol); /** * Create a connected socket. * @param address list to connect to. * @param type of socket to create. * @param protocol of socket. * @return socket descriptor created or INVALID_SOCKET. */ static socket_t create(const struct addrinfo *address, int type, int protocol); /** * Create a bound socket for a service. * @param iface to bind. * @param service port to bind. * @param family to select or AF_UNSPEC * @param type of socket to create. * @param protocol of socket to create. * @return socket descriptor created or INVALID_SOCKET. */ static socket_t create(const char *iface, const char *service, int family = AF_UNSPEC, int type = 0, int protocol = 0); /** * Create a connected socket for a service. * @param address of service for connect. * @return socket descriptor. */ static socket_t create(const Socket::address &address); /** * Release (close) a socket. * @param socket to close. */ static void release(socket_t socket); /** * Lookup and return the host name associated with a socket address. * @param address to lookup. * @param buffer to save hostname into. * @param size of buffer to save hostname into. * @return buffer or NULL if lookup fails. */ static char *hostname(const struct sockaddr *address, char *buffer, size_t size); /** * Create an address info lookup hint based on the family and type * properties of a socket descriptor. * @param socket descriptor. * @param hint buffer. * @return hint buffer. */ static struct addrinfo *hinting(socket_t socket, struct addrinfo *hint); /** * Lookup a host name and service address based on the addressing family * and socket type of a socket descriptor. Store the result in a socket * address structure. * @param socket descriptor. * @param address that is resolved. * @param hostname to resolve. * @param service port. * @return socket address size. */ static socklen_t query(socket_t socket, struct sockaddr_storage *address, const char *hostname, const char *service); /** * Get the size of a socket address. * @param address of socket. * @return size to use for this socket address object. */ static socklen_t len(const struct sockaddr *address); /** * Compare socket addresses. Test if the address and service matches * or if there is no service, then just the host address values. * @param address1 to compare. * @param address2 to compare. * @return true if same family and equal. */ static bool equal(const struct sockaddr *address1, const struct sockaddr *address2); /** * Copy a socket address. * @param target address pointer to copy into. * @param origin address pointer to copy from. * @return number of bytes copied, 0 if invalid. */ static unsigned copy(struct sockaddr *target, const struct sockaddr *origin); /** * Store an address into an address object. * @param storage for address. * @param address to store. * @return number of bytes stored. */ inline static unsigned store(struct sockaddr_storage *storage, const struct sockaddr *address) {return copy((struct sockaddr*)storage, address);} /** * Store an address into an internet address object. * @param storage for address. * @param address to store. * @return number of bytes stored. */ static unsigned store(struct sockaddr_internet *storage, const struct sockaddr *address); /** * Compare socket host addresses. Test if the host address matches * or if there is no service, then just the host address values. * @param address1 to compare. * @param address2 to compare. * @return true if same family and equal. */ static bool eq_host(const struct sockaddr *address1, const struct sockaddr *address2); /** * Compare socket addresses. Test if the stored addresses received match. * or if there is no service, then just the host address values. * @param address1 to compare. * @param address2 to compare. * @return true if same family and equal. */ inline static bool eq_from(const struct sockaddr_storage *address1, const struct sockaddr_storage *address2) {return equal((const struct sockaddr *)address1, (const struct sockaddr *)address2);} /** * Compare socket addresses. Test if the internet addresses received match. * or if there is no service, then just the host address values. * @param address1 to compare. * @param address2 to compare. * @return true if same family and equal. */ inline static bool eq_inet(const struct sockaddr_internet *address1, const struct sockaddr_internet *address2) {return equal((const struct sockaddr *)address1, (const struct sockaddr *)address2);} /** * See if both addresses are in the same subnet. This is only relevant * to IPV4 and class domain routing. * @param address1 to test. * @param address2 to test. * @return true if in same subnet. */ static bool eq_subnet(const struct sockaddr *address1, const struct sockaddr *address2); /** * Get the socket address of the interface needed to reach a destination * address. * @param address of interface found. * @param destination address. * @return 0 on success, -1 on error. */ static int via(struct sockaddr *address, const struct sockaddr *destination); /** * Get the hostname of a socket address. * @param address to lookup. * @param buffer to save hostname in. * @param size of hostname buffer. * @return buffer if found or NULL if not. */ static char *query(const struct sockaddr *address, char *buffer, socklen_t size); /** * Get the service port of a socket. * @param address of socket to examine. * @return service port number. */ static short service(const struct sockaddr *address); /** * Get the service port of an inet socket. * @param address of internet socket to examine. * @return service port number. */ inline static short service(const struct sockaddr_internet *address) {return service((const struct sockaddr *)address);} /** * Convert a socket address and service into a hash map index. * @param address to convert. * @param size of map index. * @return key index path. */ static unsigned keyindex(const struct sockaddr *address, unsigned size); /** * Convert a socket host address into a hash map index. * @param address to convert. * @param size of map index. * @return key index path. */ static unsigned keyhost(const struct sockaddr *address, unsigned size); /** * Initialize socket subsystem. */ static void init(void); /** * Initialize with program name. Used by socks, for example. * @param program name. */ static void init(const char *program); /** * Set default socket family preference for query options when the * socket type is otherwise not specified. * @param family to select. */ static void query(int family); /** * Set the default socket behavior for v6-v4 mapping. This also * effects v6 address lookup as to whether v4 remapped addresses * can be used if no v6 address is found. * @param enable true to set mapping. This is default. */ static void v4mapping(bool enable); /** * Return error code of last socket operation, * @return errno style error code. */ static int error(void); /** * Simple function to validate that a given IP address string is a "zero" * address. Such address strings are used for example in SIP to indicate * "hold" by re-inviting peers to a null address. Supports IPV4 and * IPV6 addresses. * @param string address to check. * @return true if zero/null address. */ static bool is_null(const char *string); /** * Simple function to validate that a given IP address string is a numeric * address. This can be used to verify an address is not a "host" name. * Supports IPV4 and IPV6 address strings. * @param string address to check. * @return true if zero/null address. */ static bool is_numeric(const char *string); /** * Get local address to which the socket is bound. This is defined here * because we may re-define the backend linkage for the socks proxy in * the future. * @param socket descriptor to examine. * @param address storage for local address. * @return 0 on success, -1 on failure. */ static int local(socket_t socket, struct sockaddr_storage *address); /** * Get remote address to which the socket is connected. This is defined * here because we may re-define the backend linkage for the socks proxy in * the future. * @param socket descriptor to examine. * @param address storage for remote address. * @return 0 on success, -1 on failure. */ static int remote(socket_t socket, struct sockaddr_storage *address); }; /** * A bound socket used to listen for inbound socket connections. This class * is commonly used for TCP and DCCP listener sockets. * @author David Sugar */ class __EXPORT ListenSocket : protected Socket { public: /** * Create and bind a listener socket. * @param address to bind on or "*" for all. * @param service port to bind listener. * @param backlog size for buffering pending connections. * @param family of socket. * @param type of socket. * @param protocol for socket if not TCPIP. */ ListenSocket(const char *address, const char *service, unsigned backlog = 5, int family = AF_UNSPEC, int type = 0, int protocol = 0); /** * Create a listen socket directly. * @param address to bind on or "*" for all. * @param service port to bind listener. * @param backlog size for buffering pending connections. * @param family of socket. * @param type of socket. * @param protocol for socket if not TCPIP. * @return bound and listened to socket. */ static socket_t create(const char *address, const char *service, unsigned backlog = 5, int family = AF_UNSPEC, int type = 0, int protocol = 0); /** * Accept a socket connection. * @param address to save peer connecting. * @return socket descriptor of connected socket. */ socket_t accept(struct sockaddr_storage *address = NULL) const; /** * Wait for a pending connection. * @param timeout to wait. * @return true when acceptable connection is pending. */ inline bool wait(timeout_t timeout = Timer::inf) const {return Socket::wait(timeout);} /** * Get the socket descriptor of the listener. * @return socket descriptor. */ inline operator socket_t() const {return so;} /** * Get the socket descriptor of the listener by pointer reference. * @return socket descriptor. */ inline socket_t operator*() const {return so;} /** * Get the socket descriptor of the listener. * @return socket descriptor. */ inline socket_t getsocket(void) const {return so;} inline socket_t handle(void) const {return so;} }; /** * A generic tcp server class. This saves the service id tag so that it * can be propagated. * @author David Sugar */ class __EXPORT TCPServer : public ListenSocket { public: /** * Create and bind a tcp server. This mostly is used to preserve the * service tag for TCP Socket when derived from a server instance. * @param service tag to use. * @param address of interface to bind or "*" for all. * @param backlog size for pending connections. */ TCPServer(const char *address, const char *service, unsigned backlog = 5); }; /** * Helper function for linked_pointer. */ __EXPORT struct addrinfo *_nextaddrinfo(struct addrinfo *addrinfo); /** * Helper function for linked_pointer. */ __EXPORT struct sockaddr *_getaddrinfo(struct addrinfo *addrinfo); /** * Helper function for linked_pointer. */ __EXPORT socket_t _getaddrsock(struct addrinfo *addrinfo); /** * Linked pointer for address lists. This can be used to iterate through * the list of a Socket::address object using the linked_pointer method. * @author David Sugar */ template <> class linked_pointer { private: struct addrinfo *ptr; public: inline linked_pointer(struct addrinfo *list) {ptr = list;} inline linked_pointer() {ptr = NULL;} inline linked_pointer(Socket::address& list) {ptr = list.getList();} /** * Get the full socket address list by casted reference. * @return addrinfo list we resolved or NULL if none. */ inline operator struct sockaddr *() const {return _getaddrinfo(ptr);} /** * Return the full socket address list by pointer reference. * @return addrinfo list we resolved or NULL if none. */ inline struct sockaddr *operator*() const {return _getaddrinfo(ptr);} inline operator struct sockaddr_in *() const {return (struct sockaddr_in *)_getaddrinfo(ptr);} inline struct sockaddr_in *in(void) const {return (struct sockaddr_in *)_getaddrinfo(ptr);} #ifdef AF_INET6 inline operator struct sockaddr_in6 *() const {return (struct sockaddr_in6 *)_getaddrinfo(ptr);} inline struct sockaddr_in6 *in6(void) const {return (struct sockaddr_in6 *)_getaddrinfo(ptr);} #endif /** * Get socket as expression operator. */ inline socket_t operator()(void) const {return _getaddrsock(ptr);} /** * Test if the address list is valid. * @return true if we have an address list. */ inline operator bool() const {return ptr != NULL;} /** * Assign our pointer from an address list. * @param pointer of linked list. */ inline void operator=(struct addrinfo *list) {ptr = list;} /** * Assign our pointer from an address list. * @param pointer of linked list. */ inline void operator=(Socket::address& list) {ptr = list.getList();} /** * Assign our pointer from an address list. * @param pointer of linked list. */ inline void set(struct addrinfo *list) {ptr = list;} /** * Assign our pointer from an address list. * @param pointer of linked list. */ inline void set(Socket::address& list) {ptr = list.getList();} /** * Return member from typed object our pointer references. * @return evaluated member of object we point to. */ inline struct sockaddr* operator->() const {return _getaddrinfo(ptr);} /** * Test if we have no address list. * @return true if we have no address list. */ inline bool operator!() const {return ptr == NULL;} inline void next(void) {ptr = _nextaddrinfo(ptr);} }; /** * A convenience function to convert a socket address list into an addrinfo. * @param address list object. * @return addrinfo list or NULL if empty. */ inline struct addrinfo *addrinfo(Socket::address& address) {return address.getList();} /** * A convenience function to convert a socket address list into a socket * address. * @param address list object. * @return first socket address in list or NULL if empty. */ inline struct sockaddr *addr(Socket::address& address) {return address.get();} /** * Compare two socket addresses to see if equal. If the port is zero * then this is the same as comparing host address alone. * @param s1 socket address to compare. * @param s2 socket address to compare. * @return true if addresses same. */ inline bool eq(const struct sockaddr *s1, const struct sockaddr *s2) {return Socket::equal(s1, s2);} /** * Compare two stored socket addresses to see if equal. If the port is zero * then this is the same as comparing host address alone. * @param s1 stored socket address to compare. * @param s2 stored socket address to compare. * @return true if addresses same. */ inline bool eq(const struct sockaddr_storage *s1, const struct sockaddr_storage *s2) {return Socket::equal((const struct sockaddr *)s1, (const struct sockaddr *)s2);} /** * Compare two host addresses to see if equal. The port numbers are * ignored. * @param s1 socket address to compare. * @param s2 socket address to compare. * @return true if addresses same. */ inline bool eq_host(const struct sockaddr *s1, const struct sockaddr *s2) {return Socket::eq_host(s1, s2);} inline bool eq_subnet(const struct sockaddr *s1, const struct sockaddr *s2) {return Socket::eq_subnet(s1, s2);} String str(Socket& so, strsize_t size); typedef TCPServer tcpserv_t; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/numbers.h0000664000175000017500000001374412504226620014207 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Support classes for manipulation of numbers as strings. This is * used for things which parse numbers out of strings, such as in the * date and time classes. Other useful math related functions, templates, * and macros may also be found here. * @file ucommon/numbers.h */ #ifndef _UCOMMON_NUMBERS_H_ #define _UCOMMON_NUMBERS_H_ #ifndef _UCOMMON_CONFIG_H_ #include #endif namespace ucommon { /** * A number manipulation class. This is used to extract, convert, * and manage simple numbers that are represented in C ascii strings * in a very quick and optimal way. This class modifies the string * representation each time the value is changed. No math expressions * or explicit comparison operators are supported for the Numbers class * because these are best done by casting to long first. * * @author David Sugar * @short number manipulation. */ class __EXPORT Number { protected: char *buffer; unsigned size; public: /** * Create an instance of a number. * @param buffer or NULL if created internally. * @param size of field if not null terminated. */ Number(char *buffer, unsigned size); /** * Set string based on a new value. * @param value to set. */ void set(long value); /** * Get string buffer representing the number. * @return string buffer. */ inline const char *c_str() const {return buffer;} /** * Get value of string buffer as a long integer. * @return long integer value of string buffer. */ long get() const; /** * Get value of string buffer as expression of object. * @return long integer value of string buffer. */ inline long operator()() const {return get();} /** * Cast string as long integer and get value of buffer. * @return long integer value of string buffer. */ inline operator long() const {return get();} /** * Cast object as a string to retrieve buffer. * @return string buffer of value. */ inline operator char*() const {return buffer;} /** * Assign a value to the number. This rewrites the string buffer. * @param value to assign. * @return new value of number object assigned. */ long operator=(long value); /** * Assign another number to this number. * @param number to assign to assign. * @return new value of number object assigned. */ long operator=(const Number& number); /** * Add a value to the number. This rewrites the string buffer. * @param value to add. * @return new value of number object. */ long operator+=(const long value); /** * Subtract a value from the number. This rewrites the string buffer. * @param value to subtract. * @return new value of number object. */ long operator-=(const long value); /** * Decrement the number object. This rewrites the string buffer. * @return new value of number object. */ long operator--(); /** * Increment the number object. This rewrites the string buffer. * @return new value of number object. */ long operator++(); inline bool operator==(const long value) const {return get() == value;} inline bool operator!=(const long value) const {return get() != value;} inline bool operator<(const long value) const {return get() < value;} inline bool operator>(const long value) const {return get() > value;} inline bool operator<=(const long value) const {return get() <= value;} inline bool operator>=(const long value) const {return get() >= value;} }; /** * A number manipulation class that maintains a zero lead filled string. * * @author David Sugar * @short zero filled number manipulation. */ class __EXPORT ZNumber : public Number { public: /** * Create a number class for zero fill. * @param pointer to field. * @param size of field to fill. */ ZNumber(char *pointer, unsigned size); /** * Set value of zero filled number. * @param value to set. */ void set(long value); /** * Assign number from value. * @param value to assign. * @return value assigned. */ long operator=(long value); }; /** * A convenience type for number. */ typedef Number number_t; /** * A convenience type for znumber. */ typedef ZNumber znumber_t; /** * Template for absolute value of a type. * @param value to check * @return absolute value */ template inline const T abs(const T& value) { if(value < (T)0) return -value; return value; } /** * Template for min value of a type. * @param v1 value to check * @param v2 value to check * @return v1 if < v2, else v2 */ template inline const T (min)(const T& v1, const T& v2) { return ((v1 < v2) ? v1 : v2); } /** * Template for max value of a type. * @param v1 value to check * @param v2 value to check * @return v1 if > v2, else v2 */ template inline const T (max)(const T& v1, const T& v2) { return ((v1 > v2) ? v1 : v2); } } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/keydata.h0000664000175000017500000001637012556423111014155 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Parsing of config files that have keyword/value pairs. This includes * supporting classes to extract basic config data from files that are stored * as []'s, and uses several supporting classes. * @file ucommon/keydata.h */ /** * Some exercise of keydata routines. * @example keydata.cpp */ #ifndef _UCOMMON_KEYDATA_H_ #define _UCOMMON_KEYDATA_H_ #ifndef _UCOMMON_CONFIG_H_ #include #endif #ifndef _UCOMMON_LINKED_H_ #include #endif #ifndef _UCOMMON_MEMORY_H_ #include #endif namespace ucommon { class keyfile; /** * Data keys parsed from a keyfile. This is a specific [] section from a * fully loaded keyfile, and offers common means to access data members. * This is related to the original GNU Common C++ keydata object, although * it is formed in a keyfile class which is loaded from a config file all * at once. * @author David Sugar */ class __EXPORT keydata : public OrderedObject { private: friend class keyfile; OrderedIndex index; keydata(keyfile *file); keydata(keyfile *file, const char *id); const char *name; keyfile *root; public: /** * A key value set is used for iterative access. Otherwise this class * is normally not used as we usually request the keys directly. * @author David Sugar */ class __LOCAL keyvalue : public OrderedObject { private: friend class keydata; friend class keyfile; keyvalue(keyfile *allocator, keydata *section, const char *key, const char *data); public: const char *id; const char *value; }; friend class keyvalue; /** * Lookup a key value by it's id. * @param id to look for. * @return value string or NULL if not found. */ const char *get(const char *id) const; /** * Lookup a key value by it's id. * @param id to look for. * @return value string or NULL if not found. */ inline const char *operator()(const char *id) const {return get(id);} /** * Set a keyword and value in the keydata structure. If the keyword * already exists, it is replaced. Removed items still use pager * allocated memory. * @param id to set. * @param value for the id. */ void set(const char *id, const char *value); /** * Remove a keyword id from the keydata structure. Removed items * still use pager allocated memory. * @param id to remove. */ void clear(const char *id); /** * Get the name of this section. Useful in iterative examinations. * @return name of keydata section. */ inline const char *get(void) const {return name;} /** * Get first value object, for iterative examinations. * @return first key value in chain. */ inline keyvalue *begin(void) const {return (keyvalue *)index.begin();} /** * Get last value object, for iterative examinations. * @return first key value in chain. */ inline keyvalue *end(void) const {return (keyvalue*)index.end();} /** * Convenience typedef for iterative pointer. */ typedef linked_pointer iterator; }; /** * Traditional keypair config file parsing class. This is used to get * generic config data either from a /etc/xxx.conf, a windows style * xxx.ini file, or a ~/.xxxrc file, and parses [] sections from the * entire file at once. */ class __EXPORT keyfile : public memalloc { private: friend class keydata; OrderedIndex index; keydata *defaults; int errcode; protected: keydata *create(const char *section); #ifdef _MSWINDOWS_ void load(HKEY root, keydata *section = NULL, const char *path = NULL); bool save(HKEY root, keydata *section = NULL, const char *path = NULL); #endif public: /** * Create an empty key file ready for loading. * @param pagesize for memory paging. */ keyfile(size_t pagesize = 0); /** * Create a key file object from an existing config file. * @param path to load from. * @param pagesize for memory paging. */ keyfile(const char *path, size_t pagesize = 0); keyfile(const keyfile ©, size_t pagesize = 0); /** * Load (overlay) another config file over the currently loaded one. * This is used to merge key data, such as getting default values from * a global config, and then overlaying a local home config file. * @param path to load keys from into current object. */ void load(const char *path); /** * Save (write) a set of config keys to dist. * @param path of file to save keys to. * @return true on success. */ bool save(const char *path); /** * Load from an existing keyfile object. * @param source to copy from. */ void load(const keyfile *source); /** * Load a single set of keys. * @param source of keys to copy. */ void load(const keydata *source); /** * Release and re-initialize keyfile. */ void release(void); /** * Get a keydata section name. * @param section name to look for. * @return keydata section object if found, NULL if not. */ keydata *get(const char *section) const; inline keydata *operator()(const char *section) const {return get(section);} inline keydata *operator[](const char *section) const {return get(section);} /** * Get the non-sectioned defaults if there are any. * @return default key section. */ inline keydata *get(void) const {return defaults;} /** * Get first keydata object, for iterative examinations. * @return first key value in chain. */ inline keydata *begin(void) const {return (keydata *)index.begin();} /** * Get last keydata object, for iterative examinations. * @return first key value in chain. */ inline keydata *end(void) const {return (keydata *)index.end();} /** * Convenience typedef for iterative pointer. */ typedef linked_pointer iterator; inline int err(void) const {return errcode;} /** * Assign foreign pager to us. This relocates the heap references * to our object, clears the other object. */ void assign(keyfile& source); inline keyfile& operator=(keyfile& source) { assign(source); return *this; } }; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/xml.h0000664000175000017500000001111112504227106013316 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * XML "SAX" (stream) parsing support from GNU Common C++. * @file ucommon/xml.h */ #ifndef _UCOMMON_STRING_H_ #include #endif #ifndef _UCOMMON_PROTOCOLS_H_ #include #endif #ifndef _UCOMMON_XML_H_ #define _UCOMMON_XML_H_ namespace ucommon { /** * XML streaming parser. This class implements a basic XML stream parser * that can be used to examine an XML resource thru virtual I/O methods. * This class must be derived into one that can implement the physical I/O * required to parse actual data. A mixer class using XMLParser and * tcpstream would be one example of this. This can also be used to * parse xml content in memory buffers easily. This parser is only concerned * with well-formedness, and does not perform validation. * * @author David Sugar */ class __EXPORT XMLParser { private: int ecount, dcount; enum {TAG, CDATA, COMMENT, DTD, AMP, NONE, END} state; char *buffer; unsigned bufpos, bufsize; __LOCAL bool parseTag(void); __LOCAL void putBuffer(char c); __LOCAL void clearBuffer(void); protected: /** * Create xml parser. * @param size of XML data buffer. */ XMLParser(unsigned size = 8192); /** * Destroy xml parser. */ virtual ~XMLParser(); /** * Virtual to receive embedded comments in XML document being parsed. * @param text received. * @param size of text received. */ virtual void comment(caddr_t text, size_t size); /** * Virtual to receive character text extracted from the document. * @param text received. * @param size of text received. */ virtual void characters(caddr_t text, size_t size); /** * Notify start of document event. */ virtual void startDocument(void); /** * Notify end of document event. */ virtual void endDocument(void); /** * Notify start of an element in the document. * @param name of element found. * @param attr list of attributes extracted. */ virtual void startElement(caddr_t name, caddr_t *attr) = 0; /** * Notify end of an element in the document. * @param name of element ending. */ virtual void endElement(caddr_t name) = 0; /** * Parse a chunk of data and return parser completion flag. This is * used to externally drive data into the XML parser. The return * status can be used to determine when a document has been fully * parsed. This can be called multiple times to push stream data * into the parser. * @param address of data to parse. * @param size of data to parse. */ bool partial(const char *address, size_t size); /** * Parse a stream buffer and return parser document completion flag. * This is used to scan a stream buffer for a complete XML document. * The stream is scanned until the document is complete or EOF. * Multiple XML document instances can be scanned from a continues * XML streaming source. * @param stream buffer to parse. * @return true if parse complete, false if invalid or EOF. */ bool parse(CharacterProtocol& stream); /** * Parse a file buffer and return parser document completion flag. * This is used to scan a file buffer for a complete XML document. * The file is scanned until the document is complete or EOF. * Multiple XML document instances can be scanned from a continues * XML streaming source. * @param file buffer to parse. * @return true if parse complete, false if invalid or EOF. */ bool parse(FILE *file); /** * End of document check. * @return true if end of document. */ bool end(void) const { return state == END; } }; } // namespace ucommon #endif ucommon-6.4.4/inc/ucommon/generics.h0000664000175000017500000003450412523662131014332 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . /** * Generic templates for C++. These are templates that do not depend * on any ucommon classes. They can be used for generic C++ programming. * @file ucommon/generics.h */ #ifndef _UCOMMON_GENERICS_H_ #define _UCOMMON_GENERICS_H_ #ifndef _UCOMMON_CPR_H_ #include #endif #include #include #include #ifndef UCOMMON_SYSRUNTIME #define THROW(x) throw x #define THROWS(x) throw(x) #define THROWS_ANY throw() #else #define THROW(x) ::abort() #define THROWS(x) #define THROWS_ANY #endif namespace ucommon { /** * Generic smart pointer class. This is the original Common C++ "Pointer" * class with a few additions. * @author David Sugar */ template class pointer { protected: unsigned *counter; T *object; public: inline void release(void) { if(counter && --(*counter)==0) { delete counter; delete object; } object = NULL; counter = NULL; } inline void retain(void) { if(counter) ++*counter; } inline void set(T* ptr) { if(object != ptr) { release(); counter = new unsigned; *counter = 1; object = ptr; } } inline void set(const pointer &ref) { if(object == ref.object) return; if(counter && --(*counter)==0) { delete counter; delete object; } object = ref.object; counter = ref.counter; if(counter) ++(*counter); } inline pointer() { counter = NULL; object = NULL; } inline explicit pointer(T* ptr = NULL) : object(ptr) { if(object) { counter = new unsigned; *counter = 1; } else counter = NULL; } inline pointer(const pointer &ref) { object = ref.object; counter = ref.counter; if(counter) ++(*counter); } inline pointer& operator=(const pointer &ref) { this->set(ref); return *this; } inline pointer& operator=(T *ptr) { this->set(ptr); return *this; } inline ~pointer() { release(); } inline T& operator*() const { return *object; } inline T* operator->() const { return object; } inline bool operator!() const { return (counter == NULL); } inline operator bool() const { return counter != NULL; } }; /** * Generic smart array class. This is the original Common C++ "Pointer" class * with a few additions for arrays. * @author David Sugar */ template class array_pointer { protected: unsigned *counter; T *array; public: inline void release(void) { if(counter && --(*counter)==0) { delete counter; delete[] array; } array = NULL; counter = NULL; } inline void retain(void) { if(counter) ++*counter; } inline void set(T* ptr) { if(array != ptr) { release(); counter = new unsigned; *counter = 1; array = ptr; } } inline void set(const array_pointer &ref) { if(array == ref.array) return; if(counter && --(*counter)==0) { delete counter; delete[] array; } array = ref.array; counter = ref.counter; if(counter) ++(*counter); } inline array_pointer() { counter = NULL; array = NULL; } inline explicit array_pointer(T* ptr = NULL) : array(ptr) { if(array) { counter = new unsigned; *counter = 1; } else counter = NULL; } inline array_pointer(const array_pointer &ref) { array = ref.array; counter = ref.counter; if(counter) ++(*counter); } inline array_pointer& operator=(const array_pointer &ref) { this->set(ref); return *this; } inline array_pointer& operator=(T *ptr) { this->set(ptr); return *this; } inline ~array_pointer() { release(); } inline T* operator*() const { return array; } inline T& operator[](size_t offset) const { return array[offset]; } inline T* operator()(size_t offset) const { return &array[offset]; } inline bool operator!() const { return (counter == NULL); } inline operator bool() const { return counter != NULL; } }; /** * Manage temporary object stored on the heap. This is used to create a * object on the heap who's scope is controlled by the scope of a member * function call. Sometimes we have data types and structures which cannot * themselves appear as auto variables. We may also have a limited stack * frame size in a thread context, and yet have a dynamic object that we * only want to exist during the life of the method call. Using temporary * allows any type to be created from the heap but have a lifespan of a * method's stack frame. * @author David Sugar */ template class temporary { protected: T *object; public: /** * Construct a temporary object, create our stack frame reference. */ inline temporary() { object = NULL; } /** * Disable copy constructor. */ temporary(const temporary&) { ::abort(); } /** * Construct an assigned pointer. */ inline temporary(T *ptr) { object = ptr; } /** * Assign a temporary object. This adds a pointer to an existing * type to the current temporary pointer. If the temporary was * already assigned, then it is deleted. * @param temp object to assign. */ inline T& operator=(T *temp) { if(object) delete object; object = temp; return *this; } /** * Assign a temporary object. This adds a pointer to an existing * type to the current temporary pointer. If the temporary was * already assigned, then it is deleted. * @param temp object to assign. */ inline void set(T *temp) { if(object) delete object; object = temp; } /** * Access heap object through our temporary directly. * @return reference to heap resident object. */ inline T& operator*() const { return *object; } /** * Access members of our heap object through our temporary. * @return member reference of heap object. */ inline T* operator->() const { return object; } inline operator bool() const { return object != NULL; } inline bool operator!() const { return object == NULL; } inline ~temporary() { if(object) delete object; object = NULL; } }; /** * Manage temporary array stored on the heap. This is used to create an * array on the heap who's scope is controlled by the scope of a member * function call. Sometimes we have data types and structures which cannot * themselves appear as auto variables. We may also have a limited stack * frame size in a thread context, and yet have a dynamic object that we * only want to exist during the life of the method call. Using temporary * allows any type to be created from the heap but have a lifespan of a * method's stack frame. * @author David Sugar */ template class temp_array { protected: T *array; size_t size; public: /** * Construct a temporary object, create our stack frame reference. */ inline temp_array(size_t s) { array = new T[s]; size = s; } /** * Construct a temporary object with a copy of some initial value. * @param initial object value to use. */ inline temp_array(const T& initial, size_t s) { array = new T[s]; size = s; for(size_t p = 0; p < s; ++p) array[p] = initial; } inline void reset(size_t s) { delete[] array; array = new T[s]; size = s; } inline void reset(const T& initial, size_t s) { if(array) delete[] array; array = new T[s]; size = s; for(size_t p = 0; p < s; ++p) array[p] = initial; } inline void set(const T& initial) { for(size_t p = 0; p < size; ++p) array[p] = initial; } /** * Disable copy constructor. */ temp_array(const temp_array&) { ::abort(); } inline operator bool() const { return array != NULL; } inline bool operator!() const { return array == NULL; } inline ~temp_array() { if(array) delete[] array; array = NULL; size = 0; } inline T& operator[](size_t offset) const { crit(offset < size, "array out of bound"); return array[offset]; } inline T* operator()(size_t offset) const { crit(offset < size, "array out of bound"); return &array[offset]; } }; /** * Save and restore global objects in function call stack frames. * @author David Sugar */ template class save_restore { private: T *original; T temp; public: /** * Save object into local copy and keep reference to the original object. * @param object to save. */ inline save_restore(T& object) { original = &object; temp = object; } /** * Restore original when stack frame is released. */ inline ~save_restore() { *original = temp; } }; /** * Convenience function to validate object assuming it is castable to bool. * @param object we are testing. * @return true if object valid. */ template inline bool is(T& object) { return object.operator bool(); } /** * Convenience function to test pointer object. This solves issues where * some compilers get confused between bool and pointer operators. * @param object we are testing. * @return true if object points to NULL. */ template inline bool isnull(T& object) { return (bool)(object.operator*() == NULL); } /** * Convenience function to test pointer-pointer object. This solves issues * where some compilers get confused between bool and pointer operators. * @param object we are testing. * @return true if object points to NULL. */ template inline bool isnullp(T *object) { return (bool)(object->operator*() == NULL); } /** * Convenience function to duplicate object pointer to heap. * @param object we are duping. * @return heap pointer instance. */ template inline T* dup(const T& object) { return new T(object); } template inline void dupfree(T object) { delete object; } template<> inline char *dup(const char& object) { return strdup(&object); } template<> inline void dupfree(char* object) { ::free(object); } /** * Convenience function to reset an existing object. * @param object type to reset. */ template inline void reset_unsafe(T& object) { new((caddr_t)&object) T; } /** * Convenience function to zero an object and restore type info. * @param object to zero in memory. */ template inline void zero_unsafe(T& object) { memset((void *)&object, 0, sizeof(T)); new((caddr_t)&object) T; } /** * Convenience function to copy class. * @param target to copy into. * @param source to copy from. */ template inline void copy_unsafe(T* target, const T* source) { memcpy((void *)target, (void *)source, sizeof(T)); } /** * Convenience function to store object pointer into object. * @param target to copy into. * @param source to copy from. */ template inline void store_unsafe(T& target, const T* source) { memcpy((void *)&target, (void *)source, sizeof(T)); } /** * Convenience function to swap objects. * @param o1 to swap. * @param o2 to swap. */ template inline void swap(T& o1, T& o2) { cpr_memswap(&o1, &o2, sizeof(T)); } /** * Convenience function to check memory arrays. * @param pointer to validate. * @param base address of array. * @param count of objects. * @return true if in boundry. */ template inline bool bound(const T* pointer, const T* base, size_t count) { if(pointer < base || pointer >= &base[count]) return false; if(((size_t)pointer) % sizeof(T)) return false; return true; } /** * Convenience function to return max of two objects. * @param o1 to check. * @param o2 to check. * @return max object. */ template inline T& (max)(T& o1, T& o2) { return o1 > o2 ? o1 : o2; } /** * Convenience function to return min of two objects. * @param o1 to check. * @param o2 to check. * @return min object. */ template inline T& (min)(T& o1, T& o2) { return o1 < o2 ? o1 : o2; } /** * Convenience macro to range restrict values. * @param value to check. * @param low value. * @param high value. * @return adjusted value. */ template inline T& (limit)(T& value, T& low, T& high) { return (value < low) ? low : ((value > high) ? high : value); } /** * Convert a pointer to a reference with type checking. This is * mostly convenience for documenting behavior. * @param pointer to convert. * @return object reference. */ template inline T& deref_pointer(T *pointer) { return *pointer; } } // namespace ucommon #endif ucommon-6.4.4/inc/Makefile.in0000664000175000017500000004743312557431663012772 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015 Cherokees of Idaho. # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = inc DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/ucommon-config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CHECKFLAGS = @CHECKFLAGS@ CMAKE_CURRENT_SOURCE_DIR = @CMAKE_CURRENT_SOURCE_DIR@ CMAKE_INSTALL_FULL_DATADIR = @CMAKE_INSTALL_FULL_DATADIR@ CMAKE_INSTALL_FULL_INCLUDEDIR = @CMAKE_INSTALL_FULL_INCLUDEDIR@ CMAKE_INSTALL_FULL_LIBDIR = @CMAKE_INSTALL_FULL_LIBDIR@ CMAKE_INSTALL_PREFIX = @CMAKE_INSTALL_PREFIX@ COMPAT = @COMPAT@ COMPAT_CONFIG = @COMPAT_CONFIG@ COMPAT_PC = @COMPAT_PC@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_VERSION = @LT_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MODULE_FLAGS = @MODULE_FLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OPENSSL_CFLAGS = @OPENSSL_CFLAGS@ OPENSSL_LIBS = @OPENSSL_LIBS@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PKG_SECURE_LIBS = @PKG_SECURE_LIBS@ PKG_UCOMMON_FLAGS = @PKG_UCOMMON_FLAGS@ PKG_UCOMMON_INCLUDES = @PKG_UCOMMON_INCLUDES@ PKG_UCOMMON_LIBS = @PKG_UCOMMON_LIBS@ RANLIB = @RANLIB@ SECURE = @SECURE@ SECURE_LIBS = @SECURE_LIBS@ SECURE_LOCAL = @SECURE_LOCAL@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ UCOMMON_CFGPATH = @UCOMMON_CFGPATH@ UCOMMON_FLAGS = @UCOMMON_FLAGS@ UCOMMON_INCLUDES = @UCOMMON_INCLUDES@ UCOMMON_LIBC = @UCOMMON_LIBC@ UCOMMON_LIBS = @UCOMMON_LIBS@ UCOMMON_LINKED = @UCOMMON_LINKED@ UCOMMON_LOCALE = @UCOMMON_LOCALE@ UCOMMON_PREFIX = @UCOMMON_PREFIX@ UCOMMON_VARPATH = @UCOMMON_VARPATH@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ includes = @includes@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ libs = @libs@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ MAINTAINERCLEANFILES = Makefile.in Makefile RELEASE = $(LT_VERSION) -release $(LT_RELEASE) AM_CXXFLAGS = $(UCOMMON_FLAGS) SUBDIRS = ucommon commoncpp all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu inc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu inc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ucommon-6.4.4/inc/Makefile.am0000664000175000017500000000123112504226266012734 00000000000000# Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015 Cherokees of Idaho. # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. MAINTAINERCLEANFILES = Makefile.in Makefile RELEASE = $(LT_VERSION) -release $(LT_RELEASE) AM_CXXFLAGS = $(UCOMMON_FLAGS) SUBDIRS = ucommon commoncpp ucommon-6.4.4/inc/commoncpp/0000775000175000017500000000000012557440653012764 500000000000000ucommon-6.4.4/inc/commoncpp/exception.h0000644000175000001440000001035512504227271015040 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file commoncpp/exception.h * @short GNU Common C++ exception model base classes. **/ #ifndef COMMONCPP_EXCEPTION_H_ #define COMMONCPP_EXCEPTION_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_STRING_H_ #include #endif // see if we support useful and std exception handling, else we ignore // it for the rest of the system. #if defined(CCXX_EXCEPTIONS) #define COMMONCPP_EXCEPTIONS #include #include namespace ost { /** * Mainline exception handler, this is the root for all Common C++ * exceptions and assures the ansi C++ exception class hierarchy is both * followed and imported into the gnu Common C++ class hierarchy. * * @author David Sugar * @short Base exception class for all Common C++ exceptions. */ class __EXPORT Exception : public std::exception { private: String _what; public: Exception(const String& what_arg) throw(); virtual ~Exception() throw(); virtual const char *getString() const; virtual const char *what() const throw(); }; /** * A sub-hierarchy for all Common C++ I/O related classes. * * @author David Sugar * @short I/O operation exception hierarchy. */ class __EXPORT IOException : public Exception { private: long _systemError; mutable char* _systemErrorString; public: IOException(const String &what_arg, long systemError = 0) throw(); virtual ~IOException() throw(); virtual long getSystemError() const throw(); virtual const char* getSystemErrorString() const throw(); }; /** * A sub-hierarchy for thread exceptions. * * @author David Sugar * @short thread exception hierarchy. */ class __EXPORT ThrException : public Exception { public: inline ThrException(const String &what_arg) : Exception(what_arg) {} }; /** * A sub-hierarchy for all task synchronizion related exceptions. * * @author David Sugar * @short Synchronization object exception hierarchy. */ class __EXPORT SyncException : public ThrException { public: inline SyncException(const String &what_arg) : ThrException(what_arg) {} }; class __EXPORT InterruptException : public ThrException { public: inline InterruptException() : ThrException("interrupted") {} }; } // namespace ost #endif #endif ucommon-6.4.4/inc/commoncpp/thread.h0000644000175000001440000006260712504227626014324 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 3 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file commoncpp/thread.h * @short Common C++ thread class and sychronization objects **/ #ifndef COMMONCPP_THREAD_H_ #define COMMONCPP_THREAD_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_STRING_H_ #include #endif #define ENTER_CRITICAL enterMutex(); #define LEAVE_CRITICAL leaveMutex(); #include namespace ost { class __EXPORT Mutex : protected ucommon::RecursiveMutex { public: inline Mutex() : RecursiveMutex() {} inline void enterMutex(void) {RecursiveMutex::lock();} inline void leaveMutex(void) {RecursiveMutex::release();} inline bool tryEnterMutex(void) {return RecursiveMutex::lock(0l);} inline void enter(void) {RecursiveMutex::lock();} inline void leave(void) {RecursiveMutex::release();} inline bool test(void) {return RecursiveMutex::lock(0l);} }; /** * The Mutex Counter is a counter variable which can safely be incremented * or decremented by multiple threads. A Mutex is used to protect access * to the counter variable (an integer). An initial value can be specified * for the counter, and it can be manipulated with the ++ and -- operators. * * @author David Sugar * @short Thread protected integer counter. */ class __EXPORT MutexCounter : public Mutex { protected: volatile int counter; public: /** * Create and optionally name a mutex protected counter. */ MutexCounter(); /** * Create and optionally name a mutex protected counter with * an initial value. * * @param initial value of counter. */ MutexCounter(int initial); int operator++(); int operator--(); }; /** * The MutexLock class is used to protect a section of code so that at any * given time only a single thread can perform the protected operation. * * It use Mutex to protect operation. Using this class is usefull and * exception safe. The mutex that has been locked is automatically * released when the function call stack falls out of scope, so one doesnt * have to remember to unlock the mutex at each function return. * * A common use is * * void func_to_protect() * { * MutexLock lock(mutex); * ... operation ... * } * * NOTE: do not declare variable as "MutexLock (mutex)", the mutex will be * released at statement end. * * @author Frediano Ziglio * @short Mutex automatic locker for protected access. */ class __EXPORT MutexLock { private: Mutex& mutex; public: /** * Acquire the mutex * * @param _mutex reference to mutex to aquire. */ inline MutexLock( Mutex& _mutex ) : mutex( _mutex ) { mutex.enterMutex(); } /** * Release the mutex automatically */ // this should be not-virtual inline ~MutexLock() { mutex.leaveMutex(); } }; class __EXPORT ThreadLock : protected ucommon::ThreadLock { public: inline ThreadLock() : ucommon::ThreadLock() {} inline void readLock(void) {ucommon::ThreadLock::access();} inline void writeLock(void) {ucommon::ThreadLock::modify();} inline void tryReadLock(void) {ucommon::ThreadLock::access(0);} inline void tryWriteLock(void) {ucommon::ThreadLock::modify(0);} inline void unlock(void) {ucommon::ThreadLock::release();} }; /** * The ReadLock class is used to protect a section of code through * a ThreadLock for "read" access to the member function. The * ThreadLock is automatically released when the object falls out of * scope. * * A common use is * * void func_to_protect() * { * ReadLock lock(threadlock); * ... operation ... * } * * NOTE: do not declare variable as "ReadLock (threadlock)", the * mutex will be released at statement end. * * @author David Sugar * @short Read mode automatic locker for protected access. */ class __EXPORT ReadLock { private: ThreadLock& tl; public: /** * Wait for read access * * @param _tl reference to lock to aquire. */ inline ReadLock( ThreadLock& _tl ) : tl( _tl ) { tl.readLock(); } /** * Post the semaphore automatically */ // this should be not-virtual inline ~ReadLock() { tl.unlock(); } }; /** * The WriteLock class is used to protect a section of code through * a ThreadLock for "write" access to the member function. The * ThreadLock is automatically released when the object falls out of * scope. * * A common use is * * void func_to_protect() * { * WriteLock lock(threadlock); * ... operation ... * } * * NOTE: do not declare variable as "WriteLock (threadlock)", the * mutex will be released at statement end. * * @author David Sugar * @short Read mode automatic locker for protected access. */ class __EXPORT WriteLock { private: ThreadLock& tl; public: /** * Wait for write access * * @param _tl reference to threadlock to aquire. */ inline WriteLock( ThreadLock& _tl ) : tl( _tl ) { tl.writeLock(); } /** * Post the semaphore automatically */ // this should be not-virtual inline ~WriteLock() { tl.unlock(); } }; class __EXPORT Conditional : private ucommon::Conditional { public: inline Conditional() : ucommon::Conditional() {} bool wait(timeout_t timeout, bool locked = false); void signal(bool broadcast); inline void enterMutex(void) {ucommon::Conditional::lock();} inline void leaveMutex(void) {ucommon::Conditional::unlock();} }; class __EXPORT Semaphore : private ucommon::Semaphore { public: inline Semaphore(unsigned size = 0) : ucommon::Semaphore(size) {} inline bool wait(timeout_t timeout) {return ucommon::Semaphore::wait(timeout);} inline void wait(void) {ucommon::Semaphore::wait();} inline void post(void) {ucommon::Semaphore::release();} }; /** * The SemaphoreLock class is used to protect a section of code through * a semaphore so that only x instances of the member function may * execute concurrently. * * A common use is * * void func_to_protect() * { * SemaphoreLock lock(semaphore); * ... operation ... * } * * NOTE: do not declare variable as "SemaohoreLock (semaphore)", the * mutex will be released at statement end. * * @author David Sugar * @short Semaphore automatic locker for protected access. */ class __EXPORT SemaphoreLock { private: Semaphore& sem; public: /** * Wait for the semaphore */ inline SemaphoreLock( Semaphore& _sem ) : sem( _sem ) { sem.wait(); } /** * Post the semaphore automatically */ // this should be not-virtual inline ~SemaphoreLock() { sem.post(); } }; class __EXPORT Event : private ucommon::TimedEvent { public: inline Event() : ucommon::TimedEvent() {} inline void wait(void) {ucommon::TimedEvent::wait();} inline bool wait(timeout_t timeout) {return ucommon::TimedEvent::wait(timeout);} inline void signal(void) {ucommon::TimedEvent::signal();} inline void reset(void) {ucommon::TimedEvent::reset();} inline void set(timeout_t timeout = 0) {ucommon::TimedEvent::set(timeout);} }; class __EXPORT Thread : protected ucommon::JoinableThread { public: /** * How to raise error */ typedef enum Throw { throwNothing, /**< continue without throwing error */ throwObject, /**< throw object that cause error (throw this) */ throwException /**< throw an object relative to error */ } Throw; private: friend class Slog; Throw exceptions; bool detached, terminated; Thread *parent; size_t msgpos; char msgbuf[128]; public: Thread(int pri = 0, size_t stack = 0); virtual ~Thread(); inline void map(void) {JoinableThread::map();} virtual void initial(void); virtual void notify(Thread *thread); virtual void final(void); virtual void run(void) = 0; void terminate(void); void finalize(void); void detach(void); void start(void); void exit(void); inline void join(void) {JoinableThread::join();} inline void sync(void) {Thread::exit();} static inline Thread *get(void) {return (Thread *)JoinableThread::get();} inline static void yield(void) {ucommon::Thread::yield();} inline static void sleep(timeout_t msec = TIMEOUT_INF) {ucommon::Thread::sleep(msec);} bool isRunning(void); bool isThread(void); /** * Get exception mode of the current thread. * * @return exception mode. */ static Throw getException(void); /** * Set exception mode of the current thread. * * @return exception mode. */ static void setException(Throw mode); /** * Get the thread id. */ inline pthread_t getId(void) {return tid;} }; /** * This class is used to access non-reentrant date and time functions in the * standard C library. * * The class has two purposes: * - 1 To be used internaly in CommonCpp's date and time classes to make them * thread safe. * - 2 To be used by clients as thread safe replacements to the standard C * functions, much like Thread::sleep() represents a thread safe version * of the standard sleep() function. * * @note The class provides one function with the same name as its equivalent * standard function and one with another, unique name. For new clients, * the version with the unique name is recommended to make it easy to * grep for accidental usage of the standard functions. The version with * the standard name is provided for existing clients to sed replace their * original version. * * @note Also note that some functions that returned pointers have been redone * to take that pointer as an argument instead, making the caller * responsible for memory allocation/deallocation. This is almost * how POSIX specifies *_r functions (reentrant versions of the * standard time functions), except the POSIX functions also return the * given pointer while we do not. We don't use the *_r functions as they * aren't all generally available on all platforms yet. * * @author Idar Tollefsen * @short Thread safe date and time functions. */ class __EXPORT SysTime { public: static time_t getTime(time_t *tloc = NULL); static time_t time(time_t *tloc) {return getTime(tloc);} static int getTimeOfDay(struct timeval *tp); static int gettimeofday(struct timeval *tp, struct timezone *) {return getTimeOfDay(tp);} static struct tm *getLocalTime(const time_t *clock, struct tm *result); static struct tm *locatime(const time_t *clock, struct tm *result) {return getLocalTime(clock, result);} static struct tm *getGMTTime(const time_t *clock, struct tm *result); static struct tm *gmtime(const time_t *clock, struct tm *result) {return getGMTTime(clock, result);} }; /** * Timer ports are used to provide synchronized timing events when managed * under a "service thread" such as SocketService. This is made into a * stand-alone base class since other derived libraries (such as the * serial handlers) may also use the pooled "service thread" model * and hence also require this code for managing timing. * * @author David Sugar * @short synchronized millisecond timing for service threads. */ class __EXPORT TimerPort { #ifndef _MSWINDOWS_ struct timeval timer; #else DWORD timer; #endif bool active; public: /** * Create a timer, mark it as inactive, and set the initial * "start" time to the creation time of the timer object. This * allows "incTimer" to initially refer to time delays relative * to the original start time of the object. */ TimerPort(); /** * Set a new start time for the object based on when this call is * made and optionally activate the timer for a specified number * of milliseconds. This can be used to set the starting time * of a realtime session. * * @param timeout delay in milliseconds from "now" */ void setTimer(timeout_t timeout = 0); /** * Set a timeout based on the current time reference value either * from object creation or the last setTimer(). This reference * can be used to time synchronize realtime data over specified * intervals and force expiration when a new frame should be * released in a synchronized manner. * * @param timeout delay in milliseconds from reference. */ void incTimer(timeout_t timeout); /** * Adjust a timeout based on the current time reference value either * from object creation or the last setTimer(). This reference * can be used to time synchronize realtime data over specified * intervals and force expiration when a new frame should be * released in a synchronized manner. * * @param timeout delay in milliseconds from reference. */ void decTimer(timeout_t timeout); /** * Sleep until the current timer expires. This is useful in time * syncing realtime periodic tasks. */ void sleepTimer(void); /** * This is used to "disable" the service thread from expiring * the timer object. It does not effect the reference time from * either creation or a setTimer(). */ void endTimer(void); /** * This is used by service threads to determine how much time * remains before the timer expires based on a timeout specified * in setTimer() or incTimer(). It can also be called after * setting a timeout with incTimer() to see if the current timeout * has already expired and hence that the application is already * delayed and should skip frame(s). * * return time remaining in milliseconds, or TIMEOUT_INF if * inactive. */ timeout_t getTimer(void) const; /** * This is used to determine how much time has elapsed since a * timer port setTimer benchmark time was initially set. This * allows one to use setTimer() to set the timer to the current * time and then measure elapsed time from that point forward. * * return time elapsed in milliseconds, or TIMEOUT_INF if * inactive. */ timeout_t getElapsed(void) const; }; #ifndef _MSWINDOWS_ struct timespec *getTimeout(struct timespec *spec, timeout_t timeout); #endif #if !defined(_MSWINDOWS_) || defined(_MSTHREADS_) inline struct tm *localtime_r(const time_t *t, struct tm *b) {return SysTime::getLocalTime(t, b);} inline char *ctime_r(const time_t *t, char *buf) {return ctime(t);} inline struct tm *gmtime_r(const time_t *t, struct tm *b) {return SysTime::getGMTTime(t, b);} inline char *asctime_r(const struct tm *tm, char *b) {return asctime(tm);} #endif inline Thread *getThread(void) {return Thread::get();} /** * The buffer class represents an IPC service that is built upon a buffer * of fixed capacity that can be used to transfer objects between one or * more producer and consumer threads. Producer threads post objects * into the buffer, and consumer threads wait for and receive objects from * the buffer. Semaphores are used to to block the buffer from overflowing * and indicate when there is data available, and mutexes are used to protect * multiple consumers and producer threads from stepping over each other. * * The buffer class is an abstract class in that the actual data being * buffered is not directly specified within the buffer class itself. The * buffer class should be used as a base class for a class that actually * impliments buffering and which may be aware of the data types actually * are being buffered. A template class could be created based on buffer * for this purpose. Another possibility is to create a class derived * from both Thread and Buffer which can be used to implement message passing * threads. * * @author David Sugar * @short Producer/Consumer buffer for use between threads. */ #ifdef _MSWINDOWS_ class __EXPORT Buffer : public Mutex #else class __EXPORT Buffer : public Conditional #endif { private: #ifdef _MSWINDOWS_ HANDLE sem_head, sem_tail; #endif size_t _size; size_t _used; protected: /** * Invoke derived class buffer peeking method. * @return size of object found. * @param buf pointer to copy contents of head of buffer to. */ virtual size_t onPeek(void *buf) = 0; /** * Invoke derived class object request from buffer. * @return size of object returned. * @param buf pointer to hold object returned from the buffer. */ virtual size_t onWait(void *buf) = 0; /** * Invoke derived class posting of object to buffer. * @return size of object posted. * @param buf pointer to object being posted to the buffer. */ virtual size_t onPost(void *buf) = 0; public: /** * value to return when a timed operation returned with a * timeout. */ static const size_t timeout; /** * Create a buffer object of known capacity. * @param capacity is the integer capacity of the buffer. */ Buffer(size_t capacity); /** * In derived functions, may be used to free the actual memory * used to hold buffered data. */ virtual ~Buffer(); /** * Return the capacity of the buffer as specified at creation. * @return size of buffer. */ inline size_t getSize(void) {return _size;} /** * Return the current capacity in use for the buffer. Free space * is technically getSize() - getUsed(). * @return integer used capacity of the buffer. * @see #getSize */ inline size_t getUsed(void) {return _used;} /** * Let one or more threads wait for an object to become available * in the buffer. The waiting thread(s) will wait forever if no * object is ever placed into the buffer. * * @return size of object passed by buffer in bytes. * @param buf pointer to store object retrieved from the buffer. * @param timeout time to wait. */ size_t wait(void *buf, timeout_t timeout = 0); /** * Post an object into the buffer and enable a waiting thread to * receive it. * * @return size of object posted in bytes. * @param buf pointer to object to store in the buffer. * @param timeout time to wait. */ size_t post(void *buf, timeout_t timeout = 0); /** * Peek at the current content (first object) in the buffer. * * @return size of object in the buffer. * @param buf pointer to store object found in the buffer. */ size_t peek(void *buf); /** * New virtual to test if buffer is a valid object. * @return true if object is valid. */ virtual bool isValid(void); }; /** * A buffer class that holds a known capacity of fixed sized objects defined * during creation. * * @author David Sugar * @short producer/consumer buffer for fixed size objects. */ class __EXPORT FixedBuffer : public Buffer { private: char *buf, *head, *tail; size_t objsize; protected: /** * Return the first object in the buffer. * @return predefined size of this buffers objects. * @param buf pointer to copy contents of head of buffer to. */ size_t onPeek(void *buf); /** * Wait for and return a fixed object in the buffer. * @return predefined size of this buffers objects. * @param buf pointer to hold object returned from the buffer. */ size_t onWait(void *buf); /** * Post an object of the appropriate size into the buffer. * @return predefined size of this buffers objects. * @param buf pointer to data to copy into the buffer. */ size_t onPost(void *buf); public: /** * Create a buffer of known capacity for objects of a specified * size. * * @param capacity of the buffer. * @param objsize for each object held in the buffer. */ FixedBuffer(size_t capacity, size_t objsize); /** * Create a copy of an existing fixed size buffer and duplicate * it's contents. * * @param fb existing FixedBuffer object. */ FixedBuffer(const FixedBuffer &fb); /** * Destroy the fixed buffer and free the memory used to store objects. */ virtual ~FixedBuffer(); FixedBuffer &operator=(const FixedBuffer &fb); bool isValid(void); }; /** * Somewhat generic queue processing class to establish a producer * consumer queue. This may be used to buffer cdr records, or for * other purposes where an in-memory queue is needed for rapid * posting. This class is derived from Mutex and maintains a linked * list. A thread is used to dequeue data and pass it to a callback * method that is used in place of "run" for each item present on the * queue. The conditional is used to signal the run thread when new * data is posted. * * This class was changed by Angelo Naselli to have a timeout on the queue * * @short in memory data queue interface. * @author David Sugar */ class __EXPORT ThreadQueue : public Mutex, public Thread, public Semaphore { private: void run(void); // private run method protected: typedef struct _data { struct _data *next; unsigned len; char data[1]; } data_t; timeout_t timeout; bool started; data_t *first, *last; // head/tail of list String name; /* * Overloading of final(). It demarks Semaphore to avoid deadlock. */ virtual void final(); /** * Start of dequeing. Maybe we need to connect a database * or something, so we have a virtual... */ virtual void startQueue(void); /** * End of dequeing, we expect the queue is empty for now. Maybe * we need to disconnect a database or something, so we have * another virtual. */ virtual void stopQueue(void); /** * A derivable method to call when the timout is expired. */ virtual void onTimer(void); /** * Virtual callback method to handle processing of a queued * data items. After the item is processed, it is deleted from * memory. We can call multiple instances of runQueue in order * if multiple items are waiting. * * @param data item being dequed. */ virtual void runQueue(void *data) = 0; public: /** * Create instance of our queue and give it a process priority. * * @param id queue ID. * @param pri process priority. * @param stack stack size. */ ThreadQueue(const char *id, int pri, size_t stack = 0); /** * Destroy the queue. */ virtual ~ThreadQueue(); /** * Set the queue timeout. * When the timer expires, the onTimer() method is called * for the thread * * @param timeout timeout in milliseconds. */ void setTimer(timeout_t timeout); /** * Put some unspecified data into this queue. A new qd * structure is created and sized to contain a copy of * the actual content. * * @param data pointer to data. * @param len size of data. */ void post(const void *data, unsigned len); }; /** @relates Buffer */ inline size_t get(Buffer &b, void *o, timeout_t t = 0) {return b.wait(o, t);} /** @relates Buffer */ inline size_t put(Buffer &b, void *o, timeout_t t = 0) {return b.post(o, t);} /** @relates Buffer */ inline size_t peek(Buffer &b, void *o) {return b.peek(o);} } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/object.h0000664000175000017500000003704412540267205014323 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file object.h * @short Some object manipulation classes for smart pointers, linked lists, * etc. **/ #ifndef COMMONCPP_OBJECT_H_ #define COMMONCPP_OBJECT_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif namespace ost { class MapObject; class MapIndex; /** * A reference countable object. This is used in association with smart * pointers (RefPointer). * * @author David Sugar * @short Object managed by smart pointer reference count. */ class __EXPORT RefObject { protected: friend class RefPointer; unsigned refCount; /** * The constructor simply initializes the count. */ inline RefObject() { refCount = 0; } /** * The destructor is called when the reference count returns * to zero. This is done through a virtual destructor. */ virtual ~RefObject(); public: /** * The actual object being managed can be returned by this * method as a void and then recast to the actual type. This * removes the need to dynamic cast from RefObject and the * dependence on rtti this implies. * * @return underlying object being referenced. */ virtual void *getObject(void) = 0; }; /** * Pointer to reference counted objects. This is a non-template form * of a reference count smart pointer, and so uses common code. This * can be subclassed to return explicit object types. * * @author David Sugar * @short Pointer to reference count managed objects. */ class __EXPORT RefPointer { protected: RefObject *ref; /** * Detach current object, for example, when changing pointer. */ void detach(void); /** * Patch point for mutex in derived class. This may often * be a single static mutex shared by a managed type. */ virtual void enterLock(void); /** * Patch point for a mutex in derived class. This may often * be a single static mutex shared by a managed type. */ virtual void leaveLock(void); public: /** * Create an unattached pointer. */ inline RefPointer() { ref = NULL; } /** * Create a pointer attached to a reference counted object. * * Object being referenced. */ RefPointer(RefObject *obj); /** * A copy constructor. * * Pointer being copied. */ RefPointer(const RefPointer &ptr); virtual ~RefPointer(); RefPointer& operator=(const RefObject &ref); inline void *operator*() const { return getObject(); } void *getObject(void) const; bool operator!() const; }; /** * Self managed single linked list object chain. This is used for * accumulating lists by using as a base class for a derived subclass. * * @author David Sugar * @short Accumulating single linked list. */ class __EXPORT LinkedSingle { protected: LinkedSingle *nextObject; inline LinkedSingle() { nextObject = NULL; } virtual ~LinkedSingle(); public: /** * Get first linked object in list. This may be dynamically * recast, and may refer to a master static bookmark pointer * in a derived class. Otherwise it simply returns the current * object. In a "free" list, this may not only return the first * object, but also set the first to next. * * @return pointer to first object in list. */ virtual LinkedSingle *getFirst(void); /** * Gets the last object in the list. This normally follows the * links to the end. This is a virtual because derived class * may include a static member bookmark for the current end. * * @return pointer to last object in list. */ virtual LinkedSingle *getLast(void); /** * Get next object, for convenience. Derived class may use * this with a dynamic cast. * * @return next object in list. */ inline LinkedSingle *getNext(void) { return nextObject; } /** * Insert object into chain. This is a virtual because * derived class may choose instead to perform an insert * at head or tail, may manage bookmarks, and may add mutex lock. * * @param object being inserted. */ virtual void insert(LinkedSingle& obj); LinkedSingle &operator+=(LinkedSingle &obj); }; /** * Self managed double linked list object chain. This is used for * accumulating lists by using as a base class for a derived subclass. * * @author David Sugar * @short Accumulating double linked list. */ class __EXPORT LinkedDouble { protected: LinkedDouble *nextObject, *prevObject; inline LinkedDouble() { nextObject = prevObject = NULL; } virtual ~LinkedDouble(); virtual void enterLock(void); virtual void leaveLock(void); virtual LinkedDouble *firstObject(); virtual LinkedDouble *lastObject(); public: /** * Requested in overloaded insert() method to indicate how to insert * data into list */ enum InsertMode { modeAtFirst, /**< insert at first position in list pointed by current object */ modeAtLast, /**< insert at last position in list pointed by current object */ modeBefore, /**< insert in list before current object */ modeAfter /**< insert in list after current object */ }; /** * Get first linked object in list. This may be dynamically * recast, and may refer to a master static bookmark pointer * in a derived class. Otherwise it follows list to front. * * @return pointer to first object in list. */ virtual LinkedDouble *getFirst(void); /** * Gets the last object in the list. This normally follows the * links to the end. This is a virtual because derived class * may include a static member bookmark for the current end. * * @return pointer to last object in list. */ virtual LinkedDouble *getLast(void); /** * Virtual to get the insert point to use when adding new members. This * may be current, or always head or always tail. As a virtual, this allows * derived class to establish "policy". * * @return pointer to insertion point in list. */ virtual LinkedDouble *getInsert(void); /** * Get next object, for convenience. Derived class may use * this with a dynamic cast. * * @return next object in list. */ inline LinkedDouble *getNext(void) { return nextObject; } /** * Get prev object in the list. * * @return pointer to previous object. */ inline LinkedDouble *getPrev(void) { return prevObject; } /** * Insert object into chain at given pos, as indicated by \ref InsertMode; * If no pos is given, it defaults to \ref modeAtLast, inserting element * at list's end. * * @param object being inserted. * @param position where object is inserted. */ virtual void insert(LinkedDouble& obj, InsertMode position = modeAtLast); /** * Remove object from chain. */ virtual void detach(void); LinkedDouble &operator+=(LinkedDouble &obj); LinkedDouble &operator--(); }; /** * A map table allows for entities to be mapped (hash index) onto it. * Unlike with Assoc, This form of map table also allows objects to be * removed from the table. This table also includes a mutex lock for * thread safety. A free list is also optionally maintained for reusable * maps. * * @author David Sugar * @short Table to hold hash indexed objects. */ class __EXPORT MapTable : public Mutex { protected: friend class MapObject; friend class MapIndex; unsigned range; unsigned count; MapObject **map; void cleanup(void); public: /** * Create a map table with a specified number of slots. * * @param number of slots. */ MapTable(unsigned size); /** * Destroy the table, calls cleanup. */ virtual ~MapTable(); /** * Get index value from id string. This function can be changed * as needed to provide better collision avoidence for specific * tables. * * @param id string * @return index slot in table. */ virtual unsigned getIndex(const char *id); /** * Return range of this table. * * @return table range. */ inline unsigned getRange(void) { return range; } /** * Return the number of object stored in this table. * * @return table size. */ inline unsigned getSize(void) { return count; } /** * Lookup an object by id key. It is returned as void * for * easy re-cast. * * @param key to find. * @return pointer to found object or NULL. */ void *getObject(const char *id); /** * Map an object to our table. If it is in another table * already, it is removed there first. * * @param object to map. */ void addObject(MapObject &obj); /** * Get the first element into table, it is returned as void * for * easy re-cast. * * @return pointer to found object or NULL. */ void *getFirst(); /** * Get the last element into table, it is returned as void * for * easy re-cast. * * @return pointer to found object or NULL. */ void *getLast(); /** * Get table's end, useful for cycle control; it is returned as void * for * easy re-cast. * * @return pointer to found object or NULL. */ void *getEnd() { return NULL; } /** * Get next object from managed free list. This returns as a * void so it can be recast into the actual type being used in * derived MapObject's. A derived version of MapTable may well * offer an explicit type version of this. Some derived * MapObject's may override new to use managed list. * * @return next object on free list. */ void *getFree(void); /** * Add an object to the managed free list. Some MapObject's * may override delete operator to detach and do this. * * @param object to add. */ void addFree(MapObject *obj); /** * An operator to map an object to the table. * * @return table being used. * @param object being mapped. */ MapTable &operator+=(MapObject &obj); /** * This operator is virtual in case it must also add the object to a * managed free list. * * @return current table. * @param object entity to remove. */ virtual MapTable &operator-=(MapObject &obj); }; /** * The MapIndex allows linear access into a MapTable, that otherwise could have * its elements being retrieved only by key. * It can be increased, checked and dereferenced like a pointer, by means of * suitable operators. * * @author Sergio Repetto * @short Index object to access MapTable elements */ class __EXPORT MapIndex { MapObject* thisObject; public : /** * Creates an empty map index (pointing to nothing). */ MapIndex() : thisObject(NULL) {} /** * Creates a map index pointing to a specific map object * * @param the indexed object */ MapIndex(MapObject* theObject) : thisObject(theObject) {} /** * Creates a copy of a given map index * * @param the source index object */ MapIndex(const MapIndex& theIndex) : thisObject(theIndex.thisObject) {} /** * Dereference operator: the pointed object it is returned as void * for * easy re-cast. * * @return pointer to indexed object. */ void* operator*() const { return (void*)thisObject; } /** * Assignment operator to avoid implicit cast. * * @return the object itself, as changed. */ MapIndex& operator=(MapObject *theObject); /** * Prefix increment operator, to be used in loops and such. * * @return the object itself, as changed. */ MapIndex& operator++(); // prefix /** * Postfix increment operator, to be used in loops and such. * * @return the object itself, as changed. */ MapIndex operator++(int) { // postfix return this->operator++(); } /** * Comparison operator, between two MapIndex's. * * @return the object itself, as changed. */ bool operator==(const MapIndex& theIndex) const { return thisObject == theIndex.thisObject; } bool operator!=(const MapIndex& theIndex) const { return !(*this == theIndex); } /** * Comparison operator, between the MapIndex and a MapObject, useful to avoid * casts for sake of clearness. * * @return the object itself, as changed. */ bool operator==(const MapObject* theObject) const { return thisObject == theObject; } bool operator!=(const MapObject* theObject) const { return !(*this == theObject); } }; /** * The MapObject is a base class which can be used to make a derived * class operate on a MapTable. Derived classes may override new and * delete operators to use managed free list from a MapTable. * * @author David Sugar * @short Mappable object. */ class __EXPORT MapObject { protected: friend class MapTable; friend class MapIndex; MapObject *nextObject; const char *idObject; MapTable *table; public: /** * Remove the object from it's current table. */ void detach(void); /** * Save id, mark as not using any table. * * @param id string for this object. */ MapObject(const char *id); }; } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/commoncpp.h0000644000175000001440000000507512504227215015036 00000000000000// Copyright (C) 2009-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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 COMMONCPP_COMMONCPP_H_ #define COMMONCPP_COMMONCPP_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef UCOMMON_SYSRUNTIME #include #endif #endif ucommon-6.4.4/inc/commoncpp/serial.h0000644000175000001440000006015412504227445014326 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file serial.h * @short Serial I/O services. **/ #ifndef COMMONCPP_SERIAL_H_ #define COMMONCPP_SERIAL_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_THREAD_H_ #include #endif #ifndef COMMMONCPP_EXCEPTION_H_ #include #endif namespace ost { /** * The Serial class is used as the base for all serial I/O services * under APE. A serial is a system serial port that is used either * for line or packet based data input. Serial ports may also be * "streamable" in a derived form. * * Common C++ serial I/O classes are used to manage serial devices and * implement serial device protocols. From the point of view of Common C++, * serial devices are supported by the underlying Posix specified "termios" * call interface. * * The serial I/O base class is used to hold a descriptor to a serial device * and to provide an exception handling interface for all serial I/O classes. * The base class is also used to specify serial I/O properties such as * communication speed, flow control, data size, and parity. The "Serial" * base class is not itself directly used in application development, * however. * * Common C++ Serial I/O is itself divided into two conceptual modes; frame * oriented and line oriented I/O. Both frame and line oriented I/O makes * use of the ability of the underlying tty driver to buffer data and return * "ready" status from when select either a specified number of bytes or * newline record has been reached by manipulating termios c_cc fields * appropriately. This provides some advantage in that a given thread * servicing a serial port can block and wait rather than have to continually * poll or read each and every byte as soon as it appears at the serial port. * * @author David Sugar * @short base class for all serial I/O services. */ class __EXPORT Serial { public: enum Error { errSuccess = 0, errOpenNoTty, errOpenFailed, errSpeedInvalid, errFlowInvalid, errParityInvalid, errCharsizeInvalid, errStopbitsInvalid, errOptionInvalid, errResourceFailure, errOutput, errInput, errTimeout, errExtended }; typedef enum Error Error; enum Flow { flowNone, flowSoft, flowHard, flowBoth }; typedef enum Flow Flow; enum Parity { parityNone, parityOdd, parityEven }; typedef enum Parity Parity; enum Pending { pendingInput, pendingOutput, pendingError }; typedef enum Pending Pending; private: Error errid; char *errstr; struct { bool thrown: 1; bool linebuf: 1; } flags; void *original; void *current; /** * Used to properly initialize serial object. */ void initSerial(void); protected: fd_t dev; int bufsize; /** * Opens the serial device. * * @param fname Pathname of device to open */ void open(const char *fname); /** * Closes the serial device. * */ void close(void); /** * Reads from serial device. * * @param Data Point to character buffer to receive data. Buffers MUST * be at least Length + 1 bytes in size. * @param Length Number of bytes to read. */ virtual int aRead(char * Data, const int Length); /** * Writes to serial device. * * @param Data Point to character buffer containing data to write. Buffers MUST * @param Length Number of bytes to write. */ virtual int aWrite(const char * Data, const int Length); /** * This service is used to throw all serial errors which usually * occur during the serial constructor. * * @param error defined serial error id. * @param errstr string or message to optionally pass. */ Error error(Error error, char *errstr = NULL); /** * This service is used to thow application defined serial * errors where the application specific error code is a string. * * @param err string or message to pass. */ inline void error(char *err) {error(errExtended, err);} /** * This method is used to turn the error handler on or off for * "throwing" execptions by manipulating the thrown flag. * * @param enable true to enable handler. */ inline void setError(bool enable) {flags.thrown = !enable;} /** * Set packet read mode and "size" of packet read buffer. * This sets VMIN to x. VTIM is normally set to "0" so that * "isPending()" can wait for an entire packet rather than just * the first byte. * * @return actual buffer size set. * @param size of packet read request. * @param btimer optional inter-byte data packet timeout. */ int setPacketInput(int size, unsigned char btimer = 0); /** * Set "line buffering" read mode and specifies the newline * character to be used in seperating line records. isPending * can then be used to wait for an entire line of input. * * @param newline newline character. * @param nl1 EOL2 control character. * @return size of conical input buffer. */ int setLineInput(char newline = 13, char nl1 = 0); /** * Restore serial device to the original settings at time of open. */ void restore(void); /** * Used to flush the input waiting queue. */ void flushInput(void); /** * Used to flush any pending output data. */ void flushOutput(void); /** * Used to wait until all output has been sent. */ void waitOutput(void); /** * Used as the default destructor for ending serial I/O * services. It will restore the port to it's original state. */ void endSerial(void); /** * Used to initialize a newly opened serial file handle. You * should set serial properties and DTR manually before first * use. */ void initConfig(void); /** * This allows later ttystream class to open and close a serial * device. */ Serial() {initSerial();} /** * A serial object may be constructed from a named file on the * file system. This named device must be "isatty()". * * @param name of file. */ Serial(const char *name); public: /** * The serial base class may be "thrown" as a result on an error, * and the "catcher" may then choose to destory the object. By * assuring the socket base class is a virtual destructor, we * can assure the full object is properly terminated. */ virtual ~Serial(); /** * Serial ports may also be duplecated by the assignment * operator. */ Serial &operator=(const Serial &from); /** * Set serial port speed for both input and output. * * @return 0 on success. * @param speed to select. 0 signifies modem "hang up". */ Error setSpeed(unsigned long speed); /** * Set character size. * * @return 0 on success. * @param bits character size to use (usually 7 or 8). */ Error setCharBits(int bits); /** * Set parity mode. * * @return 0 on success. * @param parity mode. */ Error setParity(Parity parity); /** * Set number of stop bits. * * @return 0 on success. * @param bits stop bits. */ Error setStopBits(int bits); /** * Set flow control. * * @return 0 on success. * @param flow control mode. */ Error setFlowControl(Flow flow); /** * Set the DTR mode off momentarily. * * @param millisec number of milliseconds. */ void toggleDTR(timeout_t millisec); /** * Send the "break" signal. */ void sendBreak(void); /** * Often used by a "catch" to fetch the last error of a thrown * serial. * * @return error numbr of last Error. */ inline Error getErrorNumber(void) {return errid;} /** * Often used by a "catch" to fetch the user set error string * of a thrown serial. * * @return string for error message. */ inline char *getErrorString(void) {return errstr;} /** * Get the "buffer" size for buffered operations. This can * be used when setting packet or line read modes to determine * how many bytes to wait for in a given read call. * * @return number of bytes used for buffering. */ inline int getBufferSize(void) {return bufsize;} /** * Get the status of pending operations. This can be used to * examine if input or output is waiting, or if an error has * occured on the serial device. * * @return true if ready, false if timeout. * @param pend ready check to perform. * @param timeout in milliseconds. */ virtual bool isPending(Pending pend, timeout_t timeout = TIMEOUT_INF); }; /** * TTY streams are used to represent serial connections that are fully * "streamable" objects using C++ stream classes and friends. * * The first application relevant serial I/O class is the TTYStream class. * TTYStream offers a linearly buffered "streaming" I/O session with the * serial device. Furthermore, traditional C++ "stream" operators (<< and * >>) may be used with the serial device. A more "true" to ANSI C++ library * format "ttystream" is also available, and this supports an "open" method * in which one can pass initial serial device parameters immediately * following the device name in a single string, as in * "/dev/tty3a:9600,7,e,1", as an example. * * The TTYSession aggragates a TTYStream and a Common C++ Thread which is * assumed to be the execution context that will be used to perform actual * I/O operations. This class is very anagolous to TCPSession. * * * @author David Sugar * @short streamable tty serial I/O class. */ class __EXPORT TTYStream : protected std::streambuf, public Serial, public std::iostream { private: int doallocate(); friend TTYStream& crlf(TTYStream&); friend TTYStream& lfcr(TTYStream&); protected: char *gbuf, *pbuf; timeout_t timeout; /** * This constructor is used to derive "ttystream", a more * C++ style version of the TTYStream class. */ TTYStream(); /** * Used to allocate the buffer space needed for iostream * operations. This is based on MAX_INPUT. */ void allocate(void); /** * Used to terminate the buffer space and clean up the tty * connection. This function is called by the destructor. */ void endStream(void); /** * This streambuf method is used to load the input buffer * through the established tty serial port. * * @return char from get buffer, EOF also possible. */ int underflow(void); /** * This streambuf method is used for doing unbuffered reads * through the establish tty serial port when in interactive mode. * Also this method will handle proper use of buffers if not in * interative mode. * * @return char from tty serial port, EOF also possible. */ int uflow(void); /** * This streambuf method is used to write the output * buffer through the established tty port. * * @param ch char to push through. * @return char pushed through. */ int overflow(int ch); public: /** * Create and open a tty serial port. * * @param filename char name of device to open. * @param to default timeout. */ TTYStream(const char *filename, timeout_t to = 0); /** * End the tty stream and cleanup. */ virtual ~TTYStream(); /** * Set the timeout control. * * @param to timeout to use. */ inline void setTimeout(timeout_t to) {timeout = to;} /** * Set tty mode to buffered or "interactive". When interactive, * all streamed I/O is directly sent to the serial port * immediately. * * @param flag bool set to true to make interactive. */ void interactive(bool flag); /** * Flushes the stream input and out buffers, writes * pending output. * * @return 0 on success. */ int sync(void); /** * Get the status of pending operations. This can be used to * examine if input or output is waiting, or if an error has * occured on the serial device. If read buffer contains data * then input is ready and if write buffer contains data it is * first flushed then checked. * * @return true if ready, false if timeout. * @param pend ready check to perform. * @param timeout in milliseconds. */ bool isPending(Pending pend, timeout_t timeout = TIMEOUT_INF); }; /** * A more natural C++ "ttystream" class for use by non-threaded * applications. This class behaves a lot more like fstream and * similar classes. * * @author David Sugar * @short C++ "fstream" style ttystream class. */ class __EXPORT ttystream : public TTYStream { public: /** * Construct an unopened "ttystream" object. */ ttystream(); /** * Construct and "open" a tty stream object. A filename in * the form "device:options[,options]" may be used to pass * device options as part of the open. * * @param name of file and serial options. */ ttystream(const char *name); /** * Open method for a tty stream. * * @param name filename to open. */ void open(const char *name); /** * Close method for a tty stream. */ void close(void); /** * Test to see if stream is opened. */ inline bool operator!() {return (dev < 0);} }; /** * * The TTYSession aggragates a TTYStream and a Common C++ Thread which is * assumed to be the execution context that will be used to perform actual * I/O operations. This class is very anagolous to TCPSession. * * @author David Sugar * @short This class is very anagolous to TCPSession. */ class __EXPORT TTYSession : public Thread, public TTYStream { public: /** * Create TTY stream that will be managed by it's own thread. * * @param name of tty device to open. * @param pri execution priority. * @param stack allocation needed on some platforms. */ TTYSession(const char *name, int pri = 0, int stack = 0); virtual ~TTYSession(); }; #ifndef _MSWINDOWS_ // Not support this right now....... // class SerialPort; class SerialService; /** * The serial port is an internal class which is attached to and then * serviced by a specified SerialService thread. Derived versions of * this class offer specific functionality such as serial integration * protocols. * * The TTYPort and TTYService classes are used to form thread-pool serviced * serial I/O protocol sets. These can be used when one has a large number * of serial devices to manage, and a single (or limited number of) thread(s) * can then be used to service the tty port objects present. Each tty port * supports a timer control and several virtual methods that the service * thread can call when events occur. This model provides for "callback" * event management, whereby the service thread performs a "callback" into * the port object when events occur. Specific events supported include the * expiration of a TTYPort timer, pending input data waiting to be read, and * "sighup" connection breaks. * * * @author David Sugar * @short base class for thread pool serviced serial I/O. */ class __EXPORT SerialPort: public Serial, public TimerPort { private: SerialPort *next, *prev; SerialService *service; #ifdef USE_POLL struct pollfd *ufd; #endif bool detect_pending; bool detect_output; bool detect_disconnect; friend class SerialService; protected: /** * Construct a tty serial port for a named serial device. * * @param svc pool thread object. * @param name of tty port. */ SerialPort(SerialService *svc, const char *name); /** * Disconnect the Serial Port from the service pool thread * and shutdown the port. */ virtual ~SerialPort(); /** * Used to indicate if the service thread should monitor pending * data for us. */ void setDetectPending( bool ); /** * Get the current state of the DetectPending flag. */ inline bool getDetectPending( void ) const { return detect_pending; } /** * Used to indicate if output ready monitoring should be performed * by the service thread. */ void setDetectOutput( bool ); /** * Get the current state of the DetectOutput flag. */ inline bool getDetectOutput( void ) const { return detect_output; } /** * Called by the service thread when the objects timer * has expired. */ virtual void expired(void); /** * Called by the service thread when input data is pending * for this tty port. Effected by setPacketInput and by * setLineInput. */ virtual void pending(void); /** * Called by the service thread when an exception has occured * such as a hangup. */ virtual void disconnect(void); /** * Transmit "send" data to the serial port. This is not public * since it's meant to support internal protocols rather than * direct public access to the device. * * @return number of bytes send. * @param buf address of buffer to send. * @param len of bytes to send. */ inline int output(void *buf, int len) {return aWrite((char *)buf, len);} /** * Perform when output is available for sending data. */ virtual void output(void); /** * Receive "input" for pending data from the serial port. This * is not a public member since it's meant to support internal * protocols rather than direct external access to the device. * * @return number of bytes received. * @param buf address of buffer to input. * @param len of input buffer used. */ inline int input(void *buf, int len) {return aRead((char *)buf, len);} public: /** * Derived setTimer to notify the service thread pool of changes * in expected timeout. This allows SerialService to * reschedule all timers. * * @param timeout in milliseconds. */ void setTimer(timeout_t timeout = 0); /** * Derived incTimer to notify the service thread pool of a * change in expected timeout. This allows SerialService to * reschedule all timers. */ void incTimer(timeout_t timeout); }; /** * The SerialService is a thead service object that is meant to service * attached serial ports. Multiple pool objects may be created and * multiple serial ports may be attached to the same thread of * of execution. This allows one to balance threads and the serial ports * they service. * * The TTYPort and TTYService classes are used to form thread-pool serviced * serial I/O protocol sets. These can be used when one has a large number * of serial devices to manage, and a single (or limited number of) thread(s) * can then be used to service the tty port objects present. Each tty port * supports a timer control and several virtual methods that the service * thread can call when events occur. This model provides for "callback" * event management, whereby the service thread performs a "callback" into * the port object when events occur. Specific events supported include the * expiration of a TTYPort timer, pending input data waiting to be read, and * "sighup" connection breaks. * * * @author David Sugar * @short Thread pool service for serial ports. */ class __EXPORT SerialService : public Thread, private Mutex { private: fd_set connect; int iosync[2]; int hiwater; int count; SerialPort *first, *last; /** * Attach a new serial port to this service thread. * * @param port of SerialPort derived object to attach. */ void attach(SerialPort *port); /** * Detach a serial port from this service thread. * * @param port of SerialPort derived object to remove. */ void detach(SerialPort *port); /** * The service thread itself. */ void run(void); friend class SerialPort; protected: /** * A virtual handler for processing user defined update * requests (1-254) which have been posted through Update. * * @param flag of update request. */ virtual void onUpdate(unsigned char flag); /** * A virtual handler for event loop calls. This can be * used to extend event loop processing. */ virtual void onEvent(void); /** * A virtual handler for adding support for additional * callback events into SerialPort. * * @param port serial port currently being evaluated. */ virtual void onCallback(SerialPort *port); public: /** * Notify service thread that a port has been added or * removed, or a timer changed, so that a new schedule * can be computed for expiring attached ports. This * can also be used to pass requests to the OnUpdate() * event handler. * * @param flag event for OnUpdate, termination, or reschedule. */ void update(unsigned char flag = 0xff); /** * Create a service thread for attaching serial ports. The * thread begins execution with the first attached port. * * @param pri of this thread to run under. * @param stack stack size. * @param id stack ID. */ SerialService(int pri = 0, size_t stack = 0, const char *id = NULL); /** * Terminate the service thread and update attached objects. */ virtual ~SerialService(); /** * Get current reference count. This can be used when selecting * the lead used service handler from a pool. * * @return count of active ports. */ inline int getCount(void) {return count;} }; #endif #ifdef CCXX_EXCEPTIONS class __EXPORT SerException : public IOException { public: SerException(const String &str) : IOException(str) {} }; #endif } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/slog.h0000644000175000001440000002124412504227460014005 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file commoncpp/slog.h * @short System logging facilities abstraction. **/ #ifndef COMMONCPP_SLOG_H_ #define COMMONCPP_SLOG_H_ #include #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_STRING_H_ #include #endif #ifndef COMMONCPP_THREAD_H_ #include #endif namespace ost { /** * The slog class is used to stream messages to the system's logging facility (syslogd). * A default slog object is used to avoid confusion with the native syslog * facility and to imply a logical relationship to the C++ clog(). * * The key difference is that the slog object sends it's output to the * system logging daemon (typically syslogd) rather than through stderr. * slog can be streamed with the << operator just * like clog; a default slog object is pre-initialized, and you stream * character data to it. * * The slog allows one to specify logging levels and other properties through the () operators. * Hence, once can do: * *
 * slog("mydaemon", SLOG_DAEMON, SLOG_EMERGENCY) << I just died << endl; 
* * or things like: * *
 * slog("mydaemon", SLOG_DAEMON);
 * slog(SLOG_INFO) << "daemon initalized" << endl; 
* * The intent is to be as common-place and as convenient to use as the stderr based clog facility * found in C++, and this is especially useful for C++ daemons. * * The std::flush manipulator doesn't work. Either the * std::endl or std::ends manipulators * must be used to cause the output to be sent to the daemon. * * When this class is used on a system that doesn't have the syslog headers * (i.e. a non-posix win32 box), the output goes to the a file with the same name * as the syslog identifier string with '.log' appended to it. If the identifier string ends in * '.exe', the '.exe' is removed before the '.log' is appened. (e.g. the identifier foo.exe will * generate a log file named foo.log) * * @author David Sugar *
Minor docs & hacks by Jon Little * * @short system logging facility class. */ class __EXPORT Slog : protected std::streambuf, public std::ostream { public: typedef enum Class { classSecurity, classAudit, classDaemon, classUser, classDefault, classLocal0, classLocal1, classLocal2, classLocal3, classLocal4, classLocal5, classLocal6, classLocal7 } Class; typedef enum Level { levelEmergency = 1, levelAlert, levelCritical, levelError, levelWarning, levelNotice, levelInfo, levelDebug } Level; private: mutable pthread_mutex_t lock; FILE *syslog; int priority; Level _level; bool _enable; bool _clogEnable; protected: /** * This is the streambuf function that actually outputs the data * to the device. Since all output should be done with the standard * ostream operators, this function should never be called directly. */ int overflow(int c); public: /** * Default (and only) constructor. The default log level is set to * SLOG_DEBUG. There is no default log facility set. One should be * set before attempting any output. This is done by the open() or the * operator()(const char*, Class, Level) * functions. */ Slog(void); virtual ~Slog(void); void close(void); /** * (re)opens the output stream. * @param ident The identifier portion of the message sent to the syslog daemon. * @param grp The log facility the message is sent to */ void open(const char *ident, Class grp = classUser); /** * Sets the log identifier, level, and class to use for subsequent output * @param ident The identifier portion of the message * @param grp The log facility the message is sent to * @param level The log level of the message */ Slog &operator()(const char *ident, Class grp = classUser, Level level = levelError); /** * Changes the log level and class to use for subsequent output * @param level The log level of the message * @param grp The log facility the message is sent to */ Slog &operator()(Level level, Class grp = classDefault); /** * Does nothing except return *this. */ Slog &operator()(void); /** * Print a formatted syslog string. * * @param format string. */ void error(const char *format, ...); /** * Print a formatted syslog string. * * @param format string. */ void warn(const char *format, ...); /** * Print a formatted syslog string. * * @param format string. */ void debug(const char *format, ...); /** * Print a formatted syslog string. * * @param format string. */ void emerg(const char *format, ...); /** * Print a formatted syslog string. * * @param format string. */ void alert(const char *format, ...); /** * Print a formatted syslog string. * * @param format string. */ void critical(const char *format, ...); /** * Print a formatted syslog string. * * @param format string. */ void notice(const char *format, ...); /** * Print a formatted syslog string. * * @param format string. */ void info(const char *format, ...); /** * Sets the logging level. * @param enable is the logging level to use for further output */ inline void level(Level enable) {_level = enable;} /** * Enables or disables the echoing of the messages to clog in addition * to the syslog daemon. This is enabled by the default class constructor. * @param f true to enable, false to disable clog output */ inline void clogEnable(bool f=true) {_clogEnable = f;} inline Slog &warn(void) {return operator()(Slog::levelWarning);} inline Slog &error(void) {return operator()(Slog::levelError);} inline Slog &debug(void) {return operator()(Slog::levelDebug);} inline Slog &emerg(void) {return operator()(Slog::levelEmergency);} inline Slog &alert(void) {return operator()(Slog::levelAlert);} inline Slog &critical(void) {return operator()(Slog::levelCritical);} inline Slog ¬ice(void) {return operator()(Slog::levelNotice);} inline Slog &info(void) {return operator()(Slog::levelInfo);} }; extern __EXPORT Slog slog; } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/tcp.h0000664000175000017500000005072612544722221013643 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file commoncpp/tcp.h * @short tcp derived socket classes. **/ #ifndef COMMONCPP_TCP_H_ #define COMMONCPP_TCP_H_ #include #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_STRING_H_ #include #endif #ifndef COMMONCPP_ADDRESS_H_ #include #endif #ifndef COMMONCPP_SOCKET_H_ #include #endif namespace ost { /** * TCP sockets are used for stream based connected sessions between two * sockets. Both error recovery and flow control operate transparently * for a TCP socket connection. The TCP socket base class is primary used * to bind a TCP "server" for accepting TCP streams. * * An implicit and unique TCPSocket object exists in Common C++ to represent * a bound TCP socket acting as a "server" for receiving connection requests. * This class is not part of TCPStream because such objects normally perform * no physical I/O (read or write operations) other than to specify a listen * backlog queue and perform "accept" operations for pending connections. * The Common C++ TCPSocket offers a Peek method to examine where the next * pending connection is coming from, and a Reject method to flush the next * request from the queue without having to create a session. * * The TCPSocket also supports a "OnAccept" method which can be called when a * TCPStream related object is created from a TCPSocket. By creating a * TCPStream from a TCPSocket, an accept operation automatically occurs, and * the TCPSocket can then still reject the client connection through the * return status of it's OnAccept method. * * @author David Sugar * @short bound server for TCP streams and sessions. */ class __EXPORT TCPSocket : protected Socket { protected: int segsize; void setSegmentSize(unsigned mss); public: /** * A method to call in a derived TCPSocket class that is acting * as a server when a connection request is being accepted. The * server can implement protocol specific rules to exclude the * remote socket from being accepted by returning false. The * Peek method can also be used for this purpose. * * @return true if client should be accepted. * @param ia internet host address of the client. * @param port number of the client. */ virtual bool onAccept(const IPV4Host &ia, tpport_t port); /** * Fetch out the socket. */ inline SOCKET getSocket(void) {return so;} /** * Get the buffer size for servers. */ inline int getSegmentSize(void) {return segsize;} /** * A TCP "server" is created as a TCP socket that is bound * to a hardware address and port number on the local machine * and that has a backlog queue to listen for remote connection * requests. If the server cannot be created, an exception is * thrown. * * @param bind local ip address or interface to use. * @param port number to bind socket under. * @param backlog size of connection request queue. * @param mss maximum segment size for accepted streams. */ TCPSocket(const IPV4Address &bind, tpport_t port, unsigned backlog = 5, unsigned mss = 536); /** * Create a named tcp socket by service and/or interface id. * For IPV4 we use [host:]svc or [host/]svc for the string. * If we have getaddrinfo, we use that to obtain the addr to * bind for. * * @param name of host interface and service port to bind. * @param backlog size of connection request queue. * @param mss maximum segment size for streaming buffers. */ TCPSocket(const char *name, unsigned backlog = 5, unsigned mss = 536); /** * Return address and port of next connection request. This * can be used instead of OnAccept() to pre-evaluate connection * requests. * * @return host requesting a connection. * @param port number of requestor. */ inline IPV4Host getRequest(tpport_t *port = NULL) const {return Socket::getIPV4Sender(port);} /** * Used to reject the next incoming connection request. */ void reject(void); /** * Used to get local bound address. */ inline IPV4Host getLocal(tpport_t *port = NULL) const {return Socket::getIPV4Local(port);} /** * Used to wait for pending connection requests. * @return true if data packets available. * @param timeout in milliseconds. TIMEOUT_INF if not specified. */ inline bool isPendingConnection(timeout_t timeout = TIMEOUT_INF) /* not const -- jfc */ {return Socket::isPending(Socket::pendingInput, timeout);} /** * Use base socket handler for ending this socket. */ virtual ~TCPSocket(); }; #ifdef CCXX_IPV6 /** * TCPV6 sockets are used for stream based connected sessions between two * ipv6 sockets. Both error recovery and flow control operate transparently * for a TCP socket connection. The TCP socket base class is primary used * to bind a TCP "server" for accepting TCP streams. * * An implicit and unique TCPV6Socket object exists in Common C++ to represent * a bound ipv6 TCP socket acting as a "server" for receiving connection requests. * This class is not part of TCPStream because such objects normally perform * no physical I/O (read or write operations) other than to specify a listen * backlog queue and perform "accept" operations for pending connections. * The Common C++ TCPV6Socket offers a Peek method to examine where the next * pending connection is coming from, and a Reject method to flush the next * request from the queue without having to create a session. * * The TCPV6Socket also supports a "OnAccept" method which can be called when a * TCPStream related object is created from a TCPSocket. By creating a * TCPStream from a TCPV6Socket, an accept operation automatically occurs, and * the TCPV6Socket can then still reject the client connection through the * return status of it's OnAccept method. * * @author David Sugar * @short bound server for TCP streams and sessions. */ class __EXPORT TCPV6Socket : protected Socket { private: int segsize; void setSegmentSize(unsigned mss); public: /** * A method to call in a derived TCPSocket class that is acting * as a server when a connection request is being accepted. The * server can implement protocol specific rules to exclude the * remote socket from being accepted by returning false. The * Peek method can also be used for this purpose. * * @return true if client should be accepted. * @param ia internet host address of the client. * @param port number of the client. */ virtual bool onAccept(const IPV6Host &ia, tpport_t port); /** * Fetch out the socket. */ inline SOCKET getSocket(void) {return so;} inline int getSegmentSize(void) {return segsize;} /** * A TCP "server" is created as a TCP socket that is bound * to a hardware address and port number on the local machine * and that has a backlog queue to listen for remote connection * requests. If the server cannot be created, an exception is * thrown. * * @param bind local ip address or interface to use. * @param port number to bind socket under. * @param backlog size of connection request queue. * @param mss maximum segment size of streaming buffer. */ TCPV6Socket(const IPV6Address &bind, tpport_t port, unsigned backlog = 5, unsigned mss = 536); /** * Create a TCP server for a named host interface and service * port. We use [host/]port for specifying the optional host * name and service port since ':' is a valid char for ipv6 * addresses. * * @param name of host interface and service to use. * @param backlog size of connection request queue. * @param mss maximum segment size of streaming buffers. */ TCPV6Socket(const char *name, unsigned backlog = 5, unsigned mss = 536); /** * Return address and port of next connection request. This * can be used instead of OnAccept() to pre-evaluate connection * requests. * * @return host requesting a connection. * @param port number of requestor. */ inline IPV6Host getRequest(tpport_t *port = NULL) const {return Socket::getIPV6Sender(port);} /** * Used to reject the next incoming connection request. */ void reject(void); /** * Used to get local bound address. */ inline IPV6Host getLocal(tpport_t *port = NULL) const {return Socket::getIPV6Local(port);} /** * Used to wait for pending connection requests. * @return true if data packets available. * @param timeout in milliseconds. TIMEOUT_INF if not specified. */ inline bool isPendingConnection(timeout_t timeout = TIMEOUT_INF) /* not const -- jfc */ {return Socket::isPending(Socket::pendingInput, timeout);} /** * Use base socket handler for ending this socket. */ virtual ~TCPV6Socket(); }; #endif /** * TCP streams are used to represent TCP client connections to a server * by TCP protocol servers for accepting client connections. The TCP * stream is a C++ "stream" class, and can accept streaming of data to * and from other C++ objects using the << and >> operators. * * TCPStream itself can be formed either by connecting to a bound network * address of a TCP server, or can be created when "accepting" a * network connection from a TCP server. * * @author David Sugar * @short streamable TCP socket connection. */ class __EXPORT TCPStream : protected std::streambuf, public Socket, public std::iostream { private: int doallocate(); void segmentBuffering(unsigned mss); friend TCPStream& crlf(TCPStream&); friend TCPStream& lfcr(TCPStream&); // no copy constructor... TCPStream(const TCPStream &source); protected: timeout_t timeout; size_t bufsize; Family family; char *gbuf, *pbuf; public: /** * The constructor required for building other classes or to * start an unconnected TCPStream for connect. */ TCPStream(Family family = IPV4, bool throwflag = true, timeout_t to = 0); /** * Disconnect the current session and prepare for a new one. */ void disconnect(void); /** * Get protocol segment size. */ int getSegmentSize(void); protected: /** * Used to allocate the buffer space needed for iostream * operations. This function is called by the constructor. * * @param size of stream buffers from constructor. */ void allocate(size_t size); /** * Used to terminate the buffer space and cleanup the socket * connection. This fucntion is called by the destructor. */ void endStream(void); /** * This streambuf method is used to load the input buffer * through the established tcp socket connection. * * @return char from get buffer, EOF if not connected. */ int underflow(); /** * This streambuf method is used for doing unbuffered reads * through the establish tcp socket connection when in interactive mode. * Also this method will handle proper use of buffers if not in * interative mode. * * @return char from tcp socket connection, EOF if not connected. */ int uflow(); /** * This streambuf method is used to write the output * buffer through the established tcp connection. * * @param ch char to push through. * @return char pushed through. */ int overflow(int ch); /** * Create a TCP stream by connecting to a TCP socket (on * a remote machine). * * @param host address of remote TCP server. * @param port number to connect. * @param mss maximum segment size of streaming buffers. */ void connect(const IPV4Host &host, tpport_t port, unsigned mss = 536); #ifdef CCXX_IPV6 void connect(const IPV6Host &host, tpport_t port, unsigned mss = 536); #endif /** * Connect a TCP stream to a named destination host and port * number, using getaddrinfo interface if available. * * @param name of host and service to connect * @param mss maximum segment size of stream buffer */ void connect(const char *name, unsigned mss = 536); /** * Used in derived classes to refer to the current object via * it's iostream. For example, to send a set of characters * in a derived method, one might use *tcp() << "test". * * @return stream pointer of this object. */ std::iostream *tcp(void) {return ((std::iostream *)this);} public: /** * Create a TCP stream by accepting a connection from a bound * TCP socket acting as a server. This performs an "accept" * call. * * @param server socket listening * @param throwflag flag to throw errors. * @param timeout for all operations. */ TCPStream(TCPSocket &server, bool throwflag = true, timeout_t timeout = 0); #ifdef CCXX_IPV6 TCPStream(TCPV6Socket &server, bool throwflag = true, timeout_t timeout = 0); #endif /** * Accept a connection from a TCP Server. * * @param server socket listening */ void connect(TCPSocket &server); #ifdef CCXX_IPV6 void connect(TCPV6Socket &server); #endif /** * Create a TCP stream by connecting to a TCP socket (on * a remote machine). * * @param host address of remote TCP server. * @param port number to connect. * @param mss maximum segment size of streaming buffers. * @param throwflag flag to throw errors. * @param timeout for all operations. */ TCPStream(const IPV4Host &host, tpport_t port, unsigned mss = 536, bool throwflag = true, timeout_t timeout = 0); #ifdef CCXX_IPV6 TCPStream(const IPV6Host &host, tpport_t port, unsigned mss = 536, bool throwflag = true, timeout_t timeout = 0); #endif /** * Construct a named TCP Socket connected to a remote machine. * * @param name of remote service. * @param family of protocol. * @param mss maximum segment size of streaming buffers. * @param throwflag flag to throw errors. * @param timer for timeout for all operations. */ TCPStream(const char *name, Family family = IPV4, unsigned mss = 536, bool throwflag = false, timeout_t timer = 0); /** * Set the I/O operation timeout for socket I/O operations. * * @param timer to change timeout. */ inline void setTimeout(timeout_t timer) {timeout = timer;} /** * Flush and empty all buffers, and then remove the allocated * buffers. */ virtual ~TCPStream(); /** * Flushes the stream input and output buffers, writes * pending output. * * @return 0 on success. */ int sync(void); /** * Print content into a socket. * * @return count of bytes sent. * @param format string */ size_t printf(const char *format, ...); /** * Get the status of pending stream data. This can be used to * examine if input or output is waiting, or if an error or * disconnect has occured on the stream. If a read buffer * contains data then input is ready and if write buffer * contains data it is first flushed and then checked. */ bool isPending(Pending pend, timeout_t timeout = TIMEOUT_INF); /** * Examine contents of next waiting packet. * * @param buf pointer to packet buffer for contents. * @param len of packet buffer. * @return number of bytes examined. */ inline ssize_t peek(void *buf, size_t len) {return ::recv(so, (char *)buf, (socksize_t)len, MSG_PEEK);} /** * Return the size of the current stream buffering used. * * @return size of stream buffers. */ inline size_t getBufferSize(void) const {return bufsize;} }; /** * The TCP session is used to primarily to represent a client connection * that can be managed on a seperate thread. The TCP session also supports * a non-blocking connection scheme which prevents blocking during the * constructor and moving the process of completing a connection into the * thread that executes for the session. * * @author David Sugar * @short Threaded streamable socket with non-blocking constructor. */ class __EXPORT TCPSession : public Thread, public TCPStream { private: TCPSession(const TCPSession &rhs); // not defined protected: /** * Normally called during the thread Initial() method by default, * this will wait for the socket connection to complete when * connecting to a remote socket. One might wish to use * setCompletion() to change the socket back to blocking I/O * calls after the connection completes. To implement the * session one must create a derived class which implements * run(). * * @return 0 if successful, -1 if timed out. * @param timeout to wait for completion in milliseconds. */ int waitConnection(timeout_t timeout = TIMEOUT_INF); /** * The initial method is used to esablish a connection when * delayed completion is used. This assures the constructor * terminates without having to wait for a connection request * to complete. */ void initial(void); public: /** * Create a TCP socket that will be connected to a remote TCP * server and that will execute under it's own thread. * * @param host internet address of remote TCP server. * @param port number of remote server. * @param size of streaming buffer. * @param pri execution priority relative to parent. * @param stack allocation needed on some platforms. */ TCPSession(const IPV4Host &host, tpport_t port, size_t size = 536, int pri = 0, size_t stack = 0); #ifdef CCXX_IPV6 TCPSession(const IPV6Host &host, tpport_t port, size_t size = 536, int pri = 0, size_t stack = 0); #endif /** * Create a TCP socket from a bound TCP server by accepting a pending * connection from that server and execute a thread for the accepted * connection. * * @param server tcp socket to accept a connection from. * @param pri execution priority relative to parent. * @param stack allocation needed on some platforms. */ TCPSession(TCPSocket &server, int pri = 0, size_t stack = 0); #ifdef CCXX_IPV6 TCPSession(TCPV6Socket &server, int pri = 0, size_t stack = 0); #endif /** * Make sure destruction happens through a virtual... */ virtual ~TCPSession(); }; } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/string.h0000644000175000001440000000644612504227575014365 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 3 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file commoncpp/string.h * @short Common C++ generic string class **/ #ifndef COMMONCPP_STRING_H_ #define COMMONCPP_STRING_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif namespace ost { typedef ucommon::String String; __EXPORT char *lsetField(char *target, size_t size, const char *src, const char fill = 0); __EXPORT char *rsetField(char *target, size_t size, const char *src, const char fill = 0); __EXPORT char *newString(const char *src, size_t size = 0); __EXPORT void delString(char *str); __EXPORT char *setUpper(char *string, size_t size); __EXPORT char *setLower(char *string, size_t size); inline char *setString(char *target, size_t size, const char *str) {return String::set(target, size, str);} inline char *addString(char *target, size_t size, const char *str) {return String::add(target, size, str);} inline char *dupString(const char *src, size_t size = 0) {return newString(src, size);} /* __EXPORT char *find(const char *cs, char *str, size_t len = 0); __EXPORT char *rfind(const char *cs, char *str, size_t len = 0); __EXPORT char *ifind(const char *cs, char *str, size_t len = 0); __EXPORT char *strip(const char *cs, char *str, size_t len = 0); __EXPORT size_t strchop(const char *cs, char *str, size_t len = 0); __EXPORT size_t strtrim(const char *cs, char *str, size_t len = 0); */ } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/udp.h0000664000175000017500000004532012544722221013637 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file commoncpp/udp.h * @short udp derived socket classes. **/ #ifndef COMMONCPP_UDP_H_ #define COMMONCPP_UDP_H_ #include #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_STRING_H_ #include #endif #ifndef COMMONCPP_ADDRESS_H_ #include #endif #ifndef COMMONCPP_SOCKET_H_ #include #endif namespace ost { /** * UDP sockets implement the TCP SOCK_DGRAM UDP protocol. They can be * used to pass unverified messages between hosts, or to broadcast a * specific message to an entire subnet. Please note that Streaming of * realtime data commonly use UDPDuplex related classes rather than * UDPSocket. * * In addition to connected TCP sessions, Common C++ supports UDP sockets and * these also cover a range of functionality. Like a TCPSocket, A UDPSocket * can be created bound to a specific network interface and/or port address, * though this is not required. UDP sockets also are usually either * connected or otherwise "associated" with a specific "peer" UDP socket. * Since UDP sockets operate through discreet packets, there are no streaming * operators used with UDP sockets. * * In addition to the UDP "socket" class, there is a "UDPBroadcast" class. * The UDPBroadcast is a socket that is set to send messages to a subnet as a * whole rather than to an individual peer socket that it may be associated * with. * * UDP sockets are often used for building "realtime" media streaming * protocols and full duplex messaging services. When used in this manner, * typically a pair of UDP sockets are used together; one socket is used to * send and the other to receive data with an associated pair of UDP sockets * on a "peer" host. This concept is represented through the Common C++ * UDPDuplex object, which is a pair of sockets that communicate with another * UDPDuplex pair. * * * @author David Sugar * @short Unreliable Datagram Protocol sockets. */ class __EXPORT UDPSocket : public Socket { private: inline Error setKeepAlive(bool enable) {return Socket::setKeepAlive(enable);} protected: Socket::address peer; Family family; public: /** * Create an unbound UDP socket, mostly for internal use. */ UDPSocket(Family family = IPV4); /** * Create a UDP socket bound by a service name. */ UDPSocket(const char *name, Family family = IPV4); /** * Create a UDP socket and bind it to a specific interface * and port address so that other UDP sockets on remote * machines (or the same host) may find and send UDP messages * to it. On failure to bind, an exception is thrown. * * @param bind address to bind this socket to. * @param port number to bind this socket to. */ UDPSocket(const ucommon::Socket::address &bind); UDPSocket(const IPV4Address &bind, tpport_t port); #ifdef CCXX_IPV6 UDPSocket(const IPV6Address &bind, tpport_t port); #endif /** * Destroy a UDP socket as a socket. */ virtual ~UDPSocket(); /** * Set the loopback. */ inline Error setLoopback(bool enable) {return Socket::setLoopbackByFamily(enable, family);} /** * Set the multicast. */ inline Error setMulticast(bool enable) {return Socket::setMulticastByFamily(enable, family);} /** * Set time to live. */ inline Error setTimeToLive(char ttl) {return Socket::setTimeToLiveByFamily(ttl, family);} /** * set the peer address to send message packets to. This can be * set before every send() call if nessisary. * * @param host address to send packets to. * @param port number to deliver packets to. */ void setPeer(const ucommon::Socket::address &host); void connect(const ucommon::Socket::address &host); void setPeer(const IPV4Host &host, tpport_t port); void connect(const IPV4Host &host, tpport_t port); #ifdef CCXX_IPV6 void setPeer(const IPV6Host &host, tpport_t port); void connect(const IPV6Host &host, tpport_t port); #endif /** * get the interface index for a named network device * * @param ethX is device name, like "eth0" or "eth1" * @param InterfaceIndex is the index value returned by os * @todo Win32 and ipv6 specific implementation. */ Socket::Error getInterfaceIndex(const char *ethX,int& InterfaceIndex); /** * join a multicast group on a particular interface * * @param ia is the multicast address to use * @param InterfaceIndex is the index value returned by * getInterfaceIndex * @todo Win32 and ipv6 specific implementation. */ Socket::Error join(const ucommon::Socket::address &ia, int InterfaceIndex=0); Socket::Error join(const IPV4Multicast &ia,int InterfaceIndex); /** * Send a message packet to a peer host. * * @param buf pointer to packet buffer to send. * @param len of packet buffer to send. * @return number of bytes sent. */ ssize_t send(const void *buf, size_t len); /** * Receive a message from any host. * * @param buf pointer to packet buffer to receive. * @param len of packet buffer to receive. * @param reply save sender address for reply if true. * @return number of bytes received. */ ssize_t receive(void *buf, size_t len, bool reply = false); /** * Examine address of sender of next waiting packet. This also * sets "peer" address to the sender so that the next "send" * message acts as a "reply". This additional behavior overides * the standard socket getSender behavior. * * @param port pointer to hold port number. */ ucommon::Socket::address getPeer(); IPV4Host getIPV4Peer(tpport_t *port = NULL); inline IPV4Host getPeer(tpport_t *port) {return getIPV4Peer(port);} #ifdef CCXX_IPV6 IPV6Host getIPV6Peer(tpport_t *port = NULL); #endif /** * Examine contents of next waiting packet. * * @param buf pointer to packet buffer for contents. * @param len of packet buffer. * @return number of bytes examined. */ inline ssize_t peek(void *buf, size_t len) {return ::recv(so, (char *)buf, (socksize_t)len, MSG_PEEK);} /** * Associate socket with a named connection */ void setPeer(const char *service); void connect(const char *service); /** * Disassociate this socket from any host connection. No data * should be read or written until a connection is established. */ Error disconnect(void); }; /** * Representing a UDP socket used for subnet broadcasts, this class * provides an alternate binding and setPeer() capability for UDP * sockets. * * @author David Sugar * @short Unreliable Datagram for subnet broadcasts. */ class __EXPORT UDPBroadcast : public UDPSocket { private: void setPeer(const IPV4Host &ia, tpport_t port); Error setBroadcast(bool enable) {return Socket::setBroadcast(enable);} public: /** * Create and bind a subnet broadcast socket. * * @param ia address to bind socket under locally. * @param port to bind socket under locally. */ UDPBroadcast(const IPV4Address &ia, tpport_t port); /** * Set peer by subnet rather than specific host. * * @param subnet of peer hosts to send to. * @param port number to use. */ void setPeer(const IPV4Broadcast &subnet, tpport_t port); }; /** * Representing half of a two-way UDP connection, the UDP transmitter * can broadcast data to another selected peer host or to an entire * subnet. * * @author David Sugar * @short Unreliable Datagram Peer Associations. */ class __EXPORT UDPTransmit : protected UDPSocket { private: /** * Common code for diferent flavours of Connect (host, broadcast, * multicast). * * @param ia network address to associate with * @param port port number to associate with */ Error cConnect(const IPV4Address &ia, tpport_t port); protected: /** * Create a UDP transmitter. */ UDPTransmit(Family family = IPV4); /** * Create a UDP transmitter, bind it to a specific interface * and port address so that other UDP sockets on remote * machines (or the same host) may find and send UDP messages * to it, and associate it with a given port on a peer host. * On failure to bind, an exception is thrown. This class is * only used to build the UDP Duplex. * * @param bind address to bind this socket to. * @param port number to bind this socket to. If 0 or not specified, * the bind socket address port is used. */ UDPTransmit(const ucommon::Socket::address &bind); UDPTransmit(const IPV4Address &bind, tpport_t port = 5005); #ifdef CCXX_IPV6 UDPTransmit(const IPV6Address &bind, tpport_t port = 5005); #endif /** * Associate this socket with a specified peer host. The port * number from the constructor will be used. All UDP packets * will be sent to and received from the specified host. * * @return 0 on success, -1 on error. * @param host address to connect socket to. * @param port to connect socket to. */ Error connect(const ucommon::Socket::address &host); Error connect(const IPV4Host &host, tpport_t port); #ifdef CCXX_IPV6 Error connect(const IPV6Address &host, tpport_t port); #endif /** * Associate this socket with a subnet of peer hosts for * subnet broadcasting. The server must be able to assert * broadcast permission for the socket. * * @return 0 on success, -1 on error. * @param subnet subnet address to broadcast into. * @param port transport port to broadcast into. */ Error connect(const IPV4Broadcast &subnet, tpport_t port); /** * Associate this socket with a multicast group. * * @return 0 on success, -1 on error. * @param mgroup address of the multicast group to send to. * @param port port number */ Error connect(const IPV4Multicast &mgroup, tpport_t port); #ifdef CCXX_IPV6 Error connect(const IPV6Multicast &mgroup, tpport_t port); #endif /** * Transmit "send" to use "connected" send rather than sendto. * * @return number of bytes sent. * @param buf address of buffer to send. * @param len of bytes to send. */ inline ssize_t send(const void *buf, size_t len) {return ::send(so, (const char *)buf, (socksize_t)len, MSG_NOSIGNAL);} /** * Stop transmitter. */ inline void endTransmitter(void) {Socket::endSocket();} /* * Get transmitter socket. * * @return transmitter. */ inline SOCKET getTransmitter(void) {return so;}; inline Error setMulticast(bool enable) {return Socket::setMulticastByFamily(enable, family);} inline Error setTimeToLive(unsigned char ttl) {return Socket::setTimeToLiveByFamily(ttl, family);} public: /** * Transmit "send" to use "connected" send rather than sendto. * * @note Windows does not support MSG_DONTWAIT, so it is defined * as 0 on that platform. * @return number of bytes sent. * @param buffer address of buffer to send. * @param len of bytes to send. */ inline ssize_t transmit(const char *buffer, size_t len) {return ::send(so, buffer, (socksize_t)len, MSG_DONTWAIT|MSG_NOSIGNAL);} /** * See if output queue is empty for sending more packets. * * @return true if output available. * @param timeout in milliseconds to wait. */ inline bool isOutputReady(unsigned long timeout = 0l) {return Socket::isPending(Socket::pendingOutput, timeout);} inline Error setRouting(bool enable) {return Socket::setRouting(enable);} inline Error setTypeOfService(Tos tos) {return Socket::setTypeOfService(tos);} inline Error setBroadcast(bool enable) {return Socket::setBroadcast(enable);} }; /** * Representing half of a two-way UDP connection, the UDP receiver * can receive data from another peer host or subnet. This class is * used exclusivily to derive the UDPDuplex. * * @author David Sugar * @short Unreliable Datagram Peer Associations. */ class __EXPORT UDPReceive : protected UDPSocket { protected: /** * Create a UDP receiver, bind it to a specific interface * and port address so that other UDP sockets on remote * machines (or the same host) may find and send UDP messages * to it, and associate it with a given port on a peer host. * On failure to bind, an exception is thrown. * * @param bind address to bind this socket to. */ UDPReceive(const ucommon::Socket::address &bind); UDPReceive(const IPV4Address &bind, tpport_t port); #ifdef CCXX_IPV6 UDPReceive(const IPV6Address &bind, tpport_t port); #endif /** * Associate this socket with a specified peer host. The port * number from the constructor will be used. All UDP packets * will be sent received from the specified host. * * @return 0 on success, -1 on error. * @param host host network address to connect socket to. * @param port host transport port to connect socket to. */ Error connect(const ucommon::Socket::address &host); Error connect(const IPV4Host &host, tpport_t port); #ifdef CCXX_IPV6 Error connect(const IPV6Host &host, tpport_t port); #endif /** * Check for pending data. * * @return true if data is waiting. * @param timeout in milliseconds. */ bool isPendingReceive(timeout_t timeout) {return Socket::isPending(Socket::pendingInput, timeout);} /** * End receiver. */ inline void endReceiver(void) {Socket::endSocket();} inline SOCKET getReceiver(void) const {return so;} inline Error setRouting(bool enable) {return Socket::setRouting(enable);} inline Error setMulticast(bool enable) {return Socket::setMulticastByFamily(enable, family);} inline Error join(const ucommon::Socket::address &ia) {return Socket::join(ia);} inline Error join(const IPV4Multicast &ia) {return Socket::join(ia);} #ifdef CCXX_IPV6 inline Error join(const IPV6Multicast &ia) {return Socket::join(ia);} #endif inline Error drop(const IPV4Multicast &ia) {return Socket::drop(ia);} #ifdef CCXX_IPV6 inline Error drop(const IPV6Multicast &ia) {return Socket::drop(ia);} #endif public: /** * Receive a data packet from the connected peer host. * * @return num of bytes actually received. * @param buf address of data receive buffer. * @param len size of data receive buffer. */ inline ssize_t receive(void *buf, size_t len) {return ::recv(so, (char *)buf, (socksize_t)len, 0);} /** * See if input queue has data packets available. * * @return true if data packets available. * @param timeout in milliseconds. */ inline bool isInputReady(timeout_t timeout = TIMEOUT_INF) {return Socket::isPending(Socket::pendingInput, timeout);} }; /** * UDP duplex connections impliment a bi-directional point-to-point UDP * session between two peer hosts. Two UDP sockets are typically used * on alternating port addresses to assure that sender and receiver * data does not collide or echo back. A UDP Duplex is commonly used * for full duplex real-time streaming of UDP data between hosts. * * @author David Sugar * @short Unreliable Datagram Peer Associations. */ class __EXPORT UDPDuplex : public UDPTransmit, public UDPReceive { public: /** * Create a UDP duplex as a pair of UDP simplex objects * bound to alternating and interconnected port addresses. * * @param bind address to bind this socket to. * @param port number to bind sender. */ UDPDuplex(const ucommon::Socket::address &bind); UDPDuplex(const IPV4Address &bind, tpport_t port); #ifdef CCXX_IPV6 UDPDuplex(const IPV6Address &bind, tpport_t port); #endif /** * Associate the duplex with a specified peer host. Both * the sender and receiver will be interconnected with * the remote host. * * @return 0 on success, error code on error. * @param host address to connect socket to. * @param port number to connect socket to. */ Error connect(const ucommon::Socket::address &host); Error connect(const IPV4Host &host, tpport_t port); #ifdef CCXX_IPV6 Error connect(const IPV6Host &host, tpport_t port); #endif /** * Disassociate this duplex from any host connection. No data * should be read or written until a connection is established. * * @return 0 on success, error code on error. */ Error disconnect(void); }; } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/misc.h0000644000175000001440000001046412504227350013774 00000000000000// Copyright (C) 2001-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file misc.h * @short various miscellaneous classes historically used. **/ #ifndef COMMONCPP_MISC_H_ #define COMMONCPP_MISC_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif #define KEYDATA_INDEX_SIZE 97 #define KEYDATA_PAGER_SIZE 512 #if defined(PATH_MAX) #if PATH_MAX > 512 #define KEYDATA_PATH_SIZE 512 #else #define KEYDATA_PATH_SIZE PATH_MAX #endif #else #define KEYDATA_PATH_SIZE 256 #endif namespace ost { class __EXPORT MemPager : private ucommon::memalloc { public: inline MemPager(size_t pagesize = 4096) : ucommon::memalloc(pagesize) {} inline void *alloc(size_t size) {return _alloc(size);} char *alloc(const char *str); inline char *first(const char *str) {return alloc(str);} inline void *first(size_t size) {return _alloc(size);} inline int getPages(void) {return pages();} inline void purge(void) {memalloc::purge();} }; /** * 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 __EXPORT SharedMemPager : public MemPager, public Mutex { protected: /** * Create a mempager mutex pool. * * @param pagesize page size for allocation. * @param name a name for the pool. */ SharedMemPager(size_t pagesize = 4096); /** * Purge the memory pool while locked. */ void purge(void); /** * Get the last memory page after locking. * * @return allocated memory space. * @param size of request. */ void* alloc(size_t size); inline void *first(size_t size) {return alloc(size);} }; /** * This class is used to associate (object) pointers with named strings. * A virtual is used to allocate memory which can be overriden in the * derived class. * * @author David Sugar * @short associate names with pointers. */ class __EXPORT Assoc { private: struct entry { const char *id; entry *next; void *data; }; entry *entries[KEYDATA_INDEX_SIZE]; protected: Assoc(); virtual ~Assoc(); void clear(void); virtual void *getMemory(size_t size) = 0; public: void *getPointer(const char *id) const; void setPointer(const char *id, void *data); }; } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/export.h0000644000175000001440000000552312504227305014362 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * Export interfaces for library interfaces. * This is a special header used when we have to build DLL's for dumb * platforms which require explicit declaration of imports and exports. * The real purpose is to include our local headers in a new library * module with external headers referenced as imports, and then to define * our own interfaces in our new library as exports. This allows native * construction of new DLL's based on/that use ucommon on Microsoft Windows * and perhaps for other similarly defective legacy platforms. Otherwise * this header is not used at all, and not when building applications. * @file commoncpp/export.h */ #if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(_MSWINDOWS_) #ifdef __EXPORT #undef __EXPORT #endif #if defined(UCOMMON_STATIC) || defined(UCOMMON_RUNTIME) #define __EXPORT #else #define __EXPORT __declspec(dllexport) #endif #endif ucommon-6.4.4/inc/commoncpp/pointer.h0000664000175000017500000000745312537554527014552 00000000000000// Copyright (C) 2001-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // 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. /** * @file commoncpp/pointer.h * @short Template for creating reference count managed smart pointers. **/ #ifndef COMMONCPP_POINTER_H_ #define COMMONCPP_POINTER_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif namespace ost { /** * Used to create and manage referece counted pointers. * * @author David Sugar * @short reference counted pointer template. */ template class Pointer { protected: unsigned *ptrCount; T *ptrObject; inline void ptrDetach(void) { if(ptrCount && --(*ptrCount)==0) { delete ptrObject; delete ptrCount; } ptrObject = NULL; ptrCount = NULL; } public: inline explicit Pointer(T* ptr = NULL) : ptrObject(ptr) { ptrCount = new unsigned; *ptrCount = 1; } inline Pointer(const Pointer &ref) { ptrObject = ref.ptrObject; ptrCount = ref.ptrCount; ++(*ptrCount); } inline virtual ~Pointer() { ptrDetach(); } inline Pointer& operator=(const Pointer &ref) { if(this != &ref) { ptrDetach(); ptrObject = ref.ptrObject; ptrCount = ref.ptrCount; ++(*ptrCount); } return *this; } inline T& operator*() const { return *ptrObject; } inline T* getObject() const { return ptrObject; } inline T* operator->() const { return ptrObject; } inline bool operator!() const { return (*ptrCount == 1); } inline int operator++() const { return ++(*ptrCount); } inline int operator--() const { if(*ptrCount == 1) { delete this; return 0; } return --(*ptrCount); } }; } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/dccp.h0000644000175000001440000001661712504227250013757 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file commoncpp/udp.h * @short udp derived socket classes. **/ #ifndef COMMONCPP_DCCP_H_ #define COMMONCPP_DCCP_H_ #include #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_STRING_H_ #include #endif #ifndef COMMONCPP_ADDRESS_H_ #include #endif #ifndef COMMONCPP_SOCKET_H_ #include #endif namespace ost { /** * DCCP sockets are used for stream based connected sessions between two * sockets. Both error recovery and flow control operate transparently * for a DCCP socket connection. The DCCP socket base class is used both * for client connections and to bind a DCCP "server" for accepting DCCP * streams. * * An implicit and unique DCCPSocket object exists in Common C++ to represent * a bound DCCP socket acting as a "server" for receiving connection requests. * This class is not part of DCCPStream because such objects normally perform * no physical I/O (read or write operations) other than to specify a listen * backlog queue and perform "accept" operations for pending connections. * The Common C++ DCCPSocket offers a Peek method to examine where the next * pending connection is coming from, and a Reject method to flush the next * request from the queue without having to create a session. * * The DCCPSocket also supports a "OnAccept" method which can be called when a * DCCPStream related object is created from a DCCPSocket. By creating a * DCCPStream from a DCCPSocket, an accept operation automatically occurs, and * the DCCPSocket can then still reject the client connection through the * return status of it's OnAccept method. * * @author Leandro Sales * @author Heverton Stuart * @short bound server for DCCP streams and sessions. */ class __EXPORT DCCPSocket : public Socket { union { struct sockaddr_in ipv4; #ifdef CCXX_IPV6 struct sockaddr_in6 ipv6; #endif } peer; Family family; public: /** * A method to call in a derived DCCPSocket class that is acting * as a server when a connection request is being accepted. The * server can implement protocol specific rules to exclude the * remote socket from being accepted by returning false. The * Peek method can also be used for this purpose. * * @return true if client should be accepted. * @param ia internet host address of the client. * @param port number of the client. */ virtual bool onAccept(const IPV4Host &ia, tpport_t port); #ifdef CCXX_IPV6 virtual bool onAccept(const IPV6Host &ia, tpport_t port); #endif virtual IPV4Host getIPV4Sender(tpport_t *port = NULL) const; #ifdef CCXX_IPV6 virtual IPV6Host getIPV6Sender(tpport_t *port = NULL) const; #endif /** * A DCCP "server" is created as a DCCP socket that is bound * to a hardware address and port number on the local machine * and that has a backlog queue to listen for remote connection * requests. If the server cannot be created, an exception is * thrown. * * @param bind local ip address or interface to use. * @param port number to bind socket under. * @param backlog size of connection request queue. */ DCCPSocket(const IPV4Address &bind, tpport_t port, unsigned backlog = 5); #ifdef CCXX_IPV6 DCCPSocket(const IPV6Address &bind, tpport_t port, unsigned backlog = 5); #endif /** * Create a named dccp socket by service and/or interface id. * For IPV4 we use [host:]svc or [host/]svc for the string. * If we have getaddrinfo, we use that to obtain the addr to * bind for. * * @param name of host interface and service port to bind. * @param backlog size of connection request queue. */ DCCPSocket(const char *name, Family family = IPV4, unsigned backlog = 5); /** * Create an unconnected ephemeral DCCP client socket. */ DCCPSocket(Family family = IPV4); /** * Create a server session by accepting a DCCP Socket. */ DCCPSocket(DCCPSocket& server, timeout_t timeout = 0); /** * Used to reject the next incoming connection request. */ void reject(void); /** * Disconnect active dccp connection (client use). */ void disconnect(void); /** * Set CCID DCCP. */ bool setCCID(uint8_t ccid); /** * Get TX CCID DCCP. */ int getTxCCID(); /** * Get RX CCID DCCP. */ int getRxCCID(); /** * Return number of bytes to be read */ size_t available(); /** * Create a DCCP client connection to a DCCP socket (on * a remote machine). * * @param host address of remote DCCP server. * @param port number to connect. */ void connect(const IPV4Host &host, tpport_t port, timeout_t timeout = 0); #ifdef CCXX_IPV6 void connect(const IPV6Host &host, tpport_t port, timeout_t timeout = 0); #endif /** * Connect to a named client. */ void connect(const char *name); /** * Used to wait for pending connection requests. * @return true if data packets available. * @param timeout in milliseconds. TIMEOUT_INF if not specified. */ inline bool isPendingConnection(timeout_t timeout = TIMEOUT_INF) /* not const -- jfc */ {return Socket::isPending(Socket::pendingInput, timeout);} /** * Use base socket handler for ending this socket. */ virtual ~DCCPSocket(); }; } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/address.h0000644000175000001440000007645112504227167014504 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file commoncpp/address.h * @short Network addresses and sockets related classes. **/ #ifndef COMMONCPP_ADDRESS_H_ #define COMMONCPP_ADDRESS_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_THREAD_H_ #include #endif #ifndef COMMMONCPP_EXCEPTION_H_ #include #endif namespace ost { // future definition of ipv4 specific classes, now defines #define INET_IPV4_ADDRESS_SIZE 16 #define CIDR_IPV4_ADDRESS_SIZE 32 #define INET_IPV6_ADDRESS_SIZE 40 #define CIDR_IPV6_ADDRESS_SIZE 45 #define CIDR IPV4Cidr #define InetAddress IPV4Address #define InetHostAddress IPV4Host #define InetMaskAddress IPV4Mask #define InetMcastAddress IPV4Multicast #define InetMcastAddressValidator IPV4MulticastValidator #define InetAddrValidator IPV4Validator #define BroadcastAddress IPV4Broadcast /** * Transport Protocol Ports. */ typedef unsigned short tpport_t; class IPV4Host; /** * Classes derived from IPV4Address would require an specific * validator to pass to the IPV4Address constructor. This is a base * class for classes of function objects used by such derived classes. * * @author Federico Montesino * @short Abstract base class for derived inet addresses validators. */ class __EXPORT IPV4Validator { public: /** * Constructor. Does not deal with any state. */ IPV4Validator() { } /** * keeps compilers happy. */ virtual ~IPV4Validator() {} /** * Pure virtual application operator. Apply the validation * algorithm specific to derived classes. */ virtual void operator()(const in_addr address) const = 0; }; /** * Class for the function object that validates multicast addresses. * Implements a specific application operator to validate multicast * addresses. * * @author Federico Montesino * @short Validating class specialized for multicast addresses. */ class __EXPORT IPV4MulticastValidator: public IPV4Validator { public: /** * Constructor. Does not deal with any state. */ IPV4MulticastValidator(){} /** * Keeps compilers happy. */ virtual ~IPV4MulticastValidator(){} /** * Application operator. Apply the validation algorithm * specific to multicast addresses */ void operator()(const in_addr address) const; }; /** * The CIDR class is used to support routing tables and validate address * policies. * * @author David Sugar * @short Classless Internet Domain Routing */ class __EXPORT IPV4Cidr { protected: struct in_addr netmask, network; unsigned getMask(const char *cp) const; public: /** * Get network address associated with this cidr. * * @return system binary coded address. */ inline struct in_addr getNetwork(void) const {return network;} /** * Get network mask associated with this cidr. * * @return system binary coded network mask. */ inline struct in_addr getNetmask(void) const {return netmask;} /** * Compute the broadcast address associated with this cidr. * * @return system binary coded network address. */ struct in_addr getBroadcast(void) const; /** * Set the cidr from a full or partial hostname, or from an * address/mask, or a host/bits specification. * * @param cidr string to use. */ void set(const char *cidr); /** * Construct a new cidr from a string. * * @param cidr string to use. */ IPV4Cidr(const char *cidr); /** * Construct an empty cidr. */ IPV4Cidr(); /** * Construct a copy of a cidr. * * @param cidr to copy from. */ IPV4Cidr(IPV4Cidr &); /** * See if a socket address is a member of this cidr's network. * * @param saddr pointer to test. * @return true if member of cidr. */ bool isMember(const struct sockaddr *saddr) const; /** * See if a low level address object is a member of this cidr's net. * * @param inaddr object to test. * @return true if member of cidr. */ bool isMember(const struct in_addr &inaddr) const; inline bool operator==(const struct sockaddr *a) const {return isMember(a);} inline bool operator==(const struct in_addr &a) const {return isMember(a);} }; #ifdef CCXX_IPV6 /** * The CIDR class is used to support routing tables and validate address * policies. * * @author David Sugar * @short Classless Internet Domain Routing */ class __EXPORT IPV6Cidr { protected: struct in6_addr netmask, network; unsigned getMask(const char *cp) const; public: /** * Get network address associated with this cidr. * * @return system binary coded address. */ inline struct in6_addr getNetwork(void) const {return network;} /** * Get network mask associated with this cidr. * * @return system binary coded network mask. */ inline struct in6_addr getNetmask(void) const {return netmask;} /** * Compute the broadcast address associated with this cidr. * * @return system binary coded network address. */ struct in6_addr getBroadcast(void) const; /** * Set the cidr from a full or partial hostname, or from a * host/bits specification. * * @param cidr string to use. */ void set(const char *cidr); /** * Construct a new cidr from a string. * * @param cidr string to use. */ IPV6Cidr(const char *cidr); /** * Construct an empty cidr. */ IPV6Cidr(); /** * Construct a copy of a cidr. * * @param cidr to copy from. */ IPV6Cidr(IPV6Cidr &); /** * See if a socket address is a member of this cidr's network. * * @param saddr pointer to test. * @return true if member of cidr. */ bool isMember(const struct sockaddr *saddr) const; /** * See if a low level address object is a member of this cidr's net. * * @param inaddr object to test. * @return true if member of cidr. */ bool isMember(const struct in6_addr &inaddr) const; inline bool operator==(const struct sockaddr *sa) const {return isMember(sa);} inline bool operator==(const struct in6_addr &a) const {return isMember(a);} }; #endif /** * The network name and address objects are all derived from a common * IPV4Address base class. Specific classes, such as IPV4Host, * IPV4Mask, etc, are defined from IPV4Address entirely so that the * manner a network address is being used can easily be documented and * understood from the code and to avoid common errors and accidental misuse * of the wrong address object. For example, a "connection" to something * that is declared as a "IPV4Host" can be kept type-safe from a * "connection" accidently being made to something that was declared a * "IPV4Broadcast". * * @author David Sugar * @short Internet Address binary data type. */ class __EXPORT IPV4Address { private: // The validator given to an IPV4Address object must not be a // transient object, but that must exist at least until the // last address object of its kind is deleted. This is an // artifact to be able to do specific checks for derived // classes inside constructors. const InetAddrValidator *validator; protected: struct in_addr * ipaddr; size_t addr_count; mutable char* hostname; // hostname for ipaddr[0]. Used by getHostname #if defined(_MSWINDOWS_) static MutexCounter counter; #else static Mutex mutex; #endif /** * Sets the IP address from a string representation of the * numeric address, ie "127.0.0.1" * * @param host The string representation of the IP address * @return true if successful */ bool setIPAddress(const char *host); /** * Used to specify a host name or numeric internet address. * * @param host The string representation of the IP address or * a hostname, , if NULL, it will default to INADDR_ANY */ void setAddress(const char *host); public: /** * Create an Internet Address object with an empty (0.0.0.0) * address. * * @param validator optional validator function object, intended for * derived classes. */ IPV4Address(const InetAddrValidator *validator = NULL); /** * Convert the system internet address data type (struct in_addr) * into a Common C++ IPV4Address object. * * @param addr struct of system used binary internet address. * @param validator optional validator function object, intended for * derived classes. */ IPV4Address(struct in_addr addr, const InetAddrValidator *validator = NULL); /** * Convert a null terminated ASCII host address string * (example: "127.0.0.1") or host address name (example: * "www.voxilla.org") directly into a Common C++ IPV4Address * object. * * @param address null terminated C string. * @param validator optional validator function object, intended for * derived classes. */ IPV4Address(const char *address, const InetAddrValidator *validator = NULL); /** * Copy constructor */ IPV4Address(const IPV4Address &rhs); /** * Destructor */ virtual ~IPV4Address(); /** * Provide a string representation of the value (Internet Address) * held in the IPV4Address object. * * @return string representation of IPV4Address. */ const char *getHostname(void) const; /** * May be used to verify if a given IPV4Address returned * by another function contains a "valid" address, or "0.0.0.0" * which is often used to mark "invalid" IPV4Address values. * * @return true if address != 0.0.0.0. */ bool isInetAddress(void) const; /** * Provide a low level system usable struct in_addr object from * the contents of IPV4Address. This is needed for services such * as bind() and connect(). * * @return system binary coded internet address. */ struct in_addr getAddress(void) const; /** * Provide a low level system usable struct in_addr object from * the contents of IPV4Address. This is needed for services such * as bind() and connect(). * * @param i for IPV4Addresses with multiple addresses, returns the * address at this index. User should call getAddressCount() * to determine the number of address the object contains. * @return system binary coded internet address. If parameter i is * out of range, the first address is returned. */ struct in_addr getAddress(size_t i) const; /** * Returns the number of internet addresses that an IPV4Address object * contains. This usually only happens with IPV4Host objects * where multiple IP addresses are returned for a DNS lookup */ size_t getAddressCount() const { return addr_count; } IPV4Address &operator=(const char *str); IPV4Address &operator=(struct in_addr addr); IPV4Address &operator=(const IPV4Address &rhs); /** * Allows assignment from the return of functions like * inet_addr() or htonl() */ IPV4Address &operator=(unsigned long addr); inline IPV4Address &operator=(unsigned int addr) {return *this = (unsigned long) addr; } inline bool operator!() const {return !isInetAddress();} /** * Compare two internet addresses to see if they are equal * (if they specify the physical address of the same internet host). * * If there is more than one IP address in either IPV4Address object, * this will return true if all of the IP addresses in the smaller * are in the larger in any order. */ bool operator==(const IPV4Address &a) const; /** * Compare two internet addresses to see if they are not * equal (if they each refer to unique and different physical * ip addresses). * * This is implimented in terms of operator== */ bool operator!=(const IPV4Address &a) const; }; /** * Internet addresses used specifically as masking addresses (such as " * 255.255.255.0") are held in the IPV4Mask derived object. The * seperate class is used so that C++ type casting can automatically * determine when an IPV4Address object is really a mask address object * rather than simply using the base class. This also allows manipulative * operators for address masking to operate only when presented with a * Masked address as well as providing cleaner and safer source. * * @author David Sugar * @short Internet Address Mask such as subnet masks. */ class __EXPORT IPV4Mask : public IPV4Address { public: /** * Create the mask from a null terminated ASCII string such as * "255.255.255.128". * * @param mask null terminated ASCII mask string. */ IPV4Mask(const char *mask); /** * Masks are usually used to coerce host addresses into a specific * router or class domain. This can be done by taking the Inet * Host Address object and "and"ing it with an address mask. This * operation can be directly expressed in C++ through the & operator. * * @return a internet host address that has been masked. * @param addr host address to be masked by subnet. * @param mask inetnet mask address object to mask by. */ friend __EXPORT IPV4Host operator&(const IPV4Host &addr, const IPV4Mask &mask); /** * Allows assignment from the return of functions like * inet_addr() or htonl() */ IPV4Address &operator=(unsigned long addr) { return IPV4Address::operator =(addr); } }; /** * This object is used to hold the actual and valid internet address of a * specific host machine that will be accessed through a socket. * * @author David Sugar * @short Address of a specific Internet host machine. */ class __EXPORT IPV4Host : public IPV4Address { private: static IPV4Host _host_; public: /** * Create a new host address for a specific internet host. The * internet host can be specified in a null terminated ASCII * string and include either the physical host address or the * DNS name of a host machine. Hence, an IPV4Host * ("www.voxilla.org") can be directly declaired in this manner. * * Defaults to the IP address that represents the interface matching * "gethostname()". * * @param host dns or physical address of an Internet host. */ IPV4Host(const char *host = NULL); /** * Convert a system socket binary address such as may be * returned through the accept() call or getsockpeer() into * an internet host address object. * * @param addr binary address of internet host. */ IPV4Host(struct in_addr addr); /** * Allows assignment from the return of functions like * inet_addr() or htonl() */ IPV4Address &operator=(unsigned long addr) { return IPV4Address::operator =(addr); } /** * Mask the internet host address object with a network mask address. * This is commonly used to coerce an address by subnet. */ IPV4Host &operator&=(const IPV4Mask &mask); friend class IPV4Mask; friend __EXPORT IPV4Host operator&(const IPV4Host &addr, const IPV4Mask &mask); }; /** * The broadcast address object is used to store the broadcast address for * a specific subnet. This is commonly used for UDP broadcast operations. */ class __EXPORT IPV4Broadcast : public IPV4Address { public: /** * Specify the physical broadcast address to use and create a new * broadcast address object based on a null terminated ASCII * string. * * @param net null terminated ASCII network address. */ IPV4Broadcast(const char *net = "255.255.255.255"); }; /** * A specialization of IPV4Address that provides address validation * for multicast addresses. Whenever its value changes the new value * is checked to be in the range from 224.0.0.1 through * 239.255.255.255. If it is not, an exception is thrown. * * @short A multicast network address. * @author Federico Montesino */ class __EXPORT IPV4Multicast: public IPV4Address { public: /** * Create an Internet Multicast Address object with an empty * (0.0.0.0) address. */ IPV4Multicast(); /** * Convert the system internet address data type (struct in_addr) * into a Common C++ IPV4Multicast object. * * @param address struct of system used binary internet address. */ IPV4Multicast(const struct in_addr address); /** * Convert a null terminated ASCII multicast address string * (example: "224.0.0.1") or multicast name string (example: * "sap.mcast.net") directly into a Common C++ * IPV4Multicast object. Works like IPV4Address(const * char*). * * @param address null terminated C string. */ IPV4Multicast(const char *address); private: /** * Check the address in addr is a valid multicast * address. In case not, throws an exception. * * @param address a system network address * @return true if validation succeeded */ static const IPV4MulticastValidator validator; }; extern __EXPORT std::ostream& operator<<(std::ostream &os, const IPV4Address &ia); inline struct in_addr getaddress(const IPV4Address &ia) {return ia.getAddress();} #ifdef CCXX_IPV6 class IPV6Host; /** * Classes derived from IPV6Address would require an specific * validator to pass to the IPV6Address constructor. This is a base * class for classes of function objects used by such derived classes. * * @author Federico Montesino * @short Abstract base class for derived inet addresses validators. */ class __EXPORT IPV6Validator { public: /** * Constructor. Does not deal with any state. */ IPV6Validator() { } /** * Keeps compilers happy. */ virtual ~IPV6Validator() {} /** * Pure virtual application operator. Apply the validation * algorithm specific to derived classes. */ virtual void operator()(const in6_addr address) const = 0; }; /** * Class for the function object that validates multicast addresses. * Implements a specific application operator to validate multicast * addresses. * * @author Federico Montesino * @short Validating class specialized for multicast addresses. */ class __EXPORT IPV6MulticastValidator: public IPV6Validator { public: /** * Constructor. Does not deal with any state. */ IPV6MulticastValidator(){} /** * Keeps compilers happy... */ virtual ~IPV6MulticastValidator(){} /** * Application operator. Apply the validation algorithm * specific to multicast addresses */ void operator()(const in6_addr address) const; }; /** * The network name and address objects are all derived from a common * IPV6Address base class. Specific classes, such as IPV4Host, * IPV6Mask, etc, are defined from IPV6Address entirely so that the * manner a network address is being used can easily be documented and * understood from the code and to avoid common errors and accidental misuse * of the wrong address object. For example, a "connection" to something * that is declared as a "IPV6Host" can be kept type-safe from a * "connection" accidently being made to something that was declared a * "IPV6Broadcast". * * @author David Sugar * @short Internet Address binary data type. */ class __EXPORT IPV6Address { private: // The validator given to an IPV4Address object must not be a // transient object, but that must exist at least until the // last address object of its kind is deleted. This is an // artifact to be able to do specific checks for derived // classes inside constructors. const IPV6Validator *validator; protected: struct in6_addr * ipaddr; size_t addr_count; mutable char* hostname; // hostname for ipaddr[0]. Used by getHostname #if defined(_MSWINDOWS_) static MutexCounter counter; #else static Mutex mutex; #endif /** * Sets the IP address from a string representation of the * numeric address, ie "127.0.0.1" * * @param host The string representation of the IP address * @return true if successful */ bool setIPAddress(const char *host); /** * Used to specify a host name or numeric internet address. * * @param host The string representation of the IP address or * a hostname, , if NULL, it will default to INADDR_ANY */ void setAddress(const char *host); public: /** * Create an Internet Address object with an empty (0.0.0.0) * address. * * @param validator optional validator function object, intended for * derived classes. */ IPV6Address(const IPV6Validator *validator = NULL); /** * Convert the system internet address data type (struct in_addr) * into a Common C++ IPV6Address object. * * @param addr struct of system used binary internet address. * @param validator optional validator function object, intended for * derived classes. */ IPV6Address(struct in6_addr addr, const IPV6Validator *validator = NULL); /** * Convert a null terminated ASCII host address string * (example: "127.0.0.1") or host address name (example: * "www.voxilla.org") directly into a Common C++ IPV6Address * object. * * @param address null terminated C string. * @param validator optional validator function object, intended for * derived classes. */ IPV6Address(const char *address, const IPV6Validator *validator = NULL); /** * Copy constructor */ IPV6Address(const IPV6Address &rhs); /** * Destructor */ virtual ~IPV6Address(); /** * Provide a string representation of the value (Internet Address) * held in the IPV6Address object. * * @return string representation of IPV6Address. */ const char *getHostname(void) const; /** * May be used to verify if a given IPV6Address returned * by another function contains a "valid" address, or "0.0.0.0" * which is often used to mark "invalid" IPV6Address values. * * @return true if address != 0.0.0.0. */ bool isInetAddress(void) const; /** * Provide a low level system usable struct in_addr object from * the contents of IPV6Address. This is needed for services such * as bind() and connect(). * * @return system binary coded internet address. */ struct in6_addr getAddress(void) const; /** * Provide a low level system usable struct in_addr object from * the contents of IPV6Address. This is needed for services such * as bind() and connect(). * * @param i for IPV6Addresses with multiple addresses, returns the * address at this index. User should call getAddressCount() * to determine the number of address the object contains. * @return system binary coded internet address. If parameter i is * out of range, the first address is returned. */ struct in6_addr getAddress(size_t i) const; /** * Returns the number of internet addresses that an IPV6Address object * contains. This usually only happens with IPV6Host objects * where multiple IP addresses are returned for a DNS lookup */ size_t getAddressCount() const { return addr_count; } IPV6Address &operator=(const char *str); IPV6Address &operator=(struct in6_addr addr); IPV6Address &operator=(const IPV6Address &rhs); inline bool operator!() const {return !isInetAddress();} /** * Compare two internet addresses to see if they are equal * (if they specify the physical address of the same internet host). * * If there is more than one IP address in either IPV6Address object, * this will return true if all of the IP addresses in the smaller * are in the larger in any order. */ bool operator==(const IPV6Address &a) const; /** * Compare two internet addresses to see if they are not * equal (if they each refer to unique and different physical * ip addresses). * * This is implimented in terms of operator== */ bool operator!=(const IPV6Address &a) const; }; /** * Internet addresses used specifically as masking addresses (such as " * 255.255.255.0") are held in the IPV6Mask derived object. The * seperate class is used so that C++ type casting can automatically * determine when an IPV6Address object is really a mask address object * rather than simply using the base class. This also allows manipulative * operators for address masking to operate only when presented with a * Masked address as well as providing cleaner and safer source. * * @author David Sugar * @short Internet Address Mask such as subnet masks. */ class __EXPORT IPV6Mask : public IPV6Address { public: /** * Create the mask from a null terminated ASCII string such as * "255.255.255.128". * * @param mask null terminated ASCII mask string. */ IPV6Mask(const char *mask); /** * Masks are usually used to coerce host addresses into a specific * router or class domain. This can be done by taking the Inet * Host Address object and "and"ing it with an address mask. This * operation can be directly expressed in C++ through the & operator. * * @return a internet host address that has been masked. * @param addr host address to be masked by subnet. * @param mask inetnet mask address object to mask by. */ friend __EXPORT IPV6Host operator&(const IPV6Host &addr, const IPV6Mask &mask); }; /** * This object is used to hold the actual and valid internet address of a * specific host machine that will be accessed through a socket. * * @author David Sugar * @short Address of a specific Internet host machine. */ class __EXPORT IPV6Host : public IPV6Address { public: /** * Create a new host address for a specific internet host. The * internet host can be specified in a null terminated ASCII * string and include either the physical host address or the * DNS name of a host machine. Hence, an IPV6Host * ("www.voxilla.org") can be directly declaired in this manner. * * Defaults to the IP address that represents the interface matching * "gethostname()". * * @param host dns or physical address of an Internet host. */ IPV6Host(const char *host = NULL); /** * Convert a system socket binary address such as may be * returned through the accept() call or getsockpeer() into * an internet host address object. * * @param addr binary address of internet host. */ IPV6Host(struct in6_addr addr); /** * Mask the internet host address object with a network mask address. * This is commonly used to coerce an address by subnet. */ IPV6Host &operator&=(const IPV6Mask &mask); friend class IPV6Mask; friend __EXPORT IPV6Host operator&(const IPV6Host &addr, const IPV6Mask &mask); }; /** * The broadcast address object is used to store the broadcast address for * a specific subnet. This is commonly used for UDP broadcast operations. */ class __EXPORT IPV6Broadcast : public IPV6Address { public: /** * Specify the physical broadcast address to use and create a new * broadcast address object based on a null terminated ASCII * string. * * @param net null terminated ASCII network address. */ IPV6Broadcast(const char *net = "255.255.255.255"); }; /** * A specialization of IPV6Address that provides address validation * for multicast addresses. Whenever its value changes the new value * is checked to be in the range from 224.0.0.1 through * 239.255.255.255. If it is not, an exception is thrown. * * @short A multicast network address. * @author Federico Montesino */ class __EXPORT IPV6Multicast: public IPV6Address { public: /** * Create an Internet Multicast Address object with an empty * (0.0.0.0) address. */ IPV6Multicast(); /** * Convert the system internet address data type (struct in_addr) * into a Common C++ IPV4Multicast object. * * @param address struct of system used binary internet address. */ IPV6Multicast(const struct in6_addr address); /** * Convert a null terminated ASCII multicast address string * (example: "224.0.0.1") or multicast name string (example: * "sap.mcast.net") directly into a Common C++ * IPV6Multicast object. Works like IPV6Address(const * char*). * * @param address null terminated C string. */ IPV6Multicast(const char *address); private: /** * Check the address in addr is a valid multicast * address. In case not, throws an exception. * * @param address a system network address * @return true if validation succeeded */ static const IPV6MulticastValidator validator; }; extern __EXPORT std::ostream& operator<<(std::ostream &os, const IPV6Address &ia); inline struct in6_addr getaddress(const IPV6Address &ia) {return ia.getAddress();} #endif } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/mime.h0000644000175000001440000001375112504227335013775 00000000000000// Copyright (C) 2001-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file mime.h * @short MIME document abstractions. **/ #ifndef COMMONCPP_MIME_H_ #define COMMONCPP_MIME_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_SOCKET_H_ #include #endif namespace ost { class MIMEMultipart; class MIMEItemPart; /** * A container class for multi-part MIME document objects which can * be streamed to a std::ostream destination. * * @author David Sugar * @short container for streamable multi-part MIME documents. */ class __EXPORT MIMEMultipart { protected: friend class MIMEItemPart; char boundry[8]; char mtype[80]; char *header[16]; MIMEItemPart *first, *last; virtual ~MIMEMultipart(); public: /** * Contruct a multi-part document, and describe it's type. * * @param document (content) type. */ MIMEMultipart(const char *document); /** * Stream the headers of the multi-part document. The headers * of individual entities are streamed as part of the body. * * @param output to stream document header into. */ virtual void head(std::ostream *output); /** * Stream the "body" of the multi-part document. This involves * streaming the headers and body of each document part. * * @param output to stream document body into. */ virtual void body(std::ostream *output); /** * Get a string array of the headers to use. This is used to * assist URLStream::post. * * @return array of headers. */ char **getHeaders(void) {return header;} }; /** * The Multipart form is a MIME multipart document specific for the * construction and delivery of form data to a web server through a * post method. * * @author David Sugar * @short deliver form results as multipart document. */ class __EXPORT MIMEMultipartForm : public MIMEMultipart { protected: virtual ~MIMEMultipartForm(); public: /** * Construct a form result. This is a MIMEMultipart of type * multipart/form-data. */ MIMEMultipartForm(); }; /** * This is used to attach an item part to a MIME multipart document * that is being streamed. The base item part class is used by all * derived items. * * @author David Sugar * @short item or part of a multi-part object. */ class __EXPORT MIMEItemPart { protected: friend class MIMEMultipart; MIMEMultipart *base; MIMEItemPart *next; const char *ctype; /** * Stream the header(s) for the current document part. * * @param output to stream header into. */ virtual void head(std::ostream *output); /** * Stream the content of this document part. * * @param output to stream document body into. */ virtual void body(std::ostream *output) = 0; /** * Construct and attach a document part to a multipart document. * * @param top multipart document to attach to. * @param ct Content-Type to use. */ MIMEItemPart(MIMEMultipart *top, const char *ct); virtual ~MIMEItemPart(); }; /** * This is a document part type for use in submitting multipart form * data to a web server. * * @author David Sugar * @short multipart document part for web form data field. */ class __EXPORT MIMEFormData : public MIMEItemPart { protected: const char *content; const char *name; virtual ~MIMEFormData(); public: /** * Stream header, Content-Disposition form-data. * * @param output stream to send header to. */ void head(std::ostream *output); /** * Stream content (value) of this form data field. * * @param output stream to send body to. */ void body(std::ostream *output); /** * Construct form data field part of multipart form. * * @param top multipart form this is part of * @param name of form data field * @param content of form data field */ MIMEFormData(MIMEMultipartForm *top, const char *name, const char *content); }; } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/Makefile.in0000664000175000017500000004412312557431663014756 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015 Cherokees of Idaho. # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = inc/commoncpp DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(pkginclude_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/ucommon-config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(pkgincludedir)" HEADERS = $(pkginclude_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) pkgincludedir = $(includedir)/commoncpp ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CHECKFLAGS = @CHECKFLAGS@ CMAKE_CURRENT_SOURCE_DIR = @CMAKE_CURRENT_SOURCE_DIR@ CMAKE_INSTALL_FULL_DATADIR = @CMAKE_INSTALL_FULL_DATADIR@ CMAKE_INSTALL_FULL_INCLUDEDIR = @CMAKE_INSTALL_FULL_INCLUDEDIR@ CMAKE_INSTALL_FULL_LIBDIR = @CMAKE_INSTALL_FULL_LIBDIR@ CMAKE_INSTALL_PREFIX = @CMAKE_INSTALL_PREFIX@ COMPAT = @COMPAT@ COMPAT_CONFIG = @COMPAT_CONFIG@ COMPAT_PC = @COMPAT_PC@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_VERSION = @LT_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MODULE_FLAGS = @MODULE_FLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OPENSSL_CFLAGS = @OPENSSL_CFLAGS@ OPENSSL_LIBS = @OPENSSL_LIBS@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PKG_SECURE_LIBS = @PKG_SECURE_LIBS@ PKG_UCOMMON_FLAGS = @PKG_UCOMMON_FLAGS@ PKG_UCOMMON_INCLUDES = @PKG_UCOMMON_INCLUDES@ PKG_UCOMMON_LIBS = @PKG_UCOMMON_LIBS@ RANLIB = @RANLIB@ SECURE = @SECURE@ SECURE_LIBS = @SECURE_LIBS@ SECURE_LOCAL = @SECURE_LOCAL@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ UCOMMON_CFGPATH = @UCOMMON_CFGPATH@ UCOMMON_FLAGS = @UCOMMON_FLAGS@ UCOMMON_INCLUDES = @UCOMMON_INCLUDES@ UCOMMON_LIBC = @UCOMMON_LIBC@ UCOMMON_LIBS = @UCOMMON_LIBS@ UCOMMON_LINKED = @UCOMMON_LINKED@ UCOMMON_LOCALE = @UCOMMON_LOCALE@ UCOMMON_PREFIX = @UCOMMON_PREFIX@ UCOMMON_VARPATH = @UCOMMON_VARPATH@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ includes = @includes@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ libs = @libs@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ MAINTAINERCLEANFILES = Makefile.in Makefile RELEASE = $(LT_VERSION) -release $(LT_RELEASE) AM_CXXFLAGS = $(UCOMMON_FLAGS) pkginclude_HEADERS = config.h export.h string.h exception.h thread.h misc.h \ slog.h applog.h address.h socket.h tcp.h udp.h dccp.h mime.h file.h \ process.h pointer.h serial.h tokenizer.h numbers.h object.h \ commoncpp.h all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu inc/commoncpp/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu inc/commoncpp/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgincludeHEADERS: $(pkginclude_HEADERS) @$(NORMAL_INSTALL) @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \ done uninstall-pkgincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(HEADERS) installdirs: for dir in "$(DESTDIR)$(pkgincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgincludeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-pkgincludeHEADERS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool cscopelist-am ctags ctags-am distclean \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-pkgincludeHEADERS install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am \ uninstall-pkgincludeHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ucommon-6.4.4/inc/commoncpp/Makefile.am0000664000175000017500000000160712504227147014735 00000000000000# Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015 Cherokees of Idaho. # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. MAINTAINERCLEANFILES = Makefile.in Makefile RELEASE = $(LT_VERSION) -release $(LT_RELEASE) AM_CXXFLAGS = $(UCOMMON_FLAGS) pkgincludedir = $(includedir)/commoncpp pkginclude_HEADERS = config.h export.h string.h exception.h thread.h misc.h \ slog.h applog.h address.h socket.h tcp.h udp.h dccp.h mime.h file.h \ process.h pointer.h serial.h tokenizer.h numbers.h object.h \ commoncpp.h ucommon-6.4.4/inc/commoncpp/applog.h0000644000175000001440000003576112504227200014324 00000000000000// Copyright (C) 2005-2015 Angelo Naselli, Penta Engineering s.r.l. // // 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. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file commoncpp/applog.h * @short Application logging facilities abstraction. **/ #ifndef COMMONCPP_APPLOG_H_ #define COMMONCPP_APPLOG_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_SLOG_H_ #include #endif #ifndef COMMONCPP_EXCEPTION_H_ #include #endif #include #include #include #include namespace ost { using namespace std; /** * Produces a dump of a buffer in a hexdump way with its * code Ascii translation and relative buffer address. * * For instance: * 0000000 - 77 98 21 49 0e 00 05 00 40 1c 01 1c 2f 00 00 00 w.!I....@.../... * */ class __EXPORT HEXdump { protected: /** * output string */ std::string _str; public: // max_len: max number of bytes to be printed. 0 prints all. /** * HEXdump constructor. * * @param buffer buffer to be "hexdumped" * @param buff_len buffer length * @param max_len max number of bytes to be "hexdumped". Usefull to * truncate output. mas_len=0 does prints all. */ HEXdump(const unsigned char *buffer, int buff_len, int max_len = 200); /** * HEXdump destructor. */ virtual ~HEXdump() { _str = string();} /** * const char* cast provided for conveneince. */ const char * c_str() const { return _str.c_str(); } /** * string cast provided for conveneince. */ std::string str() { return _str; } /** * operator << * @param hd hexdump. * @return application logger stream */ friend std::ostream& operator<< (std::ostream& out, const HEXdump &hd) { out << hd.c_str(); return out; } }; #ifdef CCXX_EXCEPTIONS /** * Applog exception, used for memory problems at the moment * */ class __EXPORT AppLogException : public ost::Exception { public: /** * Constructor. * @param what_arg exception string */ AppLogException(const char *what_arg) : ost::Exception(what_arg) {} }; #endif class __LOCAL AppLogPrivate; /** * Application logger is a class that implements a logger that can be used * by applications to save log file somewhere on the system. * * It uses ost::slog to write to syslog and std::clog to write to standard * output. * * It provides either a stream oriented logger or a old printf style one. * * It can be used to log directly on a file or in a spooler like way. Latter * uses a ost::ThreadQueue to implement a thread safe access to logger. * * It provides a global stream variable called ost::alog. * * It provides an AppLog::Ident class that represents a module name for * instance that can be used to tag logs. Logging levels are the same * defined into ost::Slog: * Slog::levelEmergency * Slog::levelAlert * Slog::levelCritical * Slog::levelError * Slog::levelWarning * Slog::levelNotice * Slog::levelInfo * Slog::levelDebugfrom. * * Example of usage: alog << mod_name << debug << "Hello world!" << std::endl; */ class __EXPORT AppLog : protected streambuf, public ostream { protected: // d pointer AppLogPrivate *d; void writeLog(bool endOfLine = true); static std::map *assoc; public: /** * Ident class that represents module name. */ class __EXPORT Ident { private: std::string _ident; public: /** * Constructor. */ Ident() {} /** * Desctructor. */ ~Ident() {} /** * Copy constructor. */ Ident(Ident& id) {_ident = id._ident;} /** * const char* constructor, provided for convenience. */ Ident(const char *str) : _ident(str) {} /** * std::string cast. */ std::string& str() {return _ident;} /** * Assignment operator (string). */ Ident& operator= (std::string &st) {_ident = st; return *this;} /** * Assignment operator (const char[]), provided for convenience. */ Ident& operator= (const char str[]) {_ident = str; return *this;} /** * const char* cast provided for conveneince. */ const char* c_str() const {return _ident.c_str();} }; #ifndef _MSWINDOWS_ /** * Constructor for a customized logger. * @param logFileName log file name. * @param logDirectly true to write directly to file, false to use * a spooler like logger. * @param usePipe true to use pipe instead of file, false otherwise */ AppLog(const char* logFileName = NULL, bool logDirectly = false , bool usePipe = false); #else /** * Constructor for a customized logger. * @param logFileName log file name. * @param logDirectly true to write directly to file, false to use * a spooler like logger. */ AppLog(const char* logFileName = NULL, bool logDirectly = false); #endif /** * Destructor */ virtual ~AppLog(); /** * Subscribes the current thread to logger, it reserves thread safe * buffer for it. */ void subscribe(); /** * Unsubscribes the current thread from logger. */ void unsubscribe(); #ifndef _MSWINDOWS_ /** * Allows to set up ost::alog parameters. * @param FileName log file name. * @param logDirectly true to write directly to file, false to use * a spooler like logger. * @param usePipe true to use pipe instead of file, false otherwise */ void logFileName(const char* FileName, bool logDirectly = false, bool usePipe = false); #else /** * Allows to set up ost::alog parameters. * @param FileName log file name. * @param logDirectly true to write directly to file, false to use * a spooler like logger. */ void logFileName(const char* FileName, bool logDirectly = false); #endif /** * if logDirectly is set it closes the file. */ void close(void); /** * Sets the log level. * @param enable log level. */ void level(Slog::Level enable); /** * Enables clog output. * @param en true to enable clog output. */ void clogEnable(bool en = true); /** * Enables slog output for error level messages. * @param en true to enable slog output. */ void slogEnable(bool en = true); /** * Sets the level for that ident. * @param ident ident (module name for instance). * @param level level */ void identLevel(const char *ident, Slog::Level level); /** * Opens the file if not already and sets ident * @param ident module name for instance. */ void open(const char *ident); /** * stream overflow() overload. * @param c character to be managed * @return c */ virtual int overflow(int c); /** * stream sync() overload */ virtual int sync(); /** * emerg level printf style method, provided for convenience. * @param format printf format */ void emerg(const char *format, ...); /** * alert level printf style method, provided for convenience. * @param format printf format */ void alert(const char *format, ...); /** * critical level printf style method, provided for convenience. * @param format printf format */ void critical(const char *format, ...); /** * error level printf style method, provided for convenience. * @param format printf format */ void error(const char *format, ...); /** * warn level printf style method, provided for convenience. * @param format printf format */ void warn(const char *format, ...); /** * notice level printf style method, provided for convenience. * @param format printf format */ void notice(const char *format, ...); /** * info level printf style method, provided for convenience. * @param format printf format */ void info(const char *format, ...); /** * debug level printf style method, provided for convenience. * @param format printf format */ void debug(const char *format, ...); /** * operator to change ident and log level * @param ident ident (module name for instance) * @param level new log level * @return application logger stream */ AppLog &operator()(const char *ident, Slog::Level level = Slog::levelError); /** * operator to change ident * @param ident ident (module name for instance) * @return application logger stream */ inline AppLog& operator()(const Ident &ident) { open(ident.c_str()); return *this; } /** * operator to change logging level * @param level new log level * @return application logger stream */ AppLog &operator()(Slog::Level level); /** * manipulator operator, to change print levels. * @param (* pfManipulator)(AppLog &) * @return application logger stream */ AppLog& operator<< (AppLog& (*pfManipulator)(AppLog&)); /** * manipulator operator, to use ostream manipulators (i.e. std::endl,...) * @param (* pfManipulator)(AppLog &) * @return application logger stream */ AppLog& operator<< (ostream& (*pfManipulator)(ostream&)); friend ostream& operator << (ostream &os, AppLog & al) { return al; } /** * operator << * @param ident module name for instance. * @return application logger stream */ inline AppLog& operator<< (Ident &ident) { open(ident.c_str()); return *this; } /** * warn level * @return application logger stream */ inline AppLog &warn(void) {return operator()(Slog::levelWarning);} /** * error level * @return application logger stream */ AppLog &error(void) { return operator()(Slog::levelError);} /** * debug level * @return application logger stream */ inline AppLog &debug(void) {return operator()(Slog::levelDebug);} /** * emerg level * @return application logger stream */ inline AppLog &emerg(void) {return operator()(Slog::levelEmergency);} /** * alert level * @return application logger stream */ inline AppLog &alert(void) {return operator()(Slog::levelAlert);} /** * critical level * @return application logger stream */ inline AppLog &critical(void) {return operator()(Slog::levelCritical);} /** * notice level * @return application logger stream */ inline AppLog ¬ice(void) {return operator()(Slog::levelNotice);} /** * info level * @return application logger stream */ inline AppLog &info(void) {return operator()(Slog::levelInfo);} /** * Translates level from string to Slog::Level, useful for * configuration files for instance. * Valid level names are: * "emerg" for Slog::levelEmergency * "alert" for Slog::levelAlert * "critical" for Slog::levelCritical * "error" for Slog::levelError * "warn" for Slog::levelWarning * "notice" for Slog::levelNotice * "info" for Slog::levelInfo * "debug" for Slog::levelDebug * @param name Slog Level name * @return Slog level value */ static Slog::Level levelTranslate(string name) { std::map::iterator it = assoc->find(name); return (it != assoc->end()) ? it->second : Slog::levelEmergency; } }; /** * Manipulator for debug level * @param sl application logger stream * @return application logger stream */ __EXPORT inline AppLog &debug(AppLog& sl) {return sl.operator()(Slog::levelDebug);} /** * Manipulator for warn level * @param sl application logger stream * @return application logger stream */ __EXPORT inline AppLog &warn(AppLog& sl) {return sl.operator()(Slog::levelWarning);} /** * Manipulator for error level * @param sl application logger stream * @return application logger stream */ __EXPORT inline AppLog &error(AppLog& sl) { return sl.operator()(Slog::levelError);} /** * Manipulator for emerg level * @param sl application logger stream * @return application logger stream */ __EXPORT inline AppLog &emerg(AppLog& sl) {return sl.operator()(Slog::levelEmergency);} /** * Manipulator for alert level * @param sl application logger stream * @return application logger stream */ __EXPORT inline AppLog &alert(AppLog& sl) {return sl.operator()(Slog::levelAlert);} /** * Manipulator for critical level * @param sl application logger stream * @return application logger stream */ __EXPORT inline AppLog &critical(AppLog& sl) {return sl.operator()(Slog::levelCritical);} /** * Manipulator for notice level * @param sl application logger stream * @return application logger stream */ __EXPORT inline AppLog ¬ice(AppLog& sl) {return sl.operator()(Slog::levelNotice);} /** * Manipulator for info level * @param sl application logger stream * @return application logger stream */ __EXPORT inline AppLog &info(AppLog& sl) {return sl.operator()(Slog::levelInfo);} /** * alog global log stream definition */ __EXPORT extern AppLog alog; } // namespace ost #endif //___APPLOG_H___ ucommon-6.4.4/inc/commoncpp/file.h0000644000175000001440000005623012504227321013757 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file file.h * @short Files and dynamic loader services. **/ #ifndef COMMONCPP_FILE_H_ #define COMMONCPP_FILE_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_THREAD_H_ #include #endif #ifndef COMMONCPP_EXCEPTION_H_ #include #endif #ifndef WIN32 # ifdef __BORLANDC__ # include # include # else # include # include # endif # include # include # include #else # if __BORLANDC__ >= 0x0560 # include # include # else # include # endif #endif namespace ost { typedef unsigned long pos_t; #ifndef _MSWINDOWS_ // use a define so that if the sys/types.h header already defines caddr_t // as it may on BSD systems, we do not break it by redefining again. #undef caddr_t #define caddr_t char * typedef size_t ccxx_size_t; #else typedef DWORD ccxx_size_t; #endif #ifndef PATH_MAX #define PATH_MAX 256 #endif #ifndef NAME_MAX #define NAME_MAX 64 #endif class __EXPORT File { public: enum Error { errSuccess = 0, errNotOpened, errMapFailed, errInitFailed, errOpenDenied, errOpenFailed, errOpenInUse, errReadInterrupted, errReadIncomplete, errReadFailure, errWriteInterrupted, errWriteIncomplete, errWriteFailure, errLockFailure, errExtended }; typedef enum Error Error; enum Access { #ifndef _MSWINDOWS_ accessReadOnly = O_RDONLY, accessWriteOnly= O_WRONLY, accessReadWrite = O_RDWR #else accessReadOnly = GENERIC_READ, accessWriteOnly = GENERIC_WRITE, accessReadWrite = GENERIC_READ | GENERIC_WRITE #endif }; typedef enum Access Access; protected: typedef struct _fcb { struct _fcb *next; caddr_t address; ccxx_size_t len; off_t pos; bool locked; } fcb_t; public: #ifdef _MSWINDOWS_ enum Open { openReadOnly, // = FILE_OPEN_READONLY, openWriteOnly, // = FILE_OPEN_WRITEONLY, openReadWrite, // = FILE_OPEN_READWRITE, openAppend, // = FILE_OPEN_APPEND, openTruncate // = FILE_OPEN_TRUNCATE }; #else enum Open { openReadOnly = O_RDONLY, openWriteOnly = O_WRONLY, openReadWrite = O_RDWR, openAppend = O_WRONLY | O_APPEND, #ifdef O_SYNC openSync = O_RDWR | O_SYNC, #else openSync = O_RDWR, #endif openTruncate = O_RDWR | O_TRUNC }; typedef enum Open Open; /* to be used in future */ #ifndef S_IRUSR #define S_IRUSR 0400 #define S_IWUSR 0200 #define S_IRGRP 0040 #define S_IWGRP 0020 #define S_IROTH 0004 #define S_IWOTH 0002 #endif #endif // !WIN32 #ifndef _MSWINDOWS_ enum Attr { attrInvalid = 0, attrPrivate = S_IRUSR | S_IWUSR, attrGroup = attrPrivate | S_IRGRP | S_IWGRP, attrPublic = attrGroup | S_IROTH | S_IWOTH }; #else // defined WIN32 enum Attr { attrInvalid=0, attrPrivate, attrGroup, attrPublic }; #endif // !WIN32 typedef enum Attr Attr; #ifdef _MSWINDOWS_ enum Complete { completionImmediate, // = FILE_COMPLETION_IMMEDIATE, completionDelayed, // = FILE_COMPLETION_DELAYED, completionDeferred // = FILE_COMPLETION_DEFERRED }; enum Mapping { mappedRead, mappedWrite, mappedReadWrite }; #else enum Mapping { mappedRead = accessReadOnly, mappedWrite = accessWriteOnly, mappedReadWrite = accessReadWrite }; enum Complete { completionImmediate, completionDelayed, completionDeferred }; #endif typedef enum Complete Complete; typedef enum Mapping Mapping; public: static const char *getExtension(const char *path); static const char *getFilename(const char *path); static char *getFilename(const char *path, char *buffer, size_t size = NAME_MAX); static char *getDirname(const char *path, char *buffer, size_t size = PATH_MAX); static char *getRealpath(const char *path, char *buffer, size_t size = PATH_MAX); }; /** * A low level portable directory class. Used to support ccstd Directory * container. This provides a basic mechanism for allocating and * accessing file entries. * * @author David Sugar * @short low level directory access class. */ class __EXPORT Dir : public File { private: #ifndef _MSWINDOWS_ DIR *dir; struct dirent *save; char save_space[sizeof(struct dirent) + PATH_MAX + 1]; struct dirent *entry; #else HANDLE hDir; WIN32_FIND_DATA data, fdata; char *name; #endif public: Dir(const char *name = NULL); static bool create(const char *path, Attr attr = attrGroup); static bool remove(const char *path); static bool setPrefix(const char *path); static bool getPrefix(char *path, size_t size = PATH_MAX); void open(const char *name); void close(void); virtual ~Dir(); const char *getName(void); const char *operator++() {return getName();} const char *operator++(int) {return getName();} const char *operator*(); bool rewind(void); bool operator!() #ifndef _MSWINDOWS_ {return !dir;} #else {return hDir != INVALID_HANDLE_VALUE;} #endif bool isValid(void); }; /** * A generic class to walk a hierarchical directory structure. * * @author David Sugar * @short Directory tree walking. */ class __EXPORT DirTree { private: char path[PATH_MAX + 1]; Dir *dir; unsigned max, current, prefixpos; protected: /** * Virtual method to filter results. Virtual override methods * should call baseclass method to assure . and .. names are * stripped out. * * @return true if current filename is accepted. * @param file path to examine * @param ino info of type, date, etc. */ virtual bool filter(const char *file, struct stat *ino); public: /** * Construct a directory tree walk starting at the specified * prefix. A maximum subdirectory depth is also specified. * * @param prefix to start walk. * @param maxdepth subdirectory depth to examine. */ DirTree(const char *prefix, unsigned maxdepth); /** * Construct an un-opened directory tree of a known maximum depth * * @param maxdepth subdirectory subdirectory depth. */ DirTree(unsigned maxdepth); virtual ~DirTree(); /** * Open a directory tree path. * * @param prefix directory path to open. */ void open(const char *prefix); /** * Close the directory path. */ void close(void); /** * Extract the next full pathname from the directory walk. * When returning directories, a '/' is appended. The * returned string is a buffer of MAX_PATH size. * * @return path of next subdirectory entry or NULL. */ char *getPath(void); /** * This is used to step through the filter virtual for an * entire subtree, and is used for cases where a derived * DirTree class performs it's primary operations through * filter rather than externally by calling getPath(). * * @return number of files and directories examined. * @param prefix directory path to examine. */ unsigned perform(const char *prefix); }; /** * The purpose of this class is to define a base class for low level * random file access that is portable between Win32 and Posix systems. * This class is a foundation both for optimized thread shared and * traditional locked file access that is commonly used to build * database services, rather than the standard C++ streaming file classes. * * @author David Sugar * @short Portable random disk file access. */ class __EXPORT RandomFile : protected Mutex, public File { private: Error errid; char *errstr; protected: #ifndef _MSWINDOWS_ int fd; // FIXME: WIN32 as no access member Access access; #else HANDLE fd; #endif char *pathname; struct { unsigned count : 16; bool thrown : 1; bool initial : 1; #ifndef _MSWINDOWS_ bool immediate : 1; #endif bool temp : 1; } flags; /** * Create an unopened random access file. */ RandomFile(const char *name = NULL); /** * Default copy constructor. */ RandomFile(const RandomFile &rf); /** * Post an error event. * * @return error code. * @param errid error code. * @param errstr error message string. */ Error error(Error errid, char *errstr = NULL); /** * Post an extended string error message. * * @return errExtended. * @param err error string. */ inline Error error(char *err) {return error(errExtended, err);} /** * Used to enable or disable throwing of exceptions on * errors. * * @param enable true if errors will be thrown. */ inline void setError(bool enable) {flags.thrown = !enable;} #ifndef _MSWINDOWS_ /** * Used to set file completion modes. * * @return errSuccess if okay. * @param mode completion mode. * @todo implement in win32 */ Error setCompletion(Complete mode); #endif /** * Used to set the temporary attribute for the file. Temporary * files are automatically deleted when closed. * * @param enable true for marking as temporary. */ inline void setTemporary(bool enable) {flags.temp = enable;} /** * This method is used to initialize a newly created file as * indicated by the "initial" flag. This method also returns * the file access permissions that should be associated with * the file. This method should never be called directly, but * is instead used to impliment the "Initial" method. Typically * one would use this to build an empty database shell when a * previously empty database file is created. * * @return access, or attrInvalid if should be removed. */ virtual Attr initialize(void); /** * Close the file. */ void final(void); public: /** * Destroy a random access file or it's derived class. */ virtual ~RandomFile(); /** * This method should be called right after a RandomFile derived * object has been created. This method will invoke initialize * if the object is newly created, and set file access permissions * appropriately. * * @return true if file had to be initialized. */ bool initial(void); /** * Get current file capacity. * * @return total file size. */ off_t getCapacity(void); /** * This method is commonly used to close and re-open an existing * database. This may be used when the database has been unlinked * and an external process provides a new one to use. */ virtual Error restart(void); /** * Return current error id. * * @return last error identifier set. */ inline Error getErrorNumber(void) {return errid;} /** * Return current error string. * * @return last error string set. */ inline char *getErrorString(void) {return errstr;} bool operator!(void); }; /** * This class defines a database I/O file service that can be shared * by multiple processes. Each thread should access a dup of the database * object, and mutex locks can be used to preserve transaction * integrety if multiple threads are used. * * SharedFile is used when a database may be shared between multiple * processes. SharedFile automatically applies low level byte-range "file * locks", and provides an interface to fetch and release byte-range locked * portions of a file. * * @author David Sugar * @short This class defines a database I/O file service that can be shared by multiple processes. */ class __EXPORT SharedFile : public RandomFile { private: fcb_t fcb; Error open(const char *path); public: /** * Open or create a new database file. You should also use * Initial. * * @param path pathname of database to open. */ SharedFile(const char *path); /** * Create a shared file as a duplicate of an existing shared * file. * * @param file original file. */ SharedFile(const SharedFile &file); /** * Close and finish a database file. */ virtual ~SharedFile(); /** * Restart an existing database; close and re-open. * * @return errSuccess if successful. */ Error restart(void) {return open(pathname);} /** * Lock and Fetch a portion of the file into physical memory. * This can use state information to fetch the current record * multiple times. * * @return errSuccess on success. * @param address address to use, or NULL if same as last I/O. * @param length length to use, or 0 if same as last I/O. * @param position file position to use -1 if same as last I/O. */ Error fetch(caddr_t address = NULL, ccxx_size_t length = 0, off_t position = -1); /** * Update a portion of a file from physical memory. This can use * state information to commit the last read record. The current * lock is also cleared. * * @return errSuccess on success. * @param address address to use, or NULL if same as last I/O. * @param length length to use, or 0 if same as last I/O. * @param position file position to use or -1 if same as last I/O. */ Error update(caddr_t address = NULL, ccxx_size_t length = 0, off_t position = -1); /** * Clear a lock held from a previous fetch operation without * updating. * * @return errSuccess on success. * @param length length to use, or 0 if same as last I/O. * @param pos file position to use or -1 if same as last I/O. */ Error clear(ccxx_size_t length = 0, off_t pos = -1); /** * Add new data to the end of the file. Locks file during append. * * @param address address to use, or NULL if same as last I/O. * @param length length to use, or 0 if same as last I/O. */ Error append(caddr_t address = NULL, ccxx_size_t length = 0); /** * Fetch the current file position marker for this thread. * * @return file position offset. */ off_t getPosition(void); bool operator++(void); bool operator--(void); }; /** * Create and map a disk file into memory. This portable class works * under both Posix via mmap and under the win32 API. A mapped file * can be referenced directly by it's memory segment. One can map * and unmap portions of a file on demand, and update * changed memory pages mapped from files immediately through sync(). * * @author David Sugar * @short Map a named disk file into memory. */ class __EXPORT MappedFile : public RandomFile { private: fcb_t fcb; int prot; #ifdef _MSWINDOWS_ HANDLE map; char mapname[64]; #endif public: /** * Open a file for mapping. More than one segment of a file * may be mapped into seperate regions of memory. * * @param fname file name to access for mapping. * @param mode access mode to map file. */ MappedFile(const char *fname, Access mode); /** * Create if not exists, and map a file of specified size * into memory. * * @param fname file name to access for mapping. * @param mode access mode to map file. * @param size of file to map. */ MappedFile(const char *fname, Access mode, size_t size); /** * Map a portion or all of a specified file in the specified * shared memory access mode. Valid mapping modes include * mappedRead, mappedWrite, and mappedReadWrite. * * @param fname pathname of file to map into memory. * @param offset from start of file to begin mapping in bytes. * @param size of mapped area in bytes. * @param mode to map file. */ MappedFile(const char *fname, pos_t offset, size_t size, Access mode); /** * Release a mapped section of memory associated with a file. The * mapped area is updated back to disk. */ virtual ~MappedFile(); // FIXME: not use library function in header ?? /** * Synchronize the contents of the mapped portion of memory with * the disk file and wait for completion. This assures the memory * mapped from the file is written back. */ void sync(void); /** * Synchronize a segment of memory mapped from a segment fetch. * * @param address memory address to update. * @param len size of segment. */ void sync(caddr_t address, size_t len); /** * Map a portion of the memory mapped from the file back to the * file and do not wait for completion. This is useful when mapping * a database file and updating a single record. * * @param offset offset into the mapped region of memory. * @param len length of partial region (example, record length). */ void update(size_t offset = 0, size_t len = 0); /** * Update a mapped region back to disk as specified by address * and length. * * @param address address of segment. * @param len length of segment. */ void update(caddr_t address, size_t len); /** * Release (unmap) a memory segment. * * @param address address of memory segment to release. * @param len length of memory segment to release. */ void release(caddr_t address, size_t len); /** * Fetch a pointer to an offset within the memory mapped portion * of the disk file. This really is used for convience of matching * operations between Update and Fetch, as one could simply have * accessed the base pointer where the file was mapped directly. * * @param offset from start of mapped memory. */ inline caddr_t fetch(size_t offset = 0) {return ((char *)(fcb.address)) + offset;} /** * Fetch and map a portion of a disk file to a logical memory * block. * * @return pointer to memory segment. * @param pos offset of file segment to map. * @param len size of memory segment to map. */ caddr_t fetch(off_t pos, size_t len); /** * Lock the currently mapped portion of a file. * * @return true if pages are locked. */ bool lock(void); /** * Unlock a locked mapped portion of a file. */ void unlock(void); /** * Compute map size to aligned page boundry. * * @param size request. * @return page aligned size. */ size_t pageAligned(size_t size); }; /** * The DSO dynamic loader class is used to load object files. On * elf based systems this is typically done with dlopen. A dummy * stub class is generated for non-dl capable systems. * * @author David Sugar * @short Dynamic class file loader. */ class __EXPORT DSO { private: const char *err; static Mutex mutex; static DSO *first; static DSO *last; DSO *next, *prev; const char *id; void *image; typedef ucommon::dso::addr_t addr_t; protected: void loader(const char *filename, bool resolve); public: /** * Construct and load a DSO object file. * * @param filename pathname of object file to load. */ DSO(const char *filename) {loader(filename, true);} DSO(const char *filename, bool resolve) {loader(filename, resolve);} /** * Retrieve error indicator associated with DSO failure. This * is often used in catch handlers. */ inline const char *getError(void) {return err;} /** * Detach a DSO object from running memory. */ virtual ~DSO(); /** * Lookup a symbol in the loaded file. */ addr_t operator[](const char *sym); static void dynunload(void); /** * Find a specific DSO object by filename. * * @param name of DSO object file (partial). */ static DSO *getObject(const char *name); /** * See if DSO object is valid. * * @return true if valid. */ bool isValid(void); /** * Install debug handler... */ static void setDebug(void); }; /** @relates RandomFile */ bool __EXPORT isDir(const char *path); /** @relates RandomFile */ bool __EXPORT isFile(const char *path); #ifndef WIN32 /** @relates RandomFile */ bool __EXPORT isDevice(const char *path); #else /** @relates RandomFile */ inline bool isDevice(const char *path) { return false; } #endif /** @relates RandomFile */ bool __EXPORT canAccess(const char *path); /** @relates RandomFile */ bool __EXPORT canModify(const char *path); /** @relates RandomFile */ time_t __EXPORT lastModified(const char *path); /** @relates RandomFile */ time_t __EXPORT lastAccessed(const char *path); #ifdef COMMON_STD_EXCEPTION class DirException : public IOException { public: DirException(const String &str) : IOException(str) {}; }; class __EXPORT DSOException : public IOException { public: DSOException(const String &str) : IOException(str) {}; }; class __EXPORT FileException : public IOException { public: FileException(const String &str) : IOException(str) {}; }; #endif } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/socket.h0000644000175000001440000004521712504227556014345 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2013 David Sugar, Tycho Softworks. // Copyright (C) 2014 David Sugar, Tycho Softworks, Savoir-Faire Linux Inc. // Copyright (C) 2015 Cherokees of Idaho, Savoir-Faire Linux Inc. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file commoncpp/socket.h * @short socket operations. **/ #ifndef COMMONCPP_SOCKET_H_ #define COMMONCPP_SOCKET_H_ #include #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_STRING_H_ #include #endif #ifndef COMMONCPP_ADDRESS_H_ #include #endif #ifndef COMMONCPP_EXCEPTION_H_ #include #endif #ifndef MSG_DONTWAIT #define MSG_DONTWAIT 0 #endif #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif #ifndef SOCK_DCCP #define SOCK_DCCP 6 #endif #ifndef IPPROTO_DCCP #define IPPROTO_DCCP 33 #endif #ifndef SOL_DCCP #define SOL_DCCP 269 #endif #define DCCP_SOCKOPT_AVAILABLE_CCIDS 12 #define DCCP_SOCKOPT_CCID 13 #define DCCP_SOCKOPT_TX_CCID 14 #define DCCP_SOCKOPT_RX_CCID 15 namespace ost { typedef socket_t SOCKET; class __EXPORT Socket : protected ucommon::Socket { public: enum State { INITIAL, AVAILABLE, BOUND, CONNECTED, CONNECTING, STREAM }; typedef enum State State; enum Family { #ifdef CCXX_IPV6 IPV6 = AF_INET6, #endif IPV4 = AF_INET }; typedef enum Family Family; enum Error { errSuccess = 0, errCreateFailed, errCopyFailed, errInput, errInputInterrupt, errResourceFailure, errOutput, errOutputInterrupt, errNotConnected, errConnectRefused, errConnectRejected, errConnectTimeout, errConnectFailed, errConnectInvalid, errConnectBusy, errConnectNoRoute, errBindingFailed, errBroadcastDenied, errRoutingDenied, errKeepaliveDenied, errServiceDenied, errServiceUnavailable, errMulticastDisabled, errTimeout, errNoDelay, errExtended, errLookupFail, errSearchErr, errInvalidValue }; typedef enum Error Error; enum Tos { tosLowDelay = 0, tosThroughput, tosReliability, tosMinCost, tosInvalid }; typedef enum Tos Tos; enum Pending { pendingInput, pendingOutput, pendingError }; typedef enum Pending Pending; private: // used by exception handlers.... mutable Error errid; mutable const char *errstr; mutable long syserr; void setSocket(void); protected: static socket_t dupSocket(socket_t s,Socket::State state); mutable struct { bool thrown: 1; bool broadcast: 1; bool route: 1; bool keepalive: 1; bool loopback: 1; bool multicast: 1; bool completion: 1; bool linger: 1; unsigned ttl: 8; } flags; State volatile state; /** * This service is used to throw all socket errors which usually * occur during the socket constructor. * * @param error defined socket error id. * @param err string or message to pass. * @param systemError the system error# that caused the error */ Error error(Error error, const char *err = NULL, long systemError = 0) const; /** * This service is used to throw application defined socket errors * where the application specific error code is a string. * * @param err string or message to pass. */ inline void error(const char *err) const {error(errExtended, err);} /** * This service is used to turn the error handler on or off for * "throwing" exceptions by manipulating the thrown flag. * * @param enable true to enable handler. */ inline void setError(bool enable) {flags.thrown = !enable;} /** * Used as the default destructor for ending a socket. This * will cleanly terminate the socket connection. It is provided * for use in derived virtual destructors. */ void endSocket(void); /** * Used as a common handler for connection failure processing. * * @return correct failure code to apply. */ Error connectError(void); /** * Set the send limit. */ Error sendLimit(int limit = 2048); /** * Set thr receive limit. */ Error receiveLimit(int limit = 1); /** * Set the send timeout for sending raw network data. * * @return errSuccess if set. * @param timer value in millisec. */ Error sendTimeout(timeout_t timer); /** * Receive timeout for receiving raw network data. * * @return errSuccess if set. * @param timer value in milliseconds. */ Error receiveTimeout(timeout_t timer); /** * Set the protocol stack network kernel send buffer size * associated with the socket. * * @return errSuccess on success, or error. * @param size of buffer in bytes. */ Error sendBuffer(unsigned size); /** * Set the protocol stack network kernel receive buffer size * associated with the socket. * * @return errSuccess on success, or error. * @param size of buffer in bytes. */ Error receiveBuffer(unsigned size); /** * Set the total protocol stack network kernel buffer size * for both send and receive together. * * @return errSuccess on success * @param size of buffer. */ Error bufferSize(unsigned size); /** * Set the subnet broadcast flag for the socket. This enables * sending to a subnet and may require special image privileges * depending on the operating system. * * @return 0 (errSuccess) on success, else error code. * @param enable when set to true. */ Error setBroadcast(bool enable); /** * Setting multicast binds the multicast interface used for * the socket to the interface the socket itself has been * implicitly bound to. It is also used as a check flag * to make sure multicast is enabled before multicast * operations are used. * * @return 0 (errSuccess) on success, else error code. * @param enable when set to true. * @param family of protocol. */ Error setMulticastByFamily(bool enable, Family family = IPV4); /** * Set the multicast loopback flag for the socket. Loopback * enables a socket to hear what it is sending. * * @return 0 (errSuccess) on success, else error code. * @param enable when set to true. * @param family of protocol. */ Error setLoopbackByFamily(bool enable, Family family = IPV4); /** * Set the multicast time to live for a multicast socket. * * @return 0 (errSuccess) on success, else error code. * @param ttl time to live. * @param fam family of protocol. */ Error setTimeToLiveByFamily(unsigned char ttl, Family fam = IPV4); /** * Join a multicast group. * * @return 0 (errSuccess) on success, else error code. * @param ia address of multicast group to join. */ Error join(const ucommon::Socket::address &ia, int iface = 0); inline Error join(const IPV4Multicast &ia) { return join(ucommon::Socket::address(getaddress(ia))); } #ifdef CCXX_IPV6 inline Error join(const IPV6Multicast &ia, int iface = 0) { return join(ucommon::Socket::address(getaddress(ia)), iface); } #endif /** * Drop membership from a multicast group. * * @return 0 (errSuccess) on success, else error code. * @param ia address of multicast group to drop. */ Error drop(const ucommon::Socket::address &ia, int iface = 0); Error drop(const IPV4Multicast &ia) { return drop(ucommon::Socket::address(getaddress(ia))); } #ifdef CCXX_IPV6 Error drop(const IPV6Multicast &ia, int iface = 0) { return drop(ucommon::Socket::address(getaddress(ia)), iface); } #endif /** * Set the socket routing to indicate if outgoing messages * should bypass normal routing (set false). * * @return 0 on success. * @param enable normal routing when set to true. */ Error setRouting(bool enable); /** * Enable/disable delaying packets (Nagle algorithm) * * @return 0 on success. * @param enable disable Nagle algorithm when set to true. */ Error setNoDelay(bool enable); /** * An unconnected socket may be created directly on the local * machine. Sockets can occupy both the internet domain (AF_INET) * and UNIX socket domain (AF_UNIX) under unix. The socket type * (SOCK_STREAM, SOCK_DGRAM) and protocol may also be specified. * If the socket cannot be created, an exception is thrown. * * @param domain socket domain to use. * @param type base type and protocol family of the socket. * @param protocol specific protocol to apply. */ Socket(int domain, int type, int protocol = 0); /** * A socket object may be created from a file descriptor when that * descriptor was created either through a socket() or accept() * call. This constructor is mostly for internal use. * * @param fd file descriptor of an already existing socket. */ Socket(socket_t fd); /** * Create an inactive socket object for base constructors. */ Socket(); /** * A socket can also be constructed from an already existing * Socket object. On POSIX systems, the socket file descriptor * is dup()'d. On Win32, DuplicateHandle() is used. * * @param source of existing socket to clone. */ Socket(const Socket &source); /** * Process a logical input line from a socket descriptor * directly. * * @param buf pointer to string. * @param len maximum length to read. * @param timeout for pending data in milliseconds. * @return number of bytes actually read. */ ssize_t readLine(char *buf, size_t len, timeout_t timeout = 0); /** * Read in a block of len bytes with specific separator. Can * be zero, or any other char. If \\n or \\r, it's treated just * like a readLine(). Otherwise it looks for the separator. * * @param buf pointer to byte allocation. * @param len maximum length to read. * @param separator separator for a particular ASCII character * @param t timeout for pending data in milliseconds. * @return number of bytes actually read. */ virtual ssize_t readData(void * buf,size_t len,char separator=0,timeout_t t=0); /** * Write a block of len bytes to socket. * * @param buf pointer to byte allocation. * @param len maximum length to write. * @param t timeout for pending data in milliseconds. * @return number of bytes actually written. */ virtual ssize_t writeData(const void* buf,size_t len,timeout_t t=0); public: ~Socket(); /** * Often used by a "catch" to fetch the last error of a thrown * socket. * * @return error number of Error error. */ inline Error getErrorNumber(void) const {return errid;} /** * Often used by a "catch" to fetch the user set error string * of a thrown socket, but only if EXTENDED error codes are used. * * @return string for error message. */ inline const char *getErrorString(void) const {return errstr;} inline long getSystemError(void) const {return syserr;} const char *getSystemErrorString(void) const; /** * Get the status of pending operations. This can be used to * examine if input or output is waiting, or if an error has * occured on the descriptor. * * @return true if ready, false on timeout. * @param pend ready check to perform. * @param timeout in milliseconds, inf. if not specified. */ virtual bool isPending(Pending pend, timeout_t timeout = TIMEOUT_INF); /** * See if a specific protocol family is available in the * current runtime environment. * * @return true if family available. */ static bool check(Family fam); /** * Operator based testing to see if a socket is currently * active. */ bool operator!() const; operator bool() const; /** * Sockets may also be duplicated by the assignment operator. */ Socket &operator=(const Socket &from); /** * May be used to examine the origin of data waiting in the * socket receive queue. This can tell a TCP server where pending * "connect" requests are coming from, or a UDP socket where it's * next packet arrived from. * * @param port ptr to port number of sender. * @return host address, test with "isInetAddress()". */ ucommon::Socket::address getSender() const; virtual IPV4Host getIPV4Sender(tpport_t *port = NULL) const; inline IPV4Host getSender(tpport_t *port) const {return getIPV4Sender(port);} #ifdef CCXX_IPV6 virtual IPV6Host getIPV6Sender(tpport_t *port = NULL) const; #endif /** * Get the host address and port of the socket this socket * is connected to. If the socket is currently not in a * connected state, then a host address of 0.0.0.0 is * returned. * * @param port ptr to port number of remote socket. * @return host address of remote socket. */ ucommon::Socket::address getPeer() const; IPV4Host getIPV4Peer(tpport_t *port = NULL) const; inline IPV4Host getPeer(tpport_t *port) const {return getIPV4Peer(port);} #ifdef CCXX_IPV6 IPV6Host getIPV6Peer(tpport_t *port = NULL) const; #endif /** * Get the local address and port number this socket is * currently bound to. * * @param port ptr to port number on local host. * @return host address of interface this socket is bound to. */ IPV4Host getIPV4Local(tpport_t *port = NULL) const; inline IPV4Host getLocal(tpport_t *port) const {return getIPV4Local(port);} #ifdef CCXX_IPV6 IPV6Host getIPV6Local(tpport_t *port = NULL) const; #endif ucommon::Socket::address getLocal() const; /** * Used to specify blocking mode for the socket. A socket * can be made non-blocking by setting setCompletion(false) * or set to block on all access with setCompletion(true). * I do not believe this form of non-blocking socket I/O is supported * in winsock, though it provides an alternate asynchronous set of * socket services. * * @param immediate mode specify socket I/O call blocking mode. */ void setCompletion(bool immediate); /** * Enable lingering sockets on close. * * @param linger specify linger enable. */ Error setLinger(bool linger); /** * Set the keep-alive status of this socket and if keep-alive * messages will be sent. * * @return 0 on success. * @param enable keep alive messages. */ Error setKeepAlive(bool enable); /** * Set packet scheduling on platforms which support ip quality * of service conventions. This effects how packets in the * queue are scheduled through the interface. * * @return 0 on success, error code on failure. * @param service type of service enumerated type. */ Error setTypeOfService(Tos service); /** * Can test to see if this socket is "connected", and hence * whether a "catch" can safely call getPeer(). Of course, * an unconnected socket will return a 0.0.0.0 address from * getPeer() as well. * * @return true when socket is connected to a peer. */ bool isConnected(void) const; /** * Test to see if the socket is at least operating or if it * is mearly initialized. "initialized" sockets may be the * result of failed constructors. * * @return true if not in initial state. */ bool isActive(void) const; /** * Return if broadcast has been enabled for the specified * socket. * * @return true if broadcast socket. */ inline bool isBroadcast(void) const {return flags.broadcast;} /** * Return if socket routing is enabled. * * @return true if routing enabled. */ inline bool isRouted(void) const {return flags.route;} inline struct in_addr getaddress(const IPV4Address &ia) {return ia.getAddress();} #ifdef CCXX_IPV6 inline struct in6_addr getaddress(const IPV6Address &ia) {return ia.getAddress();} #endif }; #if defined(CCXX_EXCEPTIONS) class __EXPORT SockException : public IOException { private: Socket::Error _socketError; public: inline SockException(const String &str, Socket::Error socketError, long systemError = 0) : IOException(str, systemError), _socketError(socketError) {} inline Socket::Error getSocketError() const {return _socketError;} }; #endif } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/tokenizer.h0000644000175000001440000002616012504227642015057 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file tokenizer.h * @short string tokenizer. **/ #ifndef COMMONCPP_TOKENIZER_H_ #define COMMONCPP_TOKENIZER_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_THREAD_H_ #include #endif #ifndef COMMMONCPP_EXCEPTION_H_ #include #endif namespace ost { /** * 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 __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 __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; if ( token ) delete [] token; 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;} }; } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/process.h0000644000175000001440000002043212504227427014520 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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. // /** * @file commoncpp/process.h * @short Process services. **/ #ifndef COMMONCPP_PROCESS_H_ #define COMMONCPP_PROCESS_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_THREAD_H_ #include #endif namespace ost { /** * A class for containing portable process related functions * that help create portable code. These are typically * referenced thru Process::xxx static member functions. * Many of these members are used both for win32 and posix * systems although some may be platform specific. * * @short Peocess wrapper class. * @author David Sugar */ class __EXPORT Process { private: static bool rtflag; public: #ifndef _MSWINDOWS_ typedef void (*Trap)(int); /** * Detach current process into a daemon, posix * only. Perhaps a similar method can be used * for creating win32 "services"? */ static void detach(void); /** * Attach the current process to another device * or i/o session. It is deamonified and dissasociated * with the prior parent process and controlling terminal. * * @param devname path to attach to. */ static void attach(const char *devname); /** * Set a posix compliant signal handler. * * @return previous handler. * @param signo signal no. * @param handler trap handler. */ static Trap setPosixSignal(int signo, Trap handler); /** * Set system call interuptable signal handler. * * #return previous handler. * @param signo signal no. * @param handler trap handler. */ static Trap setInterruptSignal(int signo, Trap handler); #endif /** * Lock a process in memory. Ideally you should be deep enough * where additional memallocs for functions will not kill you, * or use false for future. * * @return true if successful. * @param future pages as well... */ bool lock(bool future = true); /** * Unlock process pages. */ void unlock(void); /** * Spawn a process and wait for it's exit code. In win32 * this is done with the spawn system call. In posix, * this is done with a fork, an execvp, and a waitpid. * * @warning The implementation differences between posix and * win32 systems may cause side effects. For instance, if you * use atexit() and this spawn method, on posix systems the * function set up with atexit() will be called when the * parent process of the fork exits, which will not happen on * Win32 systems. * * @return error code from process. * @param exec name of executable. * @param argv list of command arguments. * @param wait for process to exit before return. */ static int spawn(const char *exec, const char **argv, bool wait = true); /** * Get the exit status of another process, waiting for it * to exit. * * @return exit code from process. * @param pid process id. */ static int join(int pid); /** * Cancel a running child process. * * @return 0 on success. * @param pid process id. * @param sig cancel signal to apply. */ static bool cancel(int pid, int sig = 0); /** * Get system environment. * * @return system environ symbol. * @param name of symbol. */ static const char *getEnv(const char *name); /** * Set system environment in a standard manner. * * @param name of environment symbol to set. * @param value of environment symbol. * @param overwrite true if replace existing symbol. */ static void setEnv(const char *name, const char *value, bool overwrite); /** * Get etc prefix path. * * @return etc prefix. */ static const char *getConfigDir(void); /** * Get home directory. * * @return user home directory. */ static const char *getHomeDir(void); /** * Get user name. * * @return user login id. */ static const char *getUser(void); /** * Set user id by name. * * @return true if successful. */ static bool setUser(const char *id, bool grp = true); /** * Set the effective group id by name. * * @return true if successful. */ static bool setGroup(const char *id); /** * Return the effective operating system page size. * * @return system page size. */ static size_t getPageSize(void); /** * Used to set process priority and optionally enable realtime. */ static void setPriority(int pri); /** * Used to set process scheduling policy. */ static void setScheduler(const char *policy); /** * Portable shortcut for setting realtime... */ static void setRealtime(int pri = 0); /** * Return true if scheduler settable. */ static bool isScheduler(void); /** * Return true if realtime scheduling. */ static inline bool isRealtime(void) {return rtflag;} }; /** * This class is used to create a "named" lock entity that can be used * to control access to a resource between multiple processes. The * posix implimentation uses a pidfile and the win32 version uses a * globally visible mutex. * * @author David Sugar * @short System-wide named lock */ class __EXPORT Lockfile { private: #ifdef _MSWINDOWS_ HANDLE _mutex; bool _flagged; #else char *_path; #endif public: /** * Create a lock under a known name. * * @param name of system-wide lock to create. */ Lockfile(const char *name); /** * Create a new lock object that can be used to make locks. */ Lockfile(); /** * Destroy the current lock and release it. */ ~Lockfile() {unlock();} /** * Lock a system-wide name for this process. If the lock * is successful, return true. If an existing lock was * already acquired, release it first. * * @return true if lock successful. * @param name system-wide lock to use. */ bool lock(const char *name); /** * Release an acquired lock. */ void unlock(void); /** * Flag if the current process has aqcuired a lock. * * @return true if we have the lock. */ bool isLocked(void); }; } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/numbers.h0000644000175000001440000001323312504227363014515 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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 COMMONCPP_NUMBERS_H_ #define COMMONCPP_NUMBERS_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif #ifndef COMMONCPP_STRING_H_ #include #endif typedef ucommon::DateTimeString DateTimeString; typedef ucommon::DateNumber DateNumber; namespace ost { class __EXPORT Date : public ucommon::Date { protected: inline void toJulian(long year, long month, long day) {ucommon::Date::set(year, month, day);} inline void fromJulian(char *buf) const {put(buf);} public: inline Date(time_t value) : ucommon::Date(value) {} inline Date(struct tm *object) : ucommon::Date(object) {} inline Date(const char *ptr, size_t size = 0) : ucommon::Date(ptr, size) {} inline Date(int y, unsigned m, unsigned d) : ucommon::Date(y, m, d) {} inline Date(const Date& object) : ucommon::Date(object) {} inline Date() : ucommon::Date() {} inline int getYear(void) const {return year();} inline unsigned getMonth(void) const {return month();} inline unsigned getDay(void) const {return day();} inline unsigned getDayOfWeek(void) const {return dow();} inline long getJulian(void) const {return julian;} inline const char *get(char *buffer) const {return put(buffer);} inline time_t getTime(void) const {return timeref();} inline bool isValid(void) const {return is_valid();} }; class __EXPORT Time : public ucommon::Time { protected: inline void toSeconds(int h, int m = 0, int s = 0) {set(h, m, s);} inline void fromSeconds(char *buf) const {put(buf);} public: inline Time(time_t value) : ucommon::Time(value) {} inline Time(tm_t *object) : ucommon::Time(object) {} inline Time(const char *ptr, size_t size) : ucommon::Time(ptr, size) {} inline Time(int h, int m, int s) : ucommon::Time(h, m, s) {} inline Time() : ucommon::Time() {} inline int getHour(void) const {return hour();} inline int getMinute(void) const {return minute();} inline int getSecond(void) const {return second();} inline const char *get(char *buffer) const {return put(buffer);} inline bool isValid(void) const {return is_valid();} }; class __EXPORT DateTime : public ucommon::DateTime { public: inline DateTime(time_t time) : ucommon::DateTime(time) {} inline DateTime(struct tm *dt) : ucommon::DateTime(dt) {} inline DateTime(int year, unsigned month, unsigned day, int hour = 0, int minute = 0, int second = 0) : ucommon::DateTime(year, month, day, hour, minute, second) {} inline DateTime(const char *ptr, size_t size) : ucommon::DateTime(ptr, size) {} inline DateTime(const DateTime& obj) : ucommon::DateTime(obj) {} inline DateTime() : ucommon::DateTime() {} inline int getYear(void) const {return year();} inline unsigned getMonth(void) const {return month();} inline unsigned getDay(void) const {return day();} inline unsigned getDayOfWeek(void) const {return dow();} inline long getJulian(void) const {return julian;} inline const char *get(char *buffer) const {return ucommon::DateTime::put(buffer);} inline time_t getTime(void) const {return ucommon::DateTime::timeref();} inline bool isValid(void) const {return ucommon::DateTime::is_valid();} inline int getHour(void) const {return hour();} inline int getMinute(void) const {return minute();} inline int getSecond(void) const {return second();} inline static tm_t *glt(time_t *time = NULL) {return ucommon::DateTime::local(time);} }; } // namespace ost #endif ucommon-6.4.4/inc/commoncpp/config.h0000644000175000001440000000556312504227233014312 00000000000000// Copyright (C) 2009-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // 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 Lesser General Public License // along with this program. If not, see . // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. 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 GNU // Common C++. If you copy code from other releases into a copy of GNU // 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 GNU 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 COMMONCPP_CONFIG_H_ #define COMMONCPP_CONFIG_H_ #ifndef _UCOMMON_UCOMMON_H_ #include #endif #ifdef __EXPORT #undef __EXPORT #endif #define __EXPORT __SHARED // #include #include #define COMMONCPP_HEADERS #define CCXX_NAMESPACES #define COMMONCPP_NAMESPACE ost #define NAMESPACE_COMMONCPP namespace ost { #define TIMEOUT_INF ucommon::Timer::inf #ifndef UCOMMON_SYSRUNTIME #define CCXX_EXCEPTIONS #endif #ifdef AF_INET6 #define CCXX_IPV6 #endif #ifdef AF_INET #define CCXX_IPV4 #endif typedef pthread_t cctid_t; typedef int8_t int8; typedef uint8_t uint8; typedef int16_t int16; typedef uint16_t uint16; typedef int32_t int32; typedef uint32_t uint32; typedef int64_t int64; typedef uint64_t uint64; #if !defined(_MSWINDOWS_) && !defined(__QNX__) #ifndef stricmp #define stricmp(x,y) String::case_compare(x,y) #endif #ifndef strnicmp #define strnicmp(x,y,z) String::case_compare(x,y,z) #endif #endif #endif ucommon-6.4.4/biicode.conf0000644000175000001440000000247712501024112012362 00000000000000# Biicode configuration file [requirements] lasote/openssl: 2 [parent] dyfet/ucommon: 0 [paths] # Local directories to look for headers (within block) # / # include inc [dependencies] CMakeLists.txt + ucommon-config.h.cmake # Manual adjust file implicit dependencies, add (+), remove (-), or overwrite (=) # hello.h + hello_imp.cpp hello_imp2.cpp # *.h + *.cpp [mains] # Manual adjust of files that define an executable # !main.cpp # Do not build executable from this file # main2.cpp # Build it (it doesnt have a main() function, but maybe it includes it) [hooks] # These are defined equal to [dependencies],files names matching bii*stage*hook.py # will be launched as python scripts at stage = {post_process, clean} # CMakeLists.txt + bii/my_post_process1_hook.py bii_clean_hook.py [includes] # Mapping of include patterns to external blocks # hello*.h: user3/depblock # includes will be processed as user3/depblock/hello*.h openssl/*.h: lasote/openssl/include [data] # Manually define data files dependencies, that will be copied to bin for execution # By default they are copied to bin/user/block/... which should be taken into account # when loading from disk such data # image.cpp + image.jpg # code should write open("user/block/image.jpg") ucommon-6.4.4/corelib/0000775000175000017500000000000012557440652011636 500000000000000ucommon-6.4.4/corelib/unicode.cpp0000664000175000017500000003360612545175110013707 00000000000000// Copyright (C) 2009-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_WCHAR_H #include #else typedef ucs4_t wchar_t; #endif namespace ucommon { const char *utf8::nil = NULL; const unsigned utf8::ucsize = sizeof(wchar_t); ucs4_t utf8::get(CharacterProtocol& cp) { int ch = cp.getchar(); unsigned count = 0; ucs4_t code; if(ch == EOF) return EOF; if(ch < 0x80) return ch; if((ch & 0xe0) == 0xc0) { code = ch & 0x1f; count = 1; } else if((ch & 0xf0) == 0xe0) { code = ch & 0x0f; count = 2; } else if((ch & 0xf8) == 0xf0) { code = ch & 0x07; count = 3; } else if((ch & 0xfc) == 0xf8) { code = ch & 0x03; count = 4; } else if((ch & 0xfe) == 0xfc) { code = ch & 0x01; count = 5; } else return EOF; while(count--) { ch = cp.getchar(); if(ch == EOF) return EOF; if((ch & 0xc0) != 0x80) return EOF; code = (code << 6) | (ch & 0x3f); } return code; } unsigned utf8::size(const char *string) { unsigned char v = (unsigned char)(*string); if(v < 0x80) return 1; if((v & 0xe0) == 0xc0) return 2; if((v & 0xf0) == 0xe0) return 3; if((v & 0xf8) == 0xf0) return 4; if((v & 0xfc) == 0xf8) return 5; if((v & 0xfe) == 0xfc) return 6; return 0; } ucs4_t utf8::codepoint(const char *string) { unsigned codesize = size(string); unsigned char encoded = (unsigned char)(*(string++)); ucs4_t code = 0; if(encoded == 0) return 0; if(!codesize) return -1; switch(codesize) { case 1: return (ucs4_t)encoded; case 2: code = encoded & 0x1f; break; case 3: code = encoded & 0x0f; break; case 4: code = encoded & 0x07; break; case 5: code = encoded & 0x03; break; case 6: code = encoded & 0x01; break; } while(--codesize) { encoded = (unsigned char)(*(string++)); // validity check... if((encoded & 0xc0) != 0x80) return 0; code = (code << 6) | (encoded & 0x3f); } return code; } size_t utf8::count(const char *string) { size_t pos = 0; unsigned codesize; if(!string) return 0; while(*string && (codesize = size(string)) != 0) { ++pos; string += codesize; } return pos; } char *utf8::offset(char *string, ssize_t pos) { if(!string) return NULL; ssize_t codepoints = (ssize_t)count(string); if(pos > codepoints) return NULL; if(pos == 0) return string; if(pos < 0) { pos = -pos; if(pos > codepoints) return NULL; pos = codepoints - pos; } while(pos--) { unsigned codesize = size(string); if(!codesize) return NULL; string += codesize; } return string; } size_t utf8::chars(const unicode_t str) { size_t ccount = 0; const wchar_t *string = (const wchar_t *)str; if(!string) return 0; while(*string != 0l) { ucs4_t chr = (ucs4_t)(*(string++)); ccount += chars(chr); } return ccount; } size_t utf8::chars(ucs4_t code) { if(code <= 0x80) return 1; if(code <= 0x000007ff) return 2; if(code <= 0x0000ffff) return 3; if(code <= 0x001fffff) return 4; if(code <= 0x03ffffff) return 5; return 6; } unicode_t unidup(const char *string) { if(sizeof(wchar_t) < 4) return (unicode_t) utf8::wdup(string); return (unicode_t) utf8::udup(string); } size_t utf8::pack(unicode_t buffer, CharacterProtocol& cp, size_t len) { size_t used = 0; wchar_t *target = (wchar_t *)buffer; assert(len > 0); while(--len) { ucs4_t code = utf8::get(cp); if(!code || code == (ucs4_t)EOF) break; *(target++) = (wchar_t)code; ++used; } *target = (wchar_t)0; return used; } ucs4_t utf8::put(ucs4_t code, CharacterProtocol& cp) { char buffer[8]; unsigned used = 0, count = 0; if(code < 0x80) return cp.putchar(code); if(code < 0x000007ff) { buffer[used++] = (code >> 6) | 0xc0; buffer[used++] = (code & 0x3f) | 0x80; } else if(code <= 0x0000ffff) { buffer[used++] = (code >> 12) | 0xe0; buffer[used++] = (code >> 6 & 0x3f) | 0x80; buffer[used++] = (code & 0x3f) | 0x80; } else if(code <= 0x001fffff) { buffer[used++] = (code >> 18) | 0xf0; buffer[used++] = (code >> 12 & 0x3f) | 0x80; buffer[used++] = (code >> 6 & 0x3f) | 0x80; buffer[used++] = (code & 0x3f) | 0x80; } else if(code <= 0x03ffffff) { buffer[used++] = (code >> 24) | 0xf8; buffer[used++] = (code >> 18 & 0x3f) | 0x80; buffer[used++] = (code >> 12 & 0x3f) | 0x80; buffer[used++] = (code >> 6 & 0x3f) | 0x80; buffer[used++] = (code & 0x3f) | 0x80; } else { buffer[used++] = (code >> 30) | 0xfc; buffer[used++] = (code >> 24 & 0x3f) | 0x80; buffer[used++] = (code >> 18 & 0x3f) | 0x80; buffer[used++] = (code >> 12 & 0x3f) | 0x80; buffer[used++] = (code >> 6 & 0x3f) | 0x80; buffer[used++] = (code & 0x3f) | 0x80; } while(count < used) { if(cp.putchar(buffer[count++]) == EOF) return EOF; } return code; } ucs4_t *utf8::udup(const char *string) { if(!string) return NULL; strsize_t len = (strsize_t)count(string); strsize_t pos = 0; ucs4_t *out = (ucs4_t *)malloc(sizeof(ucs4_t) * (++len)); if (!out) return NULL; while(*string) { out[pos++] = utf8::codepoint(string); string += utf8::size(string); } out[pos] = 0; return out; } ucs2_t *utf8::wdup(const char *string) { if(!string) return NULL; strsize_t len = (strsize_t)count(string); strsize_t pos = 0; ucs2_t *out = (ucs2_t *)malloc(sizeof(ucs2_t) * (++len)); ucs4_t ch; if (!out) return NULL; while(*string) { ch = utf8::codepoint(string); if(ch >= 0x10000 || ch < 0) { free(out); return NULL; } out[pos++] = (ucs2_t)ch; string += utf8::size(string); } out[pos] = 0; return out; } size_t utf8::unpack(const unicode_t str, CharacterProtocol& cp) { unsigned points = 0; ucs4_t code; const wchar_t *string = (const wchar_t *)str; while(0 != (code = (*(string++)))) { if(utf8::put(code, cp) == EOF) break; ++points; } return points; } unsigned utf8::ccount(const char *cp, ucs4_t code) { unsigned total = 0; ucs4_t ch; unsigned cs; if(!cp) return 0; while(*cp) { ch = utf8::codepoint(cp); cs = utf8::size(cp); if(!cs || ch == -1) break; if(ch == code) ++total; cp += cs; } return total; } const char *utf8::find(const char *cp, ucs4_t code, size_t pos) { ucs4_t ch; unsigned cs; size_t cpos = 0; if(!cp) return NULL; while(*cp) { ch = utf8::codepoint(cp); cs = utf8::size(cp); if(pos && ++cpos > pos) return NULL; if(!cs || ch == -1) return NULL; if(ch == code) return cp; cp += cs; } return NULL; } const char *utf8::rfind(const char *cp, ucs4_t code, size_t pos) { const char *result = NULL; ucs4_t ch; unsigned cs; size_t cpos = 0; if(!cp) return NULL; while(*cp) { ch = utf8::codepoint(cp); cs = utf8::size(cp); if(!cs || ch == -1) break; if(ch == code) result = cp; if(++cpos > pos) break; cp += cs; } return result; } UString::UString() { str = NULL; } UString::~UString() {} UString::UString(strsize_t size) { str = create(size); str->retain(); } UString::UString(const char *text, strsize_t size) { str = NULL; String::set(0, text, size); } UString::UString(const unicode_t text) { str = NULL; set(text); } UString::UString(const UString& copy) { str = NULL; if(copy.str) String::set(copy.str->text); } void UString::set(const unicode_t text) { strsize_t size = (strsize_t)utf8::chars(text); str = NULL; str = create(size); str->retain(); chartext cp(str->text, str->max); utf8::unpack(text, cp); str->fix(); } void UString::add(const unicode_t text) { strsize_t alloc, size; size = alloc = (strsize_t)utf8::chars(text); if(str) alloc += str->len; if(!resize(alloc)) return; chartext cp(str->text + str->len, size); utf8::unpack(text, cp); str->fix(); } size_t UString::get(unicode_t output, size_t points) const { chartext cp(str->text); return utf8::pack(output, cp, points); } void UString::cut(strsize_t pos, strsize_t size) { if(!str) return; strsize_t bpos = 0, blen = 0; if(pos && pos != npos) bpos = String::offset(utf8::offset(str->text, (ssize_t)pos)); if(size && size != npos) blen = String::offset(utf8::offset(str->text, (ssize_t)size)); String::cut(bpos, blen); } void UString::paste(strsize_t pos, const char *text, strsize_t size) { strsize_t bpos = 0, blen = 0; if(pos && pos != npos && str) bpos = String::offset(utf8::offset(str->text, (ssize_t)pos)); if(size && size != npos && str) blen = String::offset(utf8::offset(str->text, (ssize_t)size)); String::paste(bpos, text, blen); } UString UString::get(strsize_t pos, strsize_t size) const { if(!str) return UString("", 0); char *substr = utf8::offset(str->text, (ssize_t)pos); if(!substr) return UString("", 0); if(!size) return UString(substr, 0); const char *end = utf8::offset(substr, size); if(!end) return UString(substr); pos = (strsize_t)(end - substr + 1); return UString(substr, pos); } ucs4_t UString::at(int offset) const { const char *cp; if(!str) return -1; cp = utf8::offset(str->text, offset); if(!cp) return -1; return utf8::codepoint(cp); } const char *UString::find(ucs4_t code, strsize_t pos) const { if(!str) return NULL; return utf8::find(str->text, code, (size_t)pos); } const char *UString::rfind(ucs4_t code, strsize_t pos) const { if(!str) return NULL; return utf8::rfind(str->text, code, (size_t)pos); } unsigned UString::ccount(ucs4_t code) const { if(!str) return 0; return utf8::ccount(str->text, code); } UString UString::operator()(int codepoint, strsize_t size) const { return UString::get(codepoint, size); } const char *UString::operator()(int offset) const { if(!str) return NULL; return utf8::offset(str->text, offset); } utf8_pointer::utf8_pointer() { text = NULL; } utf8_pointer::utf8_pointer(const char *str) { text = (uint8_t*)str; } utf8_pointer::utf8_pointer(const utf8_pointer& copy) { text = copy.text; } void utf8_pointer::inc(void) { if(!text) return; if(*text < 0x80) { ++text; return; } if((*text & 0xc0) == 0xc0) ++text; while((*text & 0xc0) == 0x80) ++text; } void utf8_pointer::dec(void) { if(!text) return; while((*(--text) & 0xc0) == 0x80) ; } utf8_pointer& utf8_pointer::operator++() { inc(); return *this; } utf8_pointer& utf8_pointer::operator--() { dec(); return *this; } utf8_pointer& utf8_pointer::operator+=(long offset) { if(!text || !offset) return *this; if(offset > 0) { while(offset--) inc(); } else { while(offset++) dec(); } return *this; } utf8_pointer& utf8_pointer::operator-=(long offset) { if(!text || !offset) return *this; if(offset > 0) { while(offset--) dec(); } else { while(offset++) inc(); } return *this; } utf8_pointer utf8_pointer::operator+(long offset) const { utf8_pointer nsp(c_str()); nsp += offset; return nsp; } utf8_pointer utf8_pointer::operator-(long offset) const { utf8_pointer nsp(c_str()); nsp -= offset; return nsp; } utf8_pointer& utf8_pointer::operator=(const char *str) { text = (uint8_t *)str; return *this; } ucs4_t utf8_pointer::operator[](long offset) const { utf8_pointer ncp(c_str()); if(!text) return 0l; if(!offset) return utf8::codepoint((const char*)text); if(offset > 0) { while(offset--) ncp.inc(); } else { while(offset++) ncp.dec(); } return *ncp; } } // namespace ucommon ucommon-6.4.4/corelib/vector.cpp0000664000175000017500000002662212545756276013605 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include #include #include namespace ucommon { const vectorsize_t Vector::npos = (vectorsize_t)(-1); Vector::array::array(vectorsize_t size) { assert(size > 0); max = size; len = 0; list[0] = 0; } void Vector::array::dealloc(void) { purge(); this->array::~array(); ::free(this); } void Vector::array::purge(void) { vectorsize_t pos = 0; while(list[pos]) list[pos++]->release(); len = 0; list[0] = 0; } void Vector::array::dec(vectorsize_t offset) { if(!len) return; if(offset >= len) { purge(); return; } while(offset--) { list[--len]->release(); list[len] = 0; } } void Vector::array::inc(vectorsize_t offset) { if(!offset) ++offset; if(offset >= len) { purge(); return; } if(!len) return; for(vectorsize_t pos = 0; pos < offset; ++pos) list[pos]->release(); memmove(list, &list[offset], (len - offset) * sizeof(void *)); len -= offset; list[len] = 0; } void Vector::array::set(ObjectProtocol **items) { assert(items != NULL); purge(); add(items); } void Vector::array::add(ObjectProtocol **items) { assert(items != NULL); vectorsize_t size = Vector::size((void **)(items)); if(!size) return; if(len + size > max) size = max - len; if(size < 1) return; for(vectorsize_t pos = 0; pos < size; ++pos) { list[len++] = items[pos]; items[pos]->retain(); } list[len] = 0; } void Vector::array::add(ObjectProtocol *obj) { assert(obj); if(len == max) return; obj->retain(); list[len++] = obj; list[len] = 0; } vectorsize_t Vector::size(void) const { if(!data) return 0; return data->max; } vectorsize_t Vector::len(void) const { if(!data) return 0; return data->len; } Vector::Vector() { data = NULL; } Vector::Vector(ObjectProtocol **items, vectorsize_t limit) { assert(items); if(!limit) limit = size((void **)items); data = create(limit); data->retain(); data->set(items); } Vector::Vector(vectorsize_t size) { assert(size > 0); data = create(size); data->retain(); } Vector::~Vector() { release(); } ObjectProtocol **Vector::list(void) const { if(!data) return NULL; return data->list; } ObjectProtocol *Vector::invalid(void) const { return NULL; } ObjectProtocol *Vector::get(int offset) const { if(!data || !data->len) return invalid(); if(offset >= (int)(data->len)) return invalid(); if(((vectorsize_t)(-offset)) >= data->len) return invalid(); if(offset >= 0) return data->list[offset]; return data->list[data->len + offset]; } vectorsize_t Vector::get(void **target, vectorsize_t limit) const { assert(target != NULL && limit > 0); vectorsize_t pos; if(!data) { target[0] = 0; return 0; } for(pos = 0; pos < data->len && pos < limit - 1; ++pos) target[pos] = data->list[pos]; target[pos] = 0; return pos; } Vector::array *Vector::create(vectorsize_t size) const { assert(size > 0); void *mem = ::malloc((size_t)size); return new(mem) array(size); } void Vector::release(void) { if(data) data->release(); data = NULL; } ObjectProtocol *Vector::begin(void) const { if(!data) return NULL; return data->list[0]; } ObjectProtocol *Vector::end(void) const { if(!data || !data->len) return NULL; return data->list[data->len - 1]; } vectorsize_t Vector::find(ObjectProtocol *obj, vectorsize_t pos) const { assert(obj != NULL); if(!data) return npos; while(pos < data->len) { if(data->list[pos] == obj) return pos; ++pos; } return npos; } void Vector::split(vectorsize_t pos) { if(!data || pos >= data->len) return; while(data->len > pos) { --data->len; data->list[data->len]->release(); } data->list[data->len] = NULL; } void Vector::rsplit(vectorsize_t pos) { vectorsize_t head = 0; if(!data || pos >= data->len || !pos) return; while(head < pos) data->list[head++]->release(); head = 0; while(data->list[pos]) data->list[head++] = data->list[pos++]; data->len = head; data->list[head] = NULL; } void Vector::set(ObjectProtocol **list) { assert(list); if(!data && list) { data = create(size((void **)list)); data->retain(); } if(data && list) data->set(list); } void Vector::set(vectorsize_t pos, ObjectProtocol *obj) { assert(obj != NULL); if(!data || pos > data->len) return; if(pos == data->len && data->len < data->max) { data->list[data->len++] = obj; data->list[data->len] = NULL; obj->retain(); return; } data->list[pos]->release(); data->list[pos] = obj; obj->retain(); } void Vector::add(ObjectProtocol **list) { assert(list); if(data && list) data->add(list); } void Vector::add(ObjectProtocol *obj) { assert(obj); if(data && obj) data->add(obj); } void Vector::clear(void) { if(data) data->purge(); } bool Vector::resize(vectorsize_t size) { if(!size) { release(); data = NULL; return true; } if(data->is_copied() || data->max < size) { data->release(); data = create(size); data->retain(); } return true; } void Vector::cow(vectorsize_t size) { if(data) { size += data->len; } if(!size) return; if(!data || !data->max || data->is_copied() || size > data->max) { array *a = create(size); if (!a) return; if (data) { a->len = data->len; memcpy(a->list, data->list, data->len * sizeof(ObjectProtocol *)); } else a->len = 0; a->list[a->len] = 0; a->retain(); if (data) data->release(); data = a; } } void Vector::operator^=(Vector &v) { release(); set(v.list()); } Vector &Vector::operator^(Vector &v) { vectorsize_t vs = v.len(); if(!vs) return *this; if(data && data->len + vs > data->max) cow(); add(v.list()); return *this; } void Vector::operator++() { if(!data) return; data->inc(1); } void Vector::operator--() { if(!data) return; data->dec(1); } void Vector::operator+=(vectorsize_t inc) { if(!data) return; data->inc(inc); } void Vector::operator-=(vectorsize_t dec) { if(!data) return; data->inc(dec); } MemVector::MemVector(void *mem, vectorsize_t size) { assert(mem != NULL); assert(size > 0); data = new(mem) array(size); } MemVector::~MemVector() { data = NULL; } void MemVector::release(void) { data = NULL; } bool MemVector::resize(vectorsize_t size) { return false; } void MemVector::cow(vectorsize_t adj) { } ArrayReuse::ArrayReuse(size_t size, unsigned c, void *memory) : ReusableAllocator() { assert(c > 0 && size > 0 && memory != NULL); objsize = size; count = 0; limit = c; used = 0; mem = (caddr_t)memory; } ArrayReuse::ArrayReuse(size_t size, unsigned c) : ReusableAllocator() { assert(c > 0 && size > 0); objsize = size; count = 0; limit = c; used = 0; mem = (caddr_t)malloc(size * c); crit(mem != NULL, "vector reuse alloc failed"); } ArrayReuse::~ArrayReuse() { if(mem) { free(mem); mem = NULL; } } bool ArrayReuse::avail(void) const { bool rtn = false; __AUTOLOCK__ if(count < limit) rtn = true; return rtn; } ReusableObject *ArrayReuse::get(timeout_t timeout) { bool rtn = true; struct timespec ts; ReusableObject *obj = NULL; if(timeout && timeout != Timer::inf) set(&ts, timeout); __AUTOLOCK__ while(!freelist && used >= limit && rtn) { ++waiting; if(timeout == Timer::inf) wait(); else if(timeout) rtn = wait(&ts); else rtn = false; --waiting; } if(!rtn) { return NULL; } if(freelist) { obj = freelist; freelist = next(obj); } else if(used < limit) { obj = (ReusableObject *)&mem[used * objsize]; ++used; } if(obj) ++count; return obj; } ReusableObject *ArrayReuse::get(void) { return get(Timer::inf); } ReusableObject *ArrayReuse::request(void) { ReusableObject *obj = NULL; __AUTOLOCK__ if(freelist) { obj = freelist; freelist = next(obj); } else if(used < limit) { obj = (ReusableObject *)(mem + (used * objsize)); ++used; } if(obj) ++count; return obj; } vectorsize_t Vector::size(void **list) { assert(list != NULL); vectorsize_t pos = 0; while(list[pos]) ++pos; return pos; } PagerReuse::PagerReuse(mempager *p, size_t objsize, unsigned c) : MemoryRedirect(p), ReusableAllocator() { assert(objsize > 0 && c > 0); limit = c; count = 0; osize = objsize; } PagerReuse::~PagerReuse() { } bool PagerReuse::avail(void) const { bool rtn = false; __AUTOLOCK__ if(!limit) return true; if(count < limit) rtn = true; return rtn; } ReusableObject *PagerReuse::request(void) { ReusableObject *obj = NULL; __AUTOLOCK__ if(!limit || count < limit) { if(freelist) { ++count; obj = freelist; freelist = next(obj); } else { ++count; return (ReusableObject *)_alloc(osize); } } return obj; } ReusableObject *PagerReuse::get(void) { return get(Timer::inf); } ReusableObject *PagerReuse::get(timeout_t timeout) { bool rtn = true; struct timespec ts; ReusableObject *obj; if(timeout && timeout != Timer::inf) set(&ts, timeout); __AUTOLOCK__ while(rtn && limit && count >= limit) { ++waiting; if(timeout == Timer::inf) wait(); else if(timeout) rtn = wait(&ts); else rtn = false; --waiting; } if(!rtn) { return NULL; } if(freelist) { obj = freelist; freelist = next(obj); } else { ++count; return (ReusableObject *)_alloc(osize); } if(obj) ++count; return obj; } } // namespace ucommon ucommon-6.4.4/corelib/containers.cpp0000664000175000017500000003205512544454312014426 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include #include #include namespace ucommon { LinkedAllocator::LinkedAllocator() : Conditional() { freelist = NULL; } LinkedObject *LinkedAllocator::get(void) { LinkedObject *node; __AUTOLOCK__ node = freelist; if(node) freelist = freelist->getNext(); return node; } LinkedObject *LinkedAllocator::get(timeout_t timeout) { struct timespec ts; bool rtn = true; LinkedObject *node = NULL; if(timeout && timeout != Timer::inf) set(&ts, timeout); __AUTOLOCK__ while(!freelist && rtn) { if(timeout == Timer::inf) Conditional::wait(); else if(timeout) rtn = Conditional::wait(&ts); else rtn = false; } if(rtn && freelist) { node = freelist; if(node) freelist = freelist->getNext(); } return node; } void LinkedAllocator::release(LinkedObject *node) { __AUTOLOCK__ node->enlist(&freelist); signal(); } LinkedAllocator::operator bool() const { bool rtn = false; __AUTOLOCK__ if(freelist) rtn = true; return rtn; } bool LinkedAllocator::operator!() const { bool rtn = false; __AUTOLOCK__ if(!freelist) rtn = true; return rtn; } Buffer::Buffer(size_t osize, size_t c) : Conditional() { assert(osize > 0 && c > 0); bufsize = osize * c; objsize = osize; objcount = 0; limit = (unsigned)c; if(osize) { buf = (char *)malloc(bufsize); crit(buf != NULL, "buffer alloc failed"); } else buf = NULL; head = tail = buf; } Buffer::~Buffer() { if(buf) free(buf); buf = NULL; } unsigned Buffer::count(void) const { unsigned bcount = 0; __AUTOLOCK__ if(tail > head) bcount = (unsigned)((size_t)(tail - head) / objsize); else if(head > tail) bcount = (unsigned)((((buf + bufsize) - head) + (tail - buf)) / objsize); return bcount; } unsigned Buffer::size(void) const { return (unsigned)(bufsize / objsize); } void *Buffer::get(void) { caddr_t dbuf; __AUTOLOCK__ while(!objcount) wait(); dbuf = head; return dbuf; } void *Buffer::invalid(void) const { return NULL; } void *Buffer::peek(unsigned offset) { caddr_t dbuf; __AUTOLOCK__ if(offset >= objcount) { return invalid(); } dbuf = head + (objsize * offset); if(dbuf >= buf + bufsize) dbuf -= bufsize; return dbuf; } void Buffer::copy(void *data) { assert(data != NULL); void *ptr = get(); memcpy(data, ptr, objsize); release(); } bool Buffer::copy(void *data, timeout_t timeout) { assert(data != NULL); void *ptr = get(timeout); if(!ptr) return false; memcpy(data, ptr, objsize); release(); return true; } void *Buffer::get(timeout_t timeout) { caddr_t dbuf = NULL; struct timespec ts; bool rtn = true; if(timeout && timeout != Timer::inf) set(&ts, timeout); __AUTOLOCK__ while(!objcount && rtn) { if(timeout == Timer::inf) wait(); else if(timeout) rtn = wait(&ts); else rtn = false; } if(objcount && rtn) dbuf = head; return dbuf; } void Buffer::release(void) { __AUTOLOCK__ head += objsize; if(head >= buf + bufsize) head = buf; --objcount; signal(); } void Buffer::put(void *dbuf) { assert(dbuf != NULL); __AUTOLOCK__ while(objcount == limit) wait(); memcpy(tail, dbuf, objsize); tail += objsize; if(tail >= (buf + bufsize)) tail = buf; ++objcount; signal(); } bool Buffer::put(void *dbuf, timeout_t timeout) { assert(dbuf != NULL); bool rtn = true; struct timespec ts; if(timeout && timeout != Timer::inf) set(&ts, timeout); __AUTOLOCK__ while(objcount == limit && rtn) { if(timeout == Timer::inf) wait(); else if(timeout) rtn = wait(&ts); else rtn = false; } if(rtn && objcount < limit) { memcpy(tail, dbuf, objsize); tail += objsize; if(tail >= (buf + bufsize)) tail = 0; ++objcount; signal(); } return rtn; } Buffer::operator bool() const { bool rtn = false; __AUTOLOCK__ if(buf && head != tail) rtn = true; return rtn; } bool Buffer::operator!() const { bool rtn = false; __AUTOLOCK__ if(!buf || head == tail) rtn = true; return rtn; } Queue::member::member(Queue *q, ObjectProtocol *o) : OrderedObject(q) { assert(o != NULL); o->retain(); object = o; } Queue::Queue(mempager *p, size_t size) : OrderedIndex(), Conditional() { assert(size > 0); pager = p; freelist = NULL; used = 0; limit = size; } Queue::~Queue() { linked_pointer mp; OrderedObject *next; if(pager) return; mp = freelist; while(is(mp)) { next = mp->getNext(); delete *mp; mp = next; } mp = head; while(is(mp)) { next = mp->getNext(); delete *mp; mp = next; } } bool Queue::remove(ObjectProtocol *o) { assert(o != NULL); bool rtn = false; linked_pointer node; __AUTOLOCK__ node = begin(); while(node) { if(node->object == o) break; node.next(); } if(node) { --used; rtn = true; node->object->release(); node->delist(this); node->LinkedObject::enlist(&freelist); } return rtn; } ObjectProtocol *Queue::lifo(timeout_t timeout) { struct timespec ts; bool rtn = true; member *member; ObjectProtocol *obj = NULL; if(timeout && timeout != Timer::inf) set(&ts, timeout); __AUTOLOCK__ while(!tail && rtn) { if(timeout == Timer::inf) Conditional::wait(); else if(timeout) rtn = Conditional::wait(&ts); else rtn = false; } if(rtn && tail) { --used; member = static_cast(tail); obj = member->object; member->delist(this); member->LinkedObject::enlist(&freelist); } if(rtn) signal(); return obj; } ObjectProtocol *Queue::fifo(timeout_t timeout) { bool rtn = true; struct timespec ts; linked_pointer node; ObjectProtocol *obj = NULL; if(timeout && timeout != Timer::inf) set(&ts, timeout); __AUTOLOCK__ while(rtn && !head) { if(timeout == Timer::inf) Conditional::wait(); else if(timeout) rtn = Conditional::wait(&ts); else rtn = false; } if(rtn && head) { --used; node = begin(); obj = node->object; head = head->getNext(); if(!head) tail = NULL; node->LinkedObject::enlist(&freelist); } if(rtn) signal(); return obj; } ObjectProtocol *Queue::invalid(void) const { return NULL; } ObjectProtocol *Queue::get(unsigned back) { linked_pointer node; ObjectProtocol *obj; __AUTOLOCK__ node = begin(); do { if(!is(node)) { obj = invalid(); break; } obj = node->object; node.next(); } while(back-- > 0); return obj; } bool Queue::post(ObjectProtocol *object, timeout_t timeout) { assert(object != NULL); bool rtn = true; struct timespec ts; LinkedObject *mem; if(timeout && timeout != Timer::inf) set(&ts, timeout); __AUTOLOCK__ while(rtn && limit && used == limit) { if(timeout == Timer::inf) Conditional::wait(); else if(timeout) rtn = Conditional::wait(&ts); else rtn = false; } if(!rtn) { return false; } ++used; if(freelist) { mem = freelist; freelist = freelist->getNext(); new((void *)mem) member(this, object); } else { if(pager) new((void *)(pager->alloc(sizeof(member)))) member(this, object); else new member(this, object); } signal(); return true; } size_t Queue::count(void) const { size_t qcount; __AUTOLOCK__ qcount = used; return qcount; } Stack::member::member(Stack *S, ObjectProtocol *o) : LinkedObject((&S->usedlist)) { assert(o != NULL); o->retain(); object = o; } Stack::Stack(mempager *p, size_t size) : Conditional() { assert(size > 0); pager = p; freelist = usedlist = NULL; limit = size; used = 0; } Stack::~Stack() { linked_pointer mp; LinkedObject *next; if(pager) return; mp = freelist; while(is(mp)) { next = mp->getNext(); delete *mp; mp = next; } mp = usedlist; while(is(mp)) { next = mp->getNext(); delete *mp; mp = next; } } bool Stack::remove(ObjectProtocol *o) { assert(o != NULL); bool rtn = false; linked_pointer node; __AUTOLOCK__ node = static_cast(usedlist); while(node) { if(node->object == o) break; node.next(); } if(node) { --used; rtn = true; node->object->release(); node->delist(&usedlist); node->enlist(&freelist); } return rtn; } ObjectProtocol *Stack::invalid(void) const { return NULL; } ObjectProtocol *Stack::get(unsigned back) { linked_pointer node; ObjectProtocol *obj; __AUTOLOCK__ node = usedlist; do { if(!is(node)) { obj = invalid(); break; } obj = node->object; node.next(); } while(back-- > 0); return obj; } const ObjectProtocol *Stack::peek(timeout_t timeout) { bool rtn = true; struct timespec ts; member *member; ObjectProtocol *obj = NULL; if(timeout && timeout != Timer::inf) set(&ts, timeout); __AUTOLOCK__ while(rtn && !usedlist) { if(timeout == Timer::inf) Conditional::wait(); else if(timeout) rtn = Conditional::wait(&ts); else rtn = false; } if(!rtn) { return NULL; } if(usedlist) { member = static_cast(usedlist); obj = member->object; } if(rtn) signal(); return obj; } ObjectProtocol *Stack::pull(timeout_t timeout) { bool rtn = true; struct timespec ts; member *member; ObjectProtocol *obj = NULL; if(timeout && timeout != Timer::inf) set(&ts, timeout); __AUTOLOCK__ while(rtn && !usedlist) { if(timeout == Timer::inf) Conditional::wait(); else if(timeout) rtn = Conditional::wait(&ts); else rtn = false; } if(!rtn) { return NULL; } if(usedlist) { member = static_cast(usedlist); obj = member->object; usedlist = member->getNext(); member->enlist(&freelist); } if(rtn) signal(); return obj; } bool Stack::push(ObjectProtocol *object, timeout_t timeout) { assert(object != NULL); bool rtn = true; struct timespec ts; LinkedObject *mem; if(timeout && timeout != Timer::inf) set(&ts, timeout); __AUTOLOCK__ while(rtn && limit && used == limit) { if(timeout == Timer::inf) Conditional::wait(); else if(timeout) rtn = Conditional::wait(&ts); else rtn = false; } if(!rtn) { return false; } ++used; if(freelist) { mem = freelist; freelist = freelist->getNext(); new((void *)mem) member(this, object); } else { if(pager) { void *ptr = (caddr_t)pager->alloc(sizeof(member)); new(ptr) member(this, object); } else new member(this, object); } signal(); return true; } size_t Stack::count(void) const { size_t scount; __AUTOLOCK__ scount = used; return scount; } } // namespace ucommon ucommon-6.4.4/corelib/timer.cpp0000644000175000001440000002311412504370630013363 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include namespace ucommon { #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) extern int _posix_clocking; #endif static long _difftime(time_t ref) { time_t now; time(&now); return (long)difftime(ref, now); } #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) static void adj(struct timespec *ts) { assert(ts != NULL); if(ts->tv_nsec >= 1000000000l) ts->tv_sec += (ts->tv_nsec / 1000000000l); ts->tv_nsec %= 1000000000l; if(ts->tv_nsec < 0) ts->tv_nsec = -ts->tv_nsec; } #else static void adj(struct timeval *ts) { assert(ts != NULL); if(ts->tv_usec >= 1000000l) ts->tv_sec += (ts->tv_usec / 1000000l); ts->tv_usec %= 1000000l; if(ts->tv_usec < 0) ts->tv_usec = -ts->tv_usec; } #endif #ifdef WIN32 #ifdef _WIN32_WCE } // namespace ucommon extern "C" int gettimeofday(struct timeval *tv_, void *tz_) { assert(tv_ != NULL); // We could use _ftime(), but it is not available on WinCE. // (WinCE also lacks time.h) // Note also that the average error of _ftime is around 20 ms :) DWORD ms = GetTickCount(); tv_->tv_sec = ms / 1000; tv_->tv_usec = ms * 1000; return 0; } namespace ucommon { #else } // namespace ucommon #ifdef HAVE_SYS_TIMEB_H #include #endif extern "C" int gettimeofday(struct timeval *tv_, void *tz_) { assert(tv_ != NULL); #if defined(_MSC_VER) && _MSC_VER >= 1300 struct __timeb64 tb; _ftime64(&tb); #else # ifndef __BORLANDC__ struct _timeb tb; _ftime(&tb); # else struct timeb tb; ftime(&tb); # endif #endif tv_->tv_sec = (long)tb.time; tv_->tv_usec = tb.millitm * 1000; return 0; } namespace ucommon { #endif #endif #if _MSC_VER > 1400 // windows broken dll linkage issue... #else const timeout_t Timer::inf = ((timeout_t)(-1)); const time_t Timer::reset = ((time_t)0); #endif TimerQueue::event::event(timeout_t timeout) : Timer(), LinkedList() { set(timeout); } TimerQueue::event::event(TimerQueue *tq, timeout_t timeout) : Timer(), LinkedList() { set(timeout); Timer::update(); attach(tq); } TimerQueue::event::~event() { detach(); } Timer::Timer() { clear(); } Timer::Timer(timeout_t in) { set(); operator+=(in); } Timer::Timer(const Timer& copy) { timer = copy.timer; } Timer::Timer(time_t in) { set(); timer.tv_sec += _difftime(in); } #ifdef _MSWINDOWS_ Timer::tick_t Timer::ticks(void) { ULARGE_INTEGER timer; GetSystemTimeAsFileTime((FILETIME*)&timer); timer.QuadPart += (tick_t) (6893856000000000); return timer.QuadPart; } #else Timer::tick_t Timer::ticks(void) { struct timeval tv; gettimeofday(&tv, NULL); return ((tick_t)tv.tv_sec * (tick_t)10000000) + ((tick_t)tv.tv_usec * 10) + (((tick_t)0x01B21DD2) << 32) + (tick_t)0x13814000; } #endif void Timer::set(timeout_t timeout) { set(); operator+=(timeout); } void Timer::set(time_t time) { set(); timer.tv_sec += _difftime(time); } void TimerQueue::event::attach(TimerQueue *tq) { if(tq == list()) return; detach(); if(!tq) return; tq->modify(); enlist(tq); Timer::update(); tq->update(); } void TimerQueue::event::arm(timeout_t timeout) { TimerQueue *tq = list(); if(tq) tq->modify(); set(timeout); if(tq) tq->update(); } void TimerQueue::event::disarm(void) { TimerQueue *tq = list(); bool flag = is_active(); if(tq && flag) tq->modify(); clear(); if(tq && flag) tq->update(); } void TimerQueue::event::update(void) { TimerQueue *tq = list(); if(Timer::update() && tq) { tq->modify(); tq->update(); } } void TimerQueue::event::detach(void) { TimerQueue *tq = list(); if(tq) { tq->modify(); clear(); delist(); tq->update(); } } void Timer::set(void) { #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) clock_gettime(_posix_clocking, &timer); #else gettimeofday(&timer, NULL); #endif updated = true; } void Timer::clear(void) { timer.tv_sec = 0; #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) timer.tv_nsec = 0; #else timer.tv_usec = 0; #endif updated = false; } bool Timer::update(void) { bool rtn = updated; updated = false; return rtn; } bool Timer::is_active(void) const { #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) if(!timer.tv_sec && !timer.tv_nsec) return false; #else if(!timer.tv_sec && !timer.tv_usec) return false; #endif return true; } timeout_t Timer::get(void) const { timeout_t diff; #if _POSIX_TIMERS > 0 && POSIX_TIMERS struct timespec current; clock_gettime(_posix_clocking, ¤t); adj(¤t); if(current.tv_sec > timer.tv_sec) return 0; if(current.tv_sec == timer.tv_sec && current.tv_nsec > timer.tv_nsec) return 0; diff = (timer.tv_sec - current.tv_sec) * 1000; diff += ((timer.tv_nsec - current.tv_nsec) / 1000000l); #else struct timeval current; gettimeofday(¤t, NULL); adj(¤t); if(current.tv_sec > timer.tv_sec) return 0; if(current.tv_sec == timer.tv_sec && current.tv_usec > timer.tv_usec) return 0; diff = (timer.tv_sec - current.tv_sec) * 1000; diff += ((timer.tv_usec - current.tv_usec) / 1000); #endif return diff; } Timer::operator bool() const { if(get()) return false; return true; } bool Timer::operator!() const { if(get()) return true; return false; } timeout_t Timer::operator-(const Timer& source) { timeout_t tv = get(), dv = source.get(); if(!tv) return 0; if(tv == Timer::inf) return Timer::inf; if(dv == Timer::inf) return tv; if(dv > tv) return 0; return tv - dv; } bool Timer::operator==(const Timer& source) const { return get() == source.get(); } bool Timer::operator!=(const Timer& source) const { return get() != source.get(); } bool Timer::operator<(const Timer& source) const { return get() < source.get(); } bool Timer::operator<=(const Timer& source) const { return get() <= source.get(); } bool Timer::operator>(const Timer& source) const { return get() > source.get(); } bool Timer::operator>=(const Timer& source) const { return get() >= source.get(); } Timer& Timer::operator=(timeout_t to) { #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) clock_gettime(_posix_clocking, &timer); #else gettimeofday(&timer, NULL); #endif operator+=(to); return *this; } Timer& Timer::operator+=(timeout_t to) { if(!is_active()) set(); timer.tv_sec += (to / 1000); #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) timer.tv_nsec += (to % 1000l) * 1000000l; #else timer.tv_usec += (to % 1000l) * 1000l; #endif adj(&timer); updated = true; return *this; } Timer& Timer::operator-=(timeout_t to) { if(!is_active()) set(); timer.tv_sec -= (to / 1000); #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) timer.tv_nsec -= (to % 1000l) * 1000000l; #else timer.tv_usec -= (to % 1000l) * 1000l; #endif adj(&timer); return *this; } Timer& Timer::operator+=(time_t abs) { if(!is_active()) set(); timer.tv_sec += _difftime(abs); updated = true; return *this; } Timer& Timer::operator-=(time_t abs) { if(!is_active()) set(); timer.tv_sec -= _difftime(abs); return *this; } Timer& Timer::operator=(time_t abs) { #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) clock_gettime(_posix_clocking, &timer); #else gettimeofday(&timer, NULL); #endif if(!abs) return *this; timer.tv_sec += _difftime(abs); updated = true; return *this; } void Timer::sync(Timer &t) { #if _POSIX_TIMERS > 0 && defined(HAVE_CLOCK_NANOSLEEP) && defined(POSIX_TIMERS) clock_nanosleep(_posix_clocking, TIMER_ABSTIME, &t.timer, NULL); #elif defined(_MSWINDOWS_) SleepEx(t.get(), FALSE); #else usleep(t.get()); #endif } timeout_t TQEvent::timeout(void) { timeout_t timeout = get(); if(is_active() && !timeout) { disarm(); expired(); timeout = get(); Timer::update(); } return timeout; } TimerQueue::TimerQueue() : OrderedIndex() { } TimerQueue::~TimerQueue() { } timeout_t TimerQueue::expire(void) { timeout_t first = Timer::inf, next; linked_pointer timer = begin(); TimerQueue::event *tp; while(timer) { tp = *timer; timer.next(); next = tp->timeout(); if(next && next < first) first = next; } return first; } void TimerQueue::operator+=(event &te) { te.attach(this); } void TimerQueue::operator-=(event &te) { if(te.list() == this) te.detach(); } } // namespace ucommon ucommon-6.4.4/corelib/numbers.cpp0000644000175000001440000000645112504370373013727 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif namespace ucommon { Number::Number(char *buf, unsigned width) { if(width > 10) width = 10; if(width < 1) width = 1; size = width; buffer = buf; } long Number::get(void) const { int count = size; bool sign = false; long ret = 0; char *bp = buffer; if(*bp == '-') { --count; ++bp; sign = true; } else if(*bp == '+') { --count; ++bp; } while(count && *bp >='0' && *bp <='9') { ret = ret * 10l + (*bp - '0'); --count; ++bp; } if(sign) ret = -ret; return ret; } void Number::set(long value) { int count = size; char *bp = buffer; long max = 1; int exp; bool z = false; if(value < 0) { value = -value; --count; *(bp++) = '-'; } exp = count; while(--exp) max *= 10; while(max) { if(value >= max || z) { --count; *(bp++) = '0' + ((char)(value / max)); } if(value >= max) { z = true; value -= (value / max) * max; } max /= 10; } while(count-- && *bp >= '0' && *bp <='9') *(bp++) = ' '; } long Number::operator=(long value) { set(value); return value; } long Number::operator=(const Number& num) { set(num.get()); return get(); } long Number::operator+=(long value) { long value1 = get() + value; set(value1); return value1; } long Number::operator-=(long value) { long value1 = get() - value; set(value1); return value1; } long Number::operator--() { long val = get(); set(--val); return val; } long Number::operator++() { long val = get(); set(++val); return val; } ZNumber::ZNumber(char *buf, unsigned chars) : Number(buf, chars) {} void ZNumber::set(long value) { int count = size; char *bp = buffer; long max = 1; int exp; if(value < 0) { value = -value; --count; *(bp++) = '-'; } exp = count; while(--exp) max *= 10; while(max) { --count; *(bp++) = '0' + (char)(value / max); value -= (value / max) * max; max /= 10; } } long ZNumber::operator=(long value) { set(value); return value; } } // namespace ucommon ucommon-6.4.4/corelib/datetime.cpp0000644000175000001440000004601612504370251014044 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif namespace ucommon { #ifdef __BORLANDC__ using std::time_t; using std::tm; using std::localtime; #endif const long Time::c_day = 86400l; const long Time::c_hour = 3600l; const long Time::c_week = 604800l; const size_t Date::sz_string = 11; const size_t Time::sz_string = 9; const size_t DateTime::sz_string = 20; #ifdef HAVE_LOCALTIME_R tm_t *DateTime::local(const time_t *now) { tm_t *result, *dt = new tm_t; time_t tmp; if(!now) { now = &tmp; time(&tmp); } result = localtime_r(now, dt); if(result) return result; delete dt; return NULL; } tm_t *DateTime::gmt(const time_t *now) { tm_t *result, *dt = new tm_t; time_t tmp; if(!now) { now = &tmp; time(&tmp); } result = gmtime_r(now, dt); if(result) return result; delete dt; return NULL; } void DateTime::release(tm_t *dt) { if(dt) delete dt; } #else static mutex_t lockflag; tm_t *DateTime::local(const time_t *now) { tm_t *dt; time_t tmp; if(!now) { now = &tmp; time(&tmp); } lockflag.acquire(); dt = localtime(now); if(dt) return dt; lockflag.release(); return NULL; } tm_t *DateTime::gmt(const time_t *now) { tm_t *dt; time_t tmp; if(!now) { now = &tmp; time(&tmp); } lockflag.acquire(); dt = gmtime(now); if(dt) return dt; lockflag.release(); return NULL; } void DateTime::release(tm_t *dt) { if(dt) lockflag.release(); } #endif Date::Date() { set(); } Date::Date(const Date& copy) { julian = copy.julian; } Date::Date(const tm_t *dt) { set(dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday); } Date::Date(const time_t tm) { tm_t *dt = DateTime::local(&tm); set(dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday); DateTime::release(dt); } Date::Date(const char *str, size_t size) { set(str, size); } Date::~Date() { } void Date::set() { tm_t *dt = DateTime::local(); set(dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday); DateTime::release(dt); } void Date::set(const char *str, size_t size) { tm_t *dt = DateTime::local(); int nyear = 0; const char *mstr = str; const char *dstr = str; if(!size) size = strlen(str); //0000 if(size == 4) { nyear = dt->tm_year + 1900; mstr = str; dstr = str + 2; } //00/00 else if(size == 5) { nyear = dt->tm_year + 1900; mstr = str; dstr = str + 3; } //000000 else if(size == 6) { ZNumber zyear((char*)str, 2); nyear = ((dt->tm_year + 1900) / 100) * 100 + zyear(); mstr = str + 2; dstr = str + 4; } //00000000 else if(size == 8 && str[2] >= '0' && str[2] <= '9' && str[5] >= '0' && str[5] <= '9') { ZNumber zyear((char*)str, 4); nyear = zyear(); mstr = str + 4; dstr = str + 6; } //00/00/00 else if(size == 8) { ZNumber zyear((char*)str, 2); nyear = ((dt->tm_year + 1900) / 100) * 100 + zyear(); mstr = str + 3; dstr = str + 6; } //0000/00/00 else if(size == 10) { ZNumber zyear((char*)str, 4); nyear = zyear(); mstr = str + 5; dstr = str + 8; } else { julian = 0x7fffffffl; DateTime::release(dt); return; } DateTime::release(dt); ZNumber nmonth((char*)mstr, 2); ZNumber nday((char*)dstr, 2); set(nyear, nmonth(), nday()); } Date::Date(int nyear, unsigned nmonth, unsigned nday) { set(nyear, nmonth, nday); } void Date::update(void) { } bool Date::is_valid(void) const { if(julian == 0x7fffffffl) return false; return true; } time_t Date::timeref(void) const { char buf[11]; tm_t dt; memset(&dt, 0, sizeof(tm_t)); put(buf); Number nyear(buf, 4); Number nmonth(buf + 5, 2); Number nday(buf + 8, 2); dt.tm_year = nyear() - 1900; dt.tm_mon = nmonth() - 1; dt.tm_mday = nday(); return mktime(&dt); // to fill in day of week etc. } int Date::year(void) const { char buf[11]; put(buf); Number num(buf, 4); return num(); } unsigned Date::month(void) const { char buf[11]; put(buf); Number num(buf + 5, 2); return num(); } unsigned Date::day(void) const { char buf[11]; put(buf); Number num(buf + 8, 2); return num(); } unsigned Date::dow(void) const { return (unsigned)((julian + 1l) % 7l); } String Date::operator()() const { char buf[11]; put(buf); String date(buf); return date; } long Date::get(void) const { char buf[11]; put(buf); return atol(buf) * 10000 + atol(buf + 5) * 100 + atol(buf + 8); } Date& Date::operator++() { ++julian; update(); return *this; } Date& Date::operator--() { --julian; update(); return *this; } Date Date::operator+(long val) { Date result = *this; result += val; return result; } Date Date::operator-(long val) { Date result = *this; result -= val; return result; } Date& Date::operator+=(long val) { julian += val; update(); return *this; } Date& Date::operator-=(long val) { julian -= val; update(); return *this; } bool Date::operator==(const Date &d) const { return julian == d.julian; } bool Date::operator!=(const Date &d) const { return julian != d.julian; } bool Date::operator<(const Date &d) const { return julian < d.julian; } bool Date::operator<=(const Date &d) const { return julian <= d.julian; } bool Date::operator>(const Date &d) const { return julian > d.julian; } bool Date::operator>=(const Date &d) const { return julian >= d.julian; } void Date::set(long nyear, long nmonth, long nday) { julian = 0x7fffffffl; if(nmonth < 1 || nmonth > 12 || nday < 1 || nday > 31 || nyear == 0) return; if(nyear < 0) nyear--; julian = nday - 32075l + 1461l * (nyear + 4800l + ( nmonth - 14l) / 12l) / 4l + 367l * (nmonth - 2l - (nmonth - 14l) / 12l * 12l) / 12l - 3l * ((nyear + 4900l + (nmonth - 14l) / 12l) / 100l) / 4l; } Date& Date::operator=(const Date& date) { julian = date.julian; return *this; } const char *Date::put(char *buffer) const { // The following conversion algorithm is due to // Henry F. Fliegel and Thomas C. Van Flandern: ZNumber nyear(buffer, 4); buffer[4] = '-'; ZNumber nmonth(buffer + 5, 2); buffer[7] = '-'; ZNumber nday(buffer + 8, 2); double i, j, k, l, n; l = julian + 68569.0; n = int( 4 * l / 146097.0); l = l - int( (146097.0 * n + 3)/ 4 ); i = int( 4000.0 * (l+1)/1461001.0); l = l - int(1461.0*i/4.0) + 31.0; j = int( 80 * l/2447.0); k = l - int( 2447.0 * j / 80.0); l = int(j/11); j = j+2-12*l; i = 100*(n - 49) + i + l; nyear = int(i); nmonth = int(j); nday = int(k); buffer[10] = '\0'; return buffer; } Time::Time() { set(); } Time::Time(const Time& copy) { seconds = copy.seconds; } Time::Time(const tm_t *dt) { set(dt->tm_hour, dt->tm_min, dt->tm_sec); } Time::Time(const time_t tm) { tm_t *dt = DateTime::local(&tm); set(dt->tm_hour, dt->tm_min, dt->tm_sec); DateTime::release(dt); } Time::Time(const char *str, size_t size) { set(str, size); } Time::Time(int nhour, int nminute, int nsecond) { set(nhour, nminute, nsecond); } Time::~Time() { } void Time::set(void) { tm_t *dt = DateTime::local(); set(dt->tm_hour, dt->tm_min, dt->tm_sec); DateTime::release(dt); } bool Time::is_valid(void) const { if(seconds == -1) return false; return true; } int Time::hour(void) const { if(seconds == -1) return -1; return (int)(seconds / 3600l); } int Time::minute(void) const { if(seconds == -1) return -1; return (int)((seconds / 60l) % 60l); } int Time::second(void) const { if(seconds == -1) return -1; return (int)(seconds % 60l); } void Time::update(void) { seconds = abs(seconds % DateTime::c_day); } void Time::set(const char *str, size_t size) { int sec = 00; if(!size) size = strlen(str); //00:00 if (size == 5) { sec = 00; } //00:00:00 else if (size == 8) { ZNumber nsecond((char *)(str + 6), 2); sec = nsecond(); } else { seconds = -1; return; } ZNumber nhour((char *)str, 2); ZNumber nminute((char *)(str + 3), 2); set(nhour(), nminute(), sec); } String Time::operator()() const { char buf[9]; put(buf); String strTime(buf); return strTime; } long Time::get(void) const { return seconds; } Time& Time::operator++() { ++seconds; update(); return *this; } Time& Time::operator--() { --seconds; update(); return *this; } Time& Time::operator+=(long val) { seconds += val; update(); return *this; } Time& Time::operator-=(long val) { seconds -= val; update(); return *this; } Time Time::operator+(long val) { Time result = *this; result += val; return result; } Time Time::operator-(long val) { Time result = *this; result -= val; return result; } bool Time::operator==(const Time &t) const { return seconds == t.seconds; } bool Time::operator!=(const Time &t) const { return seconds != t.seconds; } bool Time::operator<(const Time &t) const { return seconds < t.seconds; } bool Time::operator<=(const Time &t) const { return seconds <= t.seconds; } bool Time::operator>(const Time &t) const { return seconds > t.seconds; } bool Time::operator>=(const Time &t) const { return seconds >= t.seconds; } long Time::operator-(const Time &t) { if(seconds < t.seconds) return (seconds + DateTime::c_day) - t.seconds; else return seconds - t.seconds; } void Time::set(int nhour, int nminute, int nsecond) { seconds = -1; if (nminute > 59 || nsecond > 59 || nhour > 23) return; seconds = 3600 * nhour + 60 * nminute + nsecond; } const char *Time::put(char *buffer) const { ZNumber zhour(buffer, 2); buffer[2] = ':'; ZNumber zminute(buffer + 3, 2); buffer[5] = ':'; ZNumber zsecond(buffer + 6, 2); zhour = (seconds / 3600l) % 24l; zminute = (seconds - (3600l * zhour())) / 60l; zsecond = seconds - (3600l * zhour()) - (60l * zminute()); buffer[8] = '\0'; return buffer; } Time& Time::operator=(const Time& time) { seconds = time.seconds; return *this; } DateTime::DateTime(const time_t tm) { tm_t *dt = DateTime::local(); Date::set(dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday); Time::set(dt->tm_hour, dt->tm_min, dt->tm_sec); DateTime::release(dt); } DateTime::DateTime(const tm_t *dt) : Date(dt), Time(dt) {} DateTime::DateTime(const DateTime& copy) { julian = copy.julian; seconds = copy.seconds; } DateTime::DateTime(const char *a_str, size_t size) { char *timestr; if (!size) size = strlen(a_str); char *str = new char[size+1]; strncpy(str, a_str, size); str[size]=0; // 00/00 00:00 if (size == 11) { timestr = str + 6; Date::set(str, 5); Time::set(timestr, 5); } // 00/00/00 00:00 else if (size == 14) { timestr = str + 9; Date::set(str, 8); Time::set(timestr,5); } // 00/00/00 00:00:00 else if (size == 17) { timestr = str + 9; Date::set(str, 8); Time::set(timestr,8); } // 0000/00/00 00:00:00 else if (size == 19) { timestr = str + 11; Date::set(str, 10); Time::set(timestr,8); } delete[] str; } DateTime::DateTime(int year, unsigned month, unsigned day, int hour, int minute, int second) : Date(year, month, day), Time(hour, minute, second) {} DateTime::DateTime() : Date(), Time() { tm_t *dt = DateTime::local(); Time::set(dt->tm_hour, dt->tm_min, dt->tm_sec); Date::set(dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday); DateTime::release(dt); } DateTime::~DateTime() { } void DateTime::set() { Date::set(); Time::set(); } bool DateTime::is_valid(void) const { return Date::is_valid() && Time::is_valid(); } const char *DateTime::put(char *buf) const { Date::put(buf); buf[10] = ' '; Time::put(buf+11); return buf; } time_t DateTime::get(void) const { char buf[11]; tm_t dt; memset(&dt, 0, sizeof(dt)); Date::put(buf); ZNumber nyear(buf, 4); ZNumber nmonth(buf + 5, 2); ZNumber nday(buf + 8, 2); dt.tm_year = nyear() - 1900; dt.tm_mon = nmonth() - 1; dt.tm_mday = nday(); Time::put(buf); ZNumber nhour(buf, 2); ZNumber nminute(buf + 2, 2); ZNumber nsecond(buf + 4, 2); dt.tm_hour = nhour(); dt.tm_min = nminute(); dt.tm_sec = nsecond(); dt.tm_isdst = -1; return mktime(&dt); } DateTime& DateTime::operator=(const DateTime& datetime) { julian = datetime.julian; seconds = datetime.seconds; return *this; } DateTime& DateTime::operator+=(long value) { seconds += value; update(); return *this; } DateTime& DateTime::operator-=(long value) { seconds -= value; update(); return *this; } void DateTime::update(void) { julian += (seconds / c_day); Time::update(); } bool DateTime::operator==(const DateTime &d) const { return (julian == d.julian) && (seconds == d.seconds); } bool DateTime::operator!=(const DateTime &d) const { return (julian != d.julian) || (seconds != d.seconds); } bool DateTime::operator<(const DateTime &d) const { if (julian != d.julian) { return (julian < d.julian); } else { return (seconds < d.seconds); } } bool DateTime::operator<=(const DateTime &d) const { if (julian != d.julian) { return (julian < d.julian); } else { return (seconds <= d.seconds); } } bool DateTime::operator>(const DateTime &d) const { if (julian != d.julian) { return (julian > d.julian); } else { return (seconds > d.seconds); } } bool DateTime::operator>=(const DateTime &d) const { if (julian != d.julian) { return (julian > d.julian); } else { return (seconds >= d.seconds); } } bool DateTime::operator!() const { return !(Date::is_valid() && Time::is_valid()); } String DateTime::format(const char *text) const { char buffer[64]; size_t last; time_t t; tm_t *tbp; String retval; t = get(); tbp = local(&t); last = ::strftime(buffer, 64, text, tbp); release(tbp); buffer[last] = '\0'; retval = buffer; return retval; } long DateTime::operator-(const DateTime &dt) { long secs = (julian - dt.julian) * c_day; secs += (seconds - dt.seconds); return secs; } DateTime DateTime::operator+(long value) { DateTime result = *this; result += value; return result; } DateTime DateTime::operator-(long value) { DateTime result = *this; result -= value; return result; } DateTime& DateTime::operator++() { ++julian; update(); return *this; } DateTime& DateTime::operator--() { --julian; update(); return *this; } DateTime::operator double() const { return (double)julian + ((double)seconds/86400.0); } DateNumber::DateNumber(char *str) : Number(str, 10), Date(str, 10) {} DateNumber::~DateNumber() {} void DateNumber::update(void) { Date::put(buffer); } void DateNumber::set(void) { Date::set(); update(); } DateTimeString::DateTimeString(const time_t t) : DateTime(t) { mode = BOTH; DateTimeString::update(); } DateTimeString::~DateTimeString() { } DateTimeString::DateTimeString(const tm_t *dt) : DateTime(dt) { mode = BOTH; DateTimeString::update(); } DateTimeString::DateTimeString(const DateTimeString& copy) : DateTime(copy) { mode = copy.mode; DateTimeString::update(); } DateTimeString::DateTimeString(const char *a_str, size_t size) : DateTime(a_str, size) { mode = BOTH; DateTimeString::update(); } DateTimeString::DateTimeString(int year, unsigned month, unsigned day, int hour, int minute, int second) : DateTime(year, month, day, hour, minute, second) { mode = BOTH; DateTimeString::update(); } DateTimeString::DateTimeString(mode_t m) : DateTime() { mode = m; DateTimeString::update(); } void DateTimeString::update(void) { DateTime::update(); switch(mode) { case BOTH: DateTime::put(buffer); break; case DATE: Date::put(buffer); break; case TIME: Time::put(buffer); } } void DateTimeString::set(mode_t newmode) { mode = newmode; update(); } void DateTimeString::set(void) { DateTime::set(); update(); } isotime::isotime(Time& time) { t = &time; pos = 0; mode = TIME; time.put(buf); } isotime::isotime(Date& date) { d = &date; pos = 0; mode = DATE; date.put(buf); } isotime::isotime(Date& date, Time& time) { d = &date; t = &time; pos = 0; mode = DATETIME; date.put(buf); buf[10] = ' '; time.put(buf + 11); } const char *isotime::_print(void) const { return buf; } int isotime::_input(int code) { if(isdigit(buf[pos]) && isdigit(code)) { buf[pos++] = code; if(buf[pos] == 0) { code = EOF; goto final; } return 0; } if(code == buf[pos]) { ++pos; return 0; } final: buf[pos] = 0; switch(mode) { case DATE: d->set(buf); break; case TIME: t->set(buf); break; case DATETIME: buf[10] = 0; d->set(buf); t->set(buf + 11); break; }; return code; } extern "C" { long tzoffset(struct timezone *tz) { struct timeval now; time_t t1, t2 = 0; struct tm t; gettimeofday(&now, tz); t1 = now.tv_sec; #ifdef HAVE_GMTIME_R gmtime_r(&t1, &t); #else t = *gmtime(&t1); #endif t.tm_isdst = 0; t2 = mktime(&t); return (long)difftime(t1, t2); } } } // namespace ucommon ucommon-6.4.4/corelib/counter.cpp0000644000175000001440000000361512504370221013722 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif namespace ucommon { counter::counter() { cycle = value = 0; } counter::counter(unsigned max) { assert(max > 0); cycle = max; value = 0; } void counter::operator=(unsigned v) { if(!cycle || v < cycle) value = v; } unsigned counter::get(void) { unsigned v = value++; if(cycle && value >= cycle) value = 0; return v; } SeqCounter::SeqCounter(void *base, size_t size, unsigned limit) : counter(limit) { assert(base != NULL); assert(size > 0); assert(limit > 0); item = base; offset = size; } void *SeqCounter::get(void) { unsigned pos = counter::get(); return (caddr_t)item + (pos * offset); } void *SeqCounter::get(unsigned pos) { if(pos >= range()) return NULL; return (caddr_t)item + (pos * offset); } bool toggle::get(void) { bool v = value; if(value) value = false; else value = true; return v; } } // namespace ucommon ucommon-6.4.4/corelib/string.cpp0000664000175000017500000012173312545756276013610 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include #ifdef HAVE_FCNTL_H #include #endif #include namespace ucommon { #if _MSC_VER > 1400 // windows broken dll linkage issue... #else const strsize_t String::npos = (strsize_t)(-1); const size_t memstring::header = sizeof(cstring); const char String::eos = '\0'; #endif String::cstring::cstring(strsize_t size) : CountedObject() { max = size; len = 0; fill = 0; text[0] = 0; } String::cstring::cstring(strsize_t size, char f) : CountedObject() { max = size; len = 0; fill = f; if(fill) { memset(text, fill, max); len = max; } } void String::cstring::fix(void) { while(fill && len < max) text[len++] = fill; text[len] = 0; } void String::cstring::unfix(void) { while(len && fill) { if(text[len - 1] == fill) --len; } text[len] = 0; } void String::cstring::clear(strsize_t offset, strsize_t size) { if(!fill || offset >= max) return; while(size && offset < max) { text[offset++] = fill; --size; } } void String::cstring::dec(strsize_t offset) { if(!len) return; if(offset >= len) { text[0] = 0; len = 0; fix(); return; } if(!fill) { text[--len] = 0; return; } while(len) { if(text[--len] == fill) break; } text[len] = 0; fix(); } void String::cstring::inc(strsize_t offset) { if(!offset) ++offset; if(offset >= len) { text[0] = 0; len = 0; fix(); return; } memmove(text, text + offset, len - offset); len -= offset; fix(); } void String::cstring::add(const char *str) { strsize_t size = (strsize_t)strlen(str); if(!size) return; while(fill && len && text[len - 1] == fill) --len; if(len + size > max) size = max - len; if(size < 1) return; memcpy(text + len, str, size); len += size; fix(); } void String::cstring::add(char ch) { if(!ch) return; while(fill && len && text[len - 1] == fill) --len; if(len == max) return; text[len++] = ch; fix(); } void String::cstring::set(strsize_t offset, const char *str, strsize_t size) { assert(str != NULL); if(offset >= max || offset > len) return; if(offset + size > max) size = max - offset; while(*str && size) { text[offset++] = *(str++); --size; } while(size && fill) { text[offset++] = fill; --size; } if(offset > len) { len = offset; text[len] = 0; } } char String::fill(void) { if(!str) return 0; return str->fill; } strsize_t String::size(void) const { if(!str) return 0; return str->max; } strsize_t String::len(void) const { if(!str) return 0; return str->len; } void String::cstring::set(const char *str) { assert(str != NULL); strsize_t size = (strsize_t)strlen(str); if(size > max) size = max; if(str < text || str > text + len) memcpy(text, str, size); else if(str != text) memmove(text, str, size); len = size; fix(); } String::String() { str = NULL; } String::String(const char *s, const char *end) { strsize_t size = 0; if(!s) s = ""; else if(!end) size = (strsize_t)strlen(s); else if(end > s) size = (strsize_t)(end - s); str = create(size); str->retain(); str->set(s); } String::String(const char *s) { strsize_t size = (strsize_t)count(s); if(!s) s = ""; str = create(size); str->retain(); str->set(s); } String::String(const char *s, strsize_t size) { if(!s) s = ""; if(!size) size = (strsize_t)strlen(s); str = create(size); str->retain(); str->set(s); } String::String(strsize_t size) { str = create(size); str->retain(); } String::String(long value) { str = create(20); str->retain(); snprintf(&str->text[0], 20, "%ld", value); str->len = (strsize_t)strlen(str->text); str->fix(); } String::String(double value) { str = create(32); str->retain(); snprintf(&str->text[0], 32, "%f", value); str->len = (strsize_t)strlen(str->text); str->fix(); } String::String(strsize_t size, char fill) { str = create(size, fill); str->retain(); } String::String(strsize_t size, const char *format, ...) { assert(format != NULL); va_list args; va_start(args, format); str = create(size); str->retain(); vsnprintf(str->text, size + 1, format, args); va_end(args); } String::String(const String &dup) { str = dup.c_copy(); if(str) str->retain(); } String::~String() { String::release(); } String::cstring *String::c_copy(void) const { return str; } String String::get(strsize_t offset, strsize_t len) const { if(!str || offset >= str->len) return String(""); if(!len) len = str->len - offset; return String(str->text + offset, len); } String::cstring *String::create(strsize_t size, char fill) const { void *mem = ::malloc(size + sizeof(cstring)); if(fill) return new(mem) cstring(size, fill); else return new(mem) cstring(size); } void String::cstring::dealloc(void) { this->cstring::~cstring(); ::free(this); } void String::retain(void) { if(str) str->retain(); } void String::release(void) { if(str) str->release(); str = NULL; } char *String::c_mem(void) const { if(!str) return NULL; return str->text; } const char *String::c_str(void) const { if(!str) return ""; return str->text; } bool String::equal(const char *s) const { #ifdef HAVE_STRCOLL const char *mystr = ""; if(str) mystr = str->text; if(!s) s = ""; return strcmp(mystr, s) == 0; #else return compare(s) == 0; #endif } int String::compare(const char *s) const { const char *mystr = ""; if(str) mystr = str->text; if(!s) s = ""; #ifdef HAVE_STRCOLL return strcoll(mystr, s); #else return strcmp(mystr, s); #endif } const char *String::begin(void) const { if(!str) return NULL; return str->text; } const char *String::end(void) const { if(!str) return NULL; return str->text + str->len; } const char *String::chr(char ch) const { assert(ch != 0); if(!str) return NULL; return ::strchr(str->text, ch); } const char *String::rchr(char ch) const { assert(ch != 0); if(!str) return NULL; return ::strrchr(str->text, ch); } const char *String::skip(const char *clist, strsize_t offset) const { if(!str || !clist || !*clist || !str->len || offset > str->len) return NULL; while(offset < str->len) { if(!strchr(clist, str->text[offset])) return str->text + offset; ++offset; } return NULL; } const char *String::rskip(const char *clist, strsize_t offset) const { if(!str || !clist || !*clist) return NULL; if(!str->len) return NULL; if(offset > str->len) offset = str->len; while(offset--) { if(!strchr(clist, str->text[offset])) return str->text + offset; } return NULL; } const char *String::rfind(const char *clist, strsize_t offset) const { if(!str || !clist || !*clist) return NULL; if(!str->len) return str->text; if(offset > str->len) offset = str->len; while(offset--) { if(strchr(clist, str->text[offset])) return str->text + offset; } return NULL; } void String::chop(const char *clist) { strsize_t offset; if(!str) return; if(!str->len) return; offset = str->len; while(offset) { if(!strchr(clist, str->text[offset - 1])) break; --offset; } if(!offset) { clear(); return; } if(offset == str->len) return; str->len = offset; str->fix(); } void String::strip(const char *clist) { trim(clist); chop(clist); } void String::trim(const char *clist) { unsigned offset = 0; if(!str) return; while(offset < str->len) { if(!strchr(clist, str->text[offset])) break; ++offset; } if(!offset) return; if(offset == str->len) { clear(); return; } memmove(str->text, str->text + offset, str->len - offset); str->len -= offset; str->fix(); } unsigned String::replace(const char *substring, const char *cp, unsigned flags) { const char *result = ""; unsigned count = 0; strsize_t cpl = 0; if(cp) cpl = (strsize_t)strlen(cp); if(!str || !substring || str->len == 0) return 0; strsize_t offset = 0; strsize_t tcl = (strsize_t)strlen(substring); while(result) { const char *text = str->text + offset; #if defined(_MSWINDOWS_) if((flags & 0x01) == INSENSITIVE) result = strstr(text, substring); #elif defined(HAVE_STRICMP) if((flags & 0x01) == INSENSITIVE) result = stristr(text, substring); #else if((flags & 0x01) == INSENSITIVE) result = strcasestr(text, substring); #endif else result = strstr(text, substring); if(result) { ++count; offset = (strsize_t)(text - str->text); cut(offset, tcl); if(cpl) { paste(offset, cp); offset += cpl; } } } return count; } const char *String::search(const char *substring, unsigned instance, unsigned flags) const { const char *result = ""; if(!str || !substring || str->len == 0) return NULL; const char *text = str->text; if(!instance) ++instance; while(instance-- && result) { #if defined(_MSWINDOWS_) if((flags & 0x01) == INSENSITIVE) result = strstr(text, substring); #elif defined(HAVE_STRICMP) if((flags & 0x01) == INSENSITIVE) result = stristr(text, substring); #else if((flags & 0x01) == INSENSITIVE) result = strcasestr(text, substring); #endif else result = strstr(text, substring); if(result) text = result + strlen(result); } return result; } const char *String::find(const char *clist, strsize_t offset) const { if(!str || !clist || !*clist || !str->len || offset > str->len) return NULL; while(offset < str->len) { if(strchr(clist, str->text[offset])) return str->text + offset; ++offset; } return NULL; } bool String::unquote(const char *clist) { assert(clist != NULL); char *s; if(!str) return false; str->unfix(); s = unquote(str->text, clist); if(!s) { str->fix(); return false; } set(s); return true; } void String::upper(void) { if(str) upper(str->text); } void String::lower(void) { if(str) lower(str->text); } void String::erase(void) { if(str) { memset(str->text, 0, str->max); str->fix(); } } strsize_t String::offset(const char *s) const { if(!str || !s) return npos; if(s < str->text || s > str->text + str->max) return npos; if(s - str->text > str->len) return str->len; return (strsize_t)(s - str->text); } strsize_t String::count(void) const { if(!str) return 0; return str->len; } strsize_t String::ccount(const char *clist) const { if(!str) return 0; return ccount(str->text, clist); } strsize_t String::printf(const char *format, ...) { assert(format != NULL); va_list args; va_start(args, format); if(str) { vsnprintf(str->text, str->max + 1, format, args); str->len = (strsize_t)strlen(str->text); str->fix(); } va_end(args); return len(); } strsize_t String::vprintf(const char *format, va_list args) { assert(format != NULL); if(str) { vsnprintf(str->text, str->max + 1, format, args); str->len = (strsize_t)strlen(str->text); str->fix(); } return len(); } #if !defined(_MSC_VER) int String::vscanf(const char *format, va_list args) { assert(format != NULL); if(str) return vsscanf(str->text, format, args); return -1; } int String::scanf(const char *format, ...) { assert(format != NULL); va_list args; int rtn = -1; va_start(args, format); if(str) rtn = vsscanf(str->text, format, args); va_end(args); return rtn; } #else int String::vscanf(const char *format, va_list args) { return 0; } int String::scanf(const char *format, ...) { return 0; } #endif void String::rsplit(const char *s) { if(!str || !s || s <= str->text || s > str->text + str->len) return; str->set(s); } void String::rsplit(strsize_t pos) { if(!str || pos > str->len || !pos) return; str->set(str->text + pos); } void String::split(const char *s) { size_t pos; if(!s || !*s || !str) return; if(s < str->text || s >= str->text + str->len) return; pos = s - str->text; str->text[pos] = 0; str->fix(); } void String::split(strsize_t pos) { if(!str || pos >= str->len) return; str->text[pos] = 0; str->fix(); } void String::set(strsize_t offset, const char *s, strsize_t size) { if(!s || !*s || !str) return; if(!size) size = (strsize_t)strlen(s); str->set(offset, s, size); } void String::set(const char *s, char overflow, strsize_t offset, strsize_t size) { size_t len = count(s); if(!s || !*s || !str) return; if(offset >= str->max) return; if(!size || size > str->max - offset) size = str->max - offset; if(len <= size) { set(offset, s, size); return; } set(offset, s, size); if(len > size && overflow) str->text[offset + size - 1] = overflow; } void String::rset(const char *s, char overflow, strsize_t offset, strsize_t size) { strsize_t len = (strsize_t)count(s); strsize_t dif; if(!s || !*s || !str) return; if(offset >= str->max) return; if(!size || size > str->max - offset) size = str->max - offset; dif = len; while(dif < size && str->fill) { str->text[offset++] = str->fill; ++dif; } if(len > size) s += len - size; set(offset, s, size); if(overflow && len > size) str->text[offset] = overflow; } void String::set(const char *s) { strsize_t len; if(!s) s = ""; if(!str) { len = (strsize_t)strlen(s); str = create(len); str->retain(); } str->set(s); } void String::paste(strsize_t offset, const char *cp, strsize_t size) { if(!cp) return; if(!size) size = (strsize_t)strlen(cp); if(!size) return; if(!str) { str = create(size); String::set(str->text, ++size, cp); str->len = --size; str->fix(); return; } cow(size); if(offset >= str->len) String::set(str->text + str->len, size + 1, cp); else { memmove(str->text + offset + size, str->text + offset, str->len - offset); memmove(str->text + offset, cp, size); } str->len += size; str->fix(); } void String::cut(strsize_t offset, strsize_t size) { if(!str || offset >= str->len) return; if(!size) size = str->len; if(offset + size >= str->len) { str->len = offset; str->fix(); return; } memmove(str->text + offset, str->text + offset + size, str->len - offset - size); str->len -= size; str->fix(); } void String::paste(char *text, size_t max, size_t offset, const char *cp, size_t size) { if(!cp || !text) return; if(!size) size = strlen(cp); if(!size) return; size_t len = strlen(text); if(len <= max) return; if(len + size >= max) size = max - len; if(offset >= len) String::set(text + len, size + 1, cp); else { memmove(text + offset + size, text + offset, len - offset); memmove(text + offset, cp, size); } } void String::cut(char *text, size_t offset, size_t size) { if(!text) return; size_t len = strlen(text); if(!len || offset >= len) return; if(offset + size >= len) { text[offset] = 0; return; } memmove(text + offset, text + offset + size, len - offset - size); len -= size; text[len] = 0; } bool String::resize(strsize_t size) { char fill = 0; if(!size) { release(); str = NULL; return true; } if(!str) { str = create(size, fill); str->retain(); } else if(str->is_copied() || str->max < size) { fill = str->fill; str->release(); str = create(size, fill); str->retain(); } return true; } void String::clear(strsize_t offset, strsize_t size) { if(!str) return; if(!size) size = str->max; str->clear(offset, size); } void String::clear(void) { if(str) str->set(""); } void String::cow(strsize_t size) { if(str) { if(str->fill) size = str->max; else size += str->len; } if(!size) return; if(!str || !str->max || str->is_copied() || size > str->max) { cstring *s = create(size); if (!s) return; if (str) { s->len = str->len; String::set(s->text, s->max + 1, str->text); } else s->len = 0; s->retain(); if (str) str->release(); str = s; } } void String::add(char ch) { char buf[2]; if(ch == 0) return; buf[0] = ch; buf[1] = 0; if(!str) { set(buf); return; } cow(1); str->add(buf); } void String::add(const char *s) { if(!s || !*s) return; if(!str) { set(s); return; } cow((strsize_t)strlen(s)); str->add(s); } char String::at(int offset) const { if(!str) return 0; if(offset >= (int)str->len) return 0; if(offset > -1) return str->text[offset]; if((strsize_t)(-offset) >= str->len) return str->text[0]; return str->text[(int)(str->len) + offset]; } String String::operator()(int offset, strsize_t len) const { const char *cp = operator()(offset); if(!cp) cp = ""; if(!len) len = (strsize_t)strlen(cp); return String(cp, len); } const char *String::operator()(int offset) const { if(!str) return NULL; if(offset >= (int)str->len) return NULL; if(offset > -1) return str->text + offset; if((strsize_t)(-offset) >= str->len) return str->text; return str->text + str->len + offset; } const char String::operator[](int offset) const { if(!str) return 0; if(offset >= (int)str->len) return 0; if(offset > -1) return str->text[offset]; if((strsize_t)(-offset) >= str->len) return *str->text; return str->text[str->len + offset]; } String &String::operator++() { if(str) str->inc(1); return *this; } String &String::operator--() { if(str) str->dec(1); return *this; } String &String::operator+=(strsize_t offset) { if(str) str->inc(offset); return *this; } String &String::operator-=(strsize_t offset) { if(str) str->dec(offset); return *this; } bool String::operator*=(const char *substr) { if(search(substr)) return true; return false; } String &String::operator^=(const char *s) { release(); set(s); return *this; } String &String::operator=(const char *s) { release(); set(s); return *this; } String &String::operator|=(const char *s) { set(s); return *this; } String &String::operator&=(const char *s) { set(s); return *this; } String &String::operator^=(const String &s) { release(); set(s.c_str()); return *this; } String &String::operator=(const String &s) { if(str == s.str) return *this; if(s.str) s.str->retain(); if(str) str->release(); str = s.str; return *this; } bool String::full(void) const { if(!str) return false; if(str->len == str->max && str->text[str->len - 1] != str->fill) return true; return false; } bool String::operator!() const { bool rtn = false; if(!str) return true; str->unfix(); if(!str->len) rtn = true; str->fix(); return rtn; } String::operator bool() const { bool rtn = false; if(!str) return false; str->unfix(); if(str->len) rtn = true; str->fix(); return rtn; } bool String::operator==(const char *s) const { return (compare(s) == 0); } bool String::operator!=(const char *s) const { return (compare(s) != 0); } bool String::operator<(const char *s) const { return (compare(s) < 0); } bool String::operator<=(const char *s) const { return (compare(s) <= 0); } bool String::operator>(const char *s) const { return (compare(s) > 0); } bool String::operator>=(const char *s) const { return (compare(s) >= 0); } String &String::operator&(const char *s) { add(s); return *this; } String &String::operator|(const char *s) { if(!s || !*s) return *this; if(!str) { set(s); return *this; } str->add(s); return *this; } String String::operator+(const char *s) { String tmp; if(str && str->text[0]) tmp.set(str->text); if(s && *s) tmp.add(s); return tmp; } String &String::operator+=(const char *s) { if(!s || !*s) return *this; add(s); return *this; } memstring::memstring(void *mem, strsize_t size, char fill) { assert(mem != NULL); assert(size > 0); str = new(mem) cstring(size, fill); str->set(""); } memstring::~memstring() { str = NULL; } memstring *memstring::create(strsize_t size, char fill) { assert(size > 0); void *mem = ::malloc(size + sizeof(memstring) + sizeof(cstring)); return new(mem) memstring((caddr_t)mem + sizeof(memstring), size, fill); } memstring *memstring::create(MemoryProtocol *mpager, strsize_t size, char fill) { assert(size > 0); void *mem = mpager->alloc(size + sizeof(memstring) + sizeof(cstring)); return new(mem) memstring((caddr_t)mem + sizeof(memstring), size, fill); } void memstring::release(void) { str = NULL; } bool memstring::resize(strsize_t size) { return false; } void memstring::cow(strsize_t adj) { } char *String::token(char *text, char **token, const char *clist, const char *quote, const char *eol) { char *result; if(!eol) eol = ""; if(!token || !clist) return NULL; if(!*token) *token = text; if(!**token) { *token = text; return NULL; } while(**token && strchr(clist, **token)) ++*token; result = *token; if(*result && *eol && NULL != (eol = strchr(eol, *result))) { if(eol[0] != eol[1] || *result == eol[1]) { *token = text; return NULL; } } if(!*result) { *token = text; return NULL; } while(quote && *quote && *result != *quote) { quote += 2; } if(quote && *quote) { ++result; ++quote; *token = strchr(result, *quote); if(!*token) *token = result + strlen(result); else { **token = 0; ++(*token); } return result; } while(**token && !strchr(clist, **token)) ++(*token); if(**token) { **token = 0; ++(*token); } return result; } String::cstring *memstring::c_copy(void) const { cstring *tmp = String::create(str->max, str->fill); tmp->set(str->text); return tmp; } void String::fix(String &s) { if(s.str) { s.str->len = (strsize_t)strlen(s.str->text); s.str->fix(); } } void String::swap(String &s1, String &s2) { String::cstring *s = s1.str; s1.str = s2.str; s2.str = s; } char *String::dup(const char *cp) { char *mem; if(!cp) return NULL; size_t len = strlen(cp) + 1; mem = (char *)malloc(len); crit(mem != NULL, "string dup allocation error"); String::set(mem, len, cp); return mem; } char *String::left(const char *cp, size_t size) { char *mem; if(!cp) return NULL; if(!size) size = strlen(cp); mem = (char *)malloc(++size); crit(mem != NULL, "string dup allocation error"); String::set(mem, size, cp); return mem; } const char *String::pos(const char *cp, ssize_t offset) { if(!cp) return NULL; size_t len = strlen(cp); if(!len) return cp; if(offset >= 0) { if((size_t)offset > len) offset = (ssize_t)len; return cp + offset; } offset = -offset; if((size_t)offset >= len) return cp; return cp + len - offset; } size_t String::count(const char *cp) { if(!cp) return 0; return strlen(cp); } const char *String::find(const char *str, const char *key, const char *delim) { size_t l1 = strlen(str); size_t l2 = strlen(key); if(!delim[0]) delim = NULL; while(l1 >= l2) { if(!strncmp(key, str, l2)) { if(l1 == l2 || !delim || strchr(delim, str[l2])) return str; } if(!delim) { ++str; --l1; continue; } while(l1 >= l2 && !strchr(delim, *str)) { ++str; --l1; } while(l1 >= l2 && strchr(delim, *str)) { ++str; --l1; } } return NULL; } const char *String::ifind(const char *str, const char *key, const char *delim) { size_t l1 = strlen(str); size_t l2 = strlen(key); if(!delim[0]) delim = NULL; while(l1 >= l2) { if(!strnicmp(key, str, l2)) { if(l1 == l2 || !delim || strchr(delim, str[l2])) return str; } if(!delim) { ++str; --l1; continue; } while(l1 >= l2 && !strchr(delim, *str)) { ++str; --l1; } while(l1 >= l2 && strchr(delim, *str)) { ++str; --l1; } } return NULL; } char *String::set(char *str, size_t size, const char *s, size_t len) { if(!str) return NULL; if(size < 2) return str; if(!s) s = ""; size_t l = strlen(s); if(l >= size) l = size - 1; if(l > len) l = len; if(!l) { *str = 0; return str; } memmove(str, s, l); str[l] = 0; return str; } char *String::rset(char *str, size_t size, const char *s) { size_t len = count(s); if(len > size) s += len - size; return set(str, size, s); } char *String::set(char *str, size_t size, const char *s) { if(!str) return NULL; if(size < 2) return str; if(!s) s = ""; size_t l = strlen(s); if(l >= size) l = size - 1; if(!l) { *str = 0; return str; } memmove(str, s, l); str[l] = 0; return str; } char *String::add(char *str, size_t size, const char *s, size_t len) { if(!str) return NULL; if(!s) return str; size_t l = strlen(s); size_t o = strlen(str); if(o >= (size - 1)) return str; set(str + o, size - o, s, l); return str; } char *String::add(char *str, size_t size, const char *s) { if(!str) return NULL; if(!s) return str; size_t o = strlen(str); if(o >= (size - 1)) return str; set(str + o, size - o, s); return str; } char *String::trim(char *str, const char *clist) { if(!str) return NULL; if(!clist) return str; while(*str && strchr(clist, *str)) ++str; return str; } char *String::chop(char *str, const char *clist) { if(!str) return NULL; if(!clist) return str; size_t offset = strlen(str); while(offset && strchr(clist, str[offset - 1])) str[--offset] = 0; return str; } char *String::strip(char *str, const char *clist) { str = trim(str, clist); chop(str, clist); return str; } bool String::check(const char *str, size_t max, size_t min) { size_t count = 0; if(!str) return false; while(*str) { if(++count > max) return false; ++str; } if(count < min) return false; return true; } void String::upper(char *str) { while(str && *str) { *str = toupper(*str); ++str; } } void String::lower(char *str) { while(str && *str) { *str = tolower(*str); ++str; } } void String::erase(char *str) { if(!str || *str == 0) return; memset(str, 0, strlen(str)); } unsigned String::ccount(const char *str, const char *clist) { unsigned count = 0; while(str && *str) { if(strchr(clist, *(str++))) ++count; } return count; } char *String::skip(char *str, const char *clist) { if(!str || !clist) return NULL; while(*str && strchr(clist, *str)) ++str; if(*str) return str; return NULL; } char *String::rskip(char *str, const char *clist) { size_t len = count(str); if(!len || !clist) return NULL; while(len > 0) { if(!strchr(clist, str[--len])) return str; } return NULL; } size_t String::seek(char *str, const char *clist) { size_t pos = 0; if(!str) return 0; if(!clist) return strlen(str); while(str[pos]) { if(strchr(clist, str[pos])) return pos; ++pos; } return pos; } char *String::find(char *str, const char *clist) { if(!str) return NULL; if(!clist) return str; while(str && *str) { if(strchr(clist, *str)) return str; } return NULL; } char *String::rfind(char *str, const char *clist) { if(!str) return NULL; if(!clist) return str + strlen(str); char *s = str + strlen(str); while(s > str) { if(strchr(clist, *(--s))) return s; } return NULL; } bool String::eq_case(const char *s1, const char *s2) { if(!s1) s1 = ""; if(!s2) s2 = ""; #ifdef HAVE_STRICMP return stricmp(s1, s2) == 0; #else return strcasecmp(s1, s2) == 0; #endif } int String::case_compare(const char *s1, const char *s2) { if(!s1) s1 = ""; if(!s2) s2 = ""; #ifdef HAVE_STRICMP return stricmp(s1, s2); #else return strcasecmp(s1, s2); #endif } int String::case_compare(const char *s1, const char *s2, size_t size) { if(!s1) s1 = ""; if(!s2) s2 = ""; #ifdef HAVE_STRICMP return strnicmp(s1, s2, size); #else return strncasecmp(s1, s2, size); #endif } bool String::eq_case(const char *s1, const char *s2, size_t size) { if(!s1) s1 = ""; if(!s2) s2 = ""; #ifdef HAVE_STRICMP return strnicmp(s1, s2, size) == 0; #else return strncasecmp(s1, s2, size) == 0; #endif } bool String::equal(const char *s1, const char *s2) { if(!s1) s1 = ""; if(!s2) s2 = ""; return strcmp(s1, s2) == 0; } bool String::equal(const char *s1, const char *s2, size_t size) { if(!s1) s1 = ""; if(!s2) s2 = ""; return strncmp(s1, s2, size) == 0; } int String::compare(const char *s1, const char *s2) { if(!s1) s1 = ""; if(!s2) s2 = ""; #ifdef HAVE_STRCOLL return strcoll(s1, s2); #else return strcmp(s1, s2); #endif } char *String::unquote(char *str, const char *clist) { assert(clist != NULL); size_t len = count(str); if(!len || !str) return NULL; while(clist[0]) { if(*str == clist[0] && str[len - 1] == clist[1]) { str[len - 1] = 0; return ++str; } clist += 2; } return str; } char *String::fill(char *str, size_t size, char fill) { if(!str) return NULL; memset(str, fill, size - 1); str[size - 1] = 0; return str; } unsigned String::hexsize(const char *format) { unsigned count = 0; char *ep; unsigned skip; while(format && *format) { while(*format && !isdigit(*format)) { ++format; ++count; } if(isdigit(*format)) { skip = (unsigned)strtol(format, &ep, 10); format = ep; count += skip * 2; } } return count; } String String::hex(const unsigned char *binary, size_t size) { strsize_t ssize = (strsize_t)(size * 2); String out(ssize, ' '); char *buf = out.c_mem(); while(size--) { snprintf(buf, 3, "%02x", *(binary++)); buf += 2; } return out; } unsigned String::hexdump(const unsigned char *binary, char *string, const char *format) { unsigned count = 0; char *ep; unsigned skip; while(format && *format) { while(*format && !isdigit(*format)) { *(string++) = *(format++); ++count; } if(isdigit(*format)) { skip = (unsigned)strtol(format, &ep, 10); format = ep; count += skip * 2; while(skip--) { snprintf(string, 3, "%02x", *(binary++)); string += 2; } } } *string = 0; return count; } static unsigned hexcode(char ch) { if(ch >= '0' && ch <= '9') return ch - '0'; else return toupper(ch) - 'A' + 10; } unsigned String::hexpack(unsigned char *binary, const char *string, const char *format) { unsigned count = 0; char *ep; unsigned skip; while(format && *format) { while(*format && !isdigit(*format)) { if(*(string++) != *(format++)) return count; ++count; } if(isdigit(*format)) { skip = (unsigned)strtol(format, &ep, 10); format = ep; count += skip * 2; while(skip--) { *(binary++) = hexcode(string[0]) * 16 + hexcode(string[1]); string += 2; } } } return count; } String &String::operator%(unsigned short& value) { unsigned long temp = USHRT_MAX + 1; char *ep; if(!str || !str->text[0]) return *this; value = 0; temp = strtoul(str->text, &ep, 0); if(temp > USHRT_MAX) goto failed; value = (unsigned short)temp; if(ep) set(ep); else set(""); failed: return *this; } String &String::operator%(short& value) { long temp = SHRT_MAX + 1; char *ep; if(!str || !str->text[0]) return *this; value = 0; temp = strtol(str->text, &ep, 0); if(temp < 0 && temp < SHRT_MIN) goto failed; if(temp > SHRT_MAX) goto failed; value = (short)temp; if(ep) set(ep); else set(""); failed: return *this; } String &String::operator%(long& value) { value = 0; char *ep; if(!str || !str->text[0]) return *this; value = strtol(str->text, &ep, 0); if(ep) set(ep); else set(""); return *this; } String &String::operator%(unsigned long& value) { value = 0; char *ep; if(!str || !str->text[0]) return *this; value = strtoul(str->text, &ep, 0); if(ep) set(ep); else set(""); return *this; } String &String::operator%(double& value) { value = 0; char *ep; if(!str || !str->text[0]) return *this; value = strtod(str->text, &ep); if(ep) set(ep); else set(""); return *this; } String &String::operator%(const char *get) { if(!str || !str->text[0] || !get) return *this; unsigned len = (strsize_t)strlen(get); const char *cp = str->text; while(isspace(*cp)) ++cp; if(eq(cp, get, len)) set(cp + len); else if(cp != str->text) set(cp); return *this; } String str(CharacterProtocol *p, strsize_t size) { String temp(size); char *cp = temp.c_mem(); int ch; bool cr = false; while(--size) { ch = p->getchar(); if(ch == 0 || ch == EOF || ch == '\n') break; if(cr) { cr = false; *(cp++) = '\r'; } if(ch == '\r') cr = true; else *(cp++) = ch; } *cp = 0; String::fix(temp); return temp; } static const unsigned char alphabet[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; String String::b64(const uint8_t *bin, size_t size) { strsize_t dsize = (strsize_t)((size * 4 / 3) + 1); String out(dsize, String::eos); b64encode(out.c_mem(), bin, size); return out; } size_t String::b64encode(char *dest, const uint8_t *bin, size_t size, size_t dsize) { assert(dest != NULL && bin != NULL); size_t count = 0; if(!dsize) dsize = (size * 4 / 3) + 1; if (!dsize || !size) goto end; unsigned bits; while(size >= 3 && dsize > 4) { bits = (((unsigned)bin[0])<<16) | (((unsigned)bin[1])<<8) | ((unsigned)bin[2]); bin += 3; size -= 3; count += 3; *(dest++) = alphabet[bits >> 18]; *(dest++) = alphabet[(bits >> 12) & 0x3f]; *(dest++) = alphabet[(bits >> 6) & 0x3f]; *(dest++) = alphabet[bits & 0x3f]; dsize -= 4; } if (size && dsize > 4) { bits = ((unsigned)bin[0])<<16; *(dest++) = alphabet[bits >> 18]; ++count; if (size == 1) { *(dest++) = alphabet[(bits >> 12) & 0x3f]; *(dest++) = '='; } else { ++count; bits |= ((unsigned)bin[1])<<8; *(dest++) = alphabet[(bits >> 12) & 0x3f]; *(dest++) = alphabet[(bits >> 6) & 0x3f]; } *(dest++) = '='; } end: *dest = 0; return count; } size_t String::b64decode(uint8_t *dest, const char *src, size_t size) { char decoder[256]; unsigned long bits; uint8_t c; unsigned i; size_t count = 0; for (i = 0; i < 256; ++i) decoder[i] = 64; for (i = 0; i < 64 ; ++i) decoder[alphabet[i]] = i; bits = 1; while(*src) { c = (uint8_t)(*(src++)); if (c == '=') { if (bits & 0x40000) { if (size < 2) break; *(dest++) = (uint8_t)((bits >> 10) & 0xff); *(dest++) = (uint8_t)((bits >> 2) & 0xff); count += 2; break; } if ((bits & 0x1000) && size) { *(dest++) = (uint8_t)((bits >> 4) & 0xff); ++count; } break; } // end on invalid chars if (decoder[c] == 64) break; bits = (bits << 6) + decoder[c]; if (bits & 0x1000000) { if (size < 3) break; *(dest++) = (uint8_t)((bits >> 16) & 0xff); *(dest++) = (uint8_t)((bits >> 8) & 0xff); *(dest++) = (uint8_t)((bits & 0xff)); bits = 1; size -= 3; count += 3; } } return count; } #define CRC24_INIT 0xb704ceL #define CRC24_POLY 0x1864cfbL uint32_t String::crc24(uint8_t *binary, size_t size) { uint32_t crc = CRC24_INIT; unsigned i; while (size--) { crc ^= (*binary++) << 16; for (i = 0; i < 8; i++) { crc <<= 1; if (crc & 0x1000000) crc ^= CRC24_POLY; } } return crc & 0xffffffL; } uint16_t String::crc16(uint8_t *binary, size_t size) { uint16_t crc = 0xffff; unsigned i; while (size--) { crc ^= (*binary++); for (i = 0; i < 8; i++) { if(crc & 1) crc = (crc >> 1) ^ 0xa001; else crc = (crc >> 1); } } return crc; } } // namespace ucommon ucommon-6.4.4/corelib/socket.cpp0000664000175000017500000024372012551014424013546 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include #ifndef _MSWINDOWS_ #include #include #include #include #else #define HAVE_GETADDRINFO 1 #endif #ifdef HAVE_FCNTL_H #include #endif #include #if defined(HAVE_SOCKS) #include #undef HAVE_POLL_H #undef HAVE_SYS_POLL_H #endif #if defined(HAVE_POLL_H) #include #elif defined(HAVE_SYS_POLL_H) #include #endif #if defined(HAVE_SYS_FILIO_H) #include #endif #if defined(HAVE_POLL) && defined(POLLRDNORM) #define USE_POLL #endif #if defined(__linux__) && !defined(IP_MTU) #define IP_MTU 14 #endif #ifndef MSG_DONTWAIT #define MSG_DONTWAIT 0 #endif #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif #ifdef __FreeBSD__ #ifdef AI_V4MAPPED #undef AI_V4MAPPED #endif #endif typedef struct multicast_internet { union { struct ip_mreq ipv4; #ifdef AF_INET6 struct ipv6_mreq ipv6; #endif }; } inetmulticast_t; #ifndef HAVE_GETADDRINFO struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; size_t ai_addrlen; char *ai_canonname; struct sockaddr *ai_addr; struct addrinfo *ai_next; }; #define NI_NUMERICHOST 0x0001 #define NI_NUMERICSERV 0x0002 #define NI_NAMEREQD 0x0004 #define NI_NOFQDN 0x0008 #define NI_DGRAM 0x0010 #define AI_PASSIVE 0x0100 #define AI_CANONNAME 0x0200 #define AI_NUMERICHOST 0x0400 #define AI_NUMERICSERV 0x0800 #endif #if defined(HAVE_SOCKS) #define _getsockname_(so, addr, alen) ::Rgetsockname(so, addr, alen) #define _getpeername_(so, addr, alen) ::Rgetpeername(so, addr, alen) #define _accept_(so, addr, alen) ::Raccept(so, addr, alen) #define _connect_(so, addr, alen) ::Rconnect(so, addr, alen) #define _bind_(so, addr, alen) ::Rbind(so, addr, alen) #define _listen_(so, backlog) ::Rlisten(so, backlog) #define _select_(cnt, rfd, wfd, efd, timeout) ::Rselect(cnt, rfd, wfd, efd, timeout) #define _send_(so, buf, bytes, flag) ::Rsend(so, buf, bytes, flag) #define _recv_(so, buf, bytes, flag) ::Rrecv(so, buf, bytes, flag) #define _sendto_(so, buf, bytes, flag, to, tolen) ::Rsendto(so, buf, bytes, flag, to, tolen) #define _recvfrom_(so, buf, bytes, flag, from, fromlen) ::Rrecvfrom(so, buf, bytes, flag, from, fromlen) #undef USE_POLL #undef accept #undef sendto #undef recvfrom #undef select #elif defined(__PTH__) #define _send_(so, buf, bytes, flag) pth_send(so, buf, bytes, flag) #define _recv_(so, buf, bytes, flag) pth_recv(so, buf, bytes, flag) #define _sendto_(so, buf, bytes, flag, to, tolen) pth_sendto(so, buf, bytes, flag, to, tolen) #define _recvfrom_(so, buf, bytes, flag, from, fromlen) pth_recvfrom(so, buf, bytes, flag, from, fromlen) #define _connect_(so, addr, addrlen) pth_connect(so, addr, addrlen) #define _accept_(so, addr, addrlen) pth_accept(so, addr, addrlen) #define _select_(cnt, rfd, wfd, efd, timeout) pth_select(cnt, rfd, wfd, efd, timeout) #define _poll_(fds, cnt, timeout) pth_poll(fds, cnt, timeout) #define _getsockname_(so, addr, alen) ::getsockname(so, addr, alen) #define _getpeername_(so, addr, alen) ::getpeername(so, addr, alen) #define _bind_(so, addr, alen) ::bind(so, addr, alen) #define _listen_(so, count) ::listen(so, count) #else #define _send_(so, buf, bytes, flag) ::send(so, buf, bytes, flag) #define _recv_(so, buf, bytes, flag) ::recv(so, buf, bytes, flag) #define _sendto_(so, buf, bytes, flag, to, tolen) ::sendto(so, buf, bytes, flag, to, tolen) #define _recvfrom_(so, buf, bytes, flag, from, fromlen) ::recvfrom(so, buf, bytes, flag, from, fromlen) #define _connect_(so, addr, addrlen) ::connect(so, addr, addrlen) #define _accept_(so, addr, addrlen) ::accept(so, addr, addrlen) #define _select_(cnt, rfd, wfd, efd, timeout) ::select(cnt, rfd, wfd, efd, timeout) #define _poll_(fds, cnt, timeout) ::poll(fds, cnt, timeout) #define _getsockname_(so, addr, alen) ::getsockname(so, addr, alen) #define _getpeername_(so, addr, alen) ::getpeername(so, addr, alen) #define _bind_(so, addr, alen) ::bind(so, addr, alen) #define _listen_(so, count) ::listen(so, count) #endif namespace ucommon { typedef unsigned char bit_t; static int query_family = 0; static int v6only = 0; static void socket_mapping(int family, socket_t so) { if(so == INVALID_SOCKET) return; #if defined(IPV6_V6ONLY) && defined(IPPROTO_IPV6) if(family == AF_INET6) setsockopt (so, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &v6only, sizeof (v6only)); #endif } #ifndef HAVE_GETADDRINFO static mutex servmutex, hostmutex; static void freeaddrinfo(struct addrinfo *aip) { while(aip != NULL) { struct addrinfo *next = aip->ai_next; if(aip->ai_canonname != NULL) free(aip->ai_canonname); if(aip->ai_addr != NULL) free(aip->ai_addr); free(aip); aip = next; } } static int getnameinfo(const struct sockaddr *addr, socklen_t len, char *host, size_t hostlen, char *service, size_t servlen, int flags) { char *cp; struct hostent *hp; struct servent *sp; assert(addr != NULL); assert(host != NULL || hostlen == 0); assert(service != NULL || servlen == 0); short port = 0; switch(addr->sa_family) { #ifdef AF_UNIX case AF_UNIX: if(hostlen > 0) snprintf(host, hostlen, "%s", ((struct sockaddr_un *)addr)->sun_path); if(servlen > 0) snprintf(service, servlen, "%s", ((struct sockaddr_un *)addr)->sun_path); return 0; #endif #ifdef AF_INET6 case AF_INET6: port = ((struct sockaddr_in6 *)addr)->sin6_port; break; #endif case AF_INET: port = ((struct sockaddr_in *)addr)->sin_port; break; default: return -1; } if(hostlen > 0) { if(flags & NI_NUMERICHOST) { if(inet_ntop(addr->sa_family, addr, host, hostlen) == NULL) return -1; } else { hostmutex.lock(); hp = gethostbyaddr((caddr_t)addr, len, addr->sa_family); if(hp != NULL && hp->h_name != NULL) { if(flags & NI_NOFQDN) { cp = strchr(hp->h_name, '.'); if(cp) *cp = 0; } snprintf(host, hostlen, "%s", hp->h_name); hostmutex.unlock(); } else { hostmutex.unlock(); if(flags & NI_NAMEREQD) return -1; if(inet_ntop(addr->sa_family, addr, host, hostlen) != NULL) return -1; } } } if(servlen > 0) { if(flags & NI_NUMERICSERV) snprintf(service, servlen, "%d", ntohs(port)); else { servmutex.lock(); sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : NULL); if(sp && sp->s_name) snprintf(service, servlen, "%s", sp->s_name); else snprintf(service, servlen, "%d", ntohs(port)); servmutex.unlock(); } } return 0; } static int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hintsp, struct addrinfo **res) { int family; const char *servtype = "tcp"; struct hostent *hp; struct servent *sp; char **np; struct addrinfo hints; struct addrinfo *aip = NULL, *prior = NULL; socklen_t len; short port = 0; struct sockaddr_in *ipv4; #ifdef AF_INET6 struct sockaddr_in6 *ipv6; #endif if(hintsp == NULL) { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; } else memcpy(&hints, hintsp, sizeof(hints)); *res = NULL; #ifdef AF_UNIX if(hints.ai_family == AF_UNIX || (hints.ai_family == AF_UNSPEC && hostname && *hostname == '/')) { if(hints.ai_socktype == 0) hints.ai_socktype = SOCK_STREAM; aip = (struct addrinfo *)malloc(sizeof(struct addrinfo)); memset(aip, 0, sizeof(struct addrinfo)); aip->ai_next = NULL; aip->ai_canonname = NULL; aip->ai_protocol = hints.ai_protocol; struct sockaddr_un *unp; if(strlen(hostname) >= sizeof(unp->sun_path)) return -1; unp = (struct sockaddr_un *)malloc(sizeof(struct sockaddr_un)); memset(unp, 0, sizeof(struct sockaddr_un)); unp->sun_family = AF_UNIX; String::set(unp->sun_path, sizeof(unp->sun_path), hostname); #ifdef __SUN_LEN len = sizeof(unp->sun_len) + strlen(unp->sun_path) + sizeof(unp->sun_family) + 1; unp->sun_len = len; #else len = strlen(unp->sun_path) + sizeof(unp->sun_family) + 1; #endif if(hints.ai_flags & AI_PASSIVE) unlink(unp->sun_path); aip->ai_addr = (struct sockaddr *)unp; aip->ai_addrlen = len; *res = aip; return 0; } #endif if(servname && *servname) { if(servname[0] >= '0' && servname[0] <= '9') { port = htons(atoi(servname)); } else { if(hints.ai_socktype == SOCK_DGRAM) servtype = "udp"; servmutex.lock(); sp = getservbyname(servname, servtype); if(!sp) { servmutex.unlock(); return -1; } port = sp->s_port; servmutex.unlock(); } } if((!hostname || !*hostname)) { aip = (struct addrinfo *)malloc(sizeof(struct addrinfo)); memset(aip, 0, sizeof(struct addrinfo)); aip->ai_canonname = NULL; aip->ai_socktype = hints.ai_socktype; aip->ai_protocol = hints.ai_protocol; aip->ai_next = NULL; #ifdef AF_INET6 if(hints.ai_family == AF_INET6) { aip->ai_family = AF_INET6; ipv6 = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6)); memset(ipv6, 0, sizeof(struct sockaddr_in6)); if(!(hints.ai_flags & AI_PASSIVE)) inet_pton(AF_INET6, "::1", &ipv6->sin6_addr); ipv6->sin6_family = AF_INET6; ipv6->sin6_port = port; aip->ai_addr = (struct sockaddr *)ipv6; *res = aip; return 0; } #endif aip->ai_family = AF_INET; ipv4 = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in)); memset(ipv4, 0, sizeof(struct sockaddr_in)); ipv4->sin_family = AF_INET; ipv4->sin_port = port; if(!(hints.ai_flags & AI_PASSIVE)) inet_pton(AF_INET, "127.0.0.1", &ipv4->sin_addr); aip->ai_addr = (struct sockaddr *)ipv4; *res = aip; return 0; } family = hints.ai_family; #ifdef AF_UNSPEC if(family == AF_UNSPEC) family = AF_INET; #endif hostmutex.lock(); #ifdef HAVE_GETHOSTBYNAME2 hp = gethostbyname2(hostname, family); #else hp = gethostbyname(hostname); #endif if(!hp) { hostmutex.unlock(); return -1; } for(np = hp->h_addr_list; *np != NULL; np++) { aip = (struct addrinfo *)malloc(sizeof(struct addrinfo)); memset(aip, 0, sizeof(struct addrinfo)); if(hints.ai_flags & AI_CANONNAME) aip->ai_canonname = strdup(hp->h_name); else aip->ai_canonname = NULL; aip->ai_socktype = hints.ai_socktype; aip->ai_protocol = hints.ai_protocol; aip->ai_next = NULL; if(prior) prior->ai_next = aip; else *res = aip; prior = aip; #ifdef AF_INET6 if(hints.ai_family == AF_INET6) { aip->ai_family = AF_INET6; ipv6 = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6)); memset(ipv6, 0, sizeof(struct sockaddr_in6)); memcpy(&ipv6->sin6_addr, *np, sizeof(&ipv6->sin6_addr)); ipv6->sin6_family = AF_INET6; ipv6->sin6_port = port; aip->ai_addr = (struct sockaddr *)ipv6; continue; } #endif aip->ai_family = AF_INET; ipv4 = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in)); memset(ipv4, 0, sizeof(struct sockaddr_in)); ipv4->sin_family = AF_INET; ipv4->sin_port = port; memcpy(&ipv4->sin_addr, *np, sizeof(&ipv4->sin_addr)); aip->ai_addr = (struct sockaddr *)ipv4; } hostmutex.unlock(); if(*res) return 0; else return -1; } #endif #if defined(AF_UNIX) && !defined(_MSWINDOWS_) static socklen_t unixaddr(struct sockaddr_un *addr, const char *path) { assert(addr != NULL); assert(path != NULL && *path != 0); socklen_t len; unsigned slen = strlen(path); if(slen > sizeof(addr->sun_path)) slen = sizeof(addr->sun_path); memset(addr, 0, sizeof(*addr)); addr->sun_family = AF_UNIX; memcpy(addr->sun_path, path, slen); #ifdef __SUN_LEN len = sizeof(addr->sun_len) + strlen(addr->sun_path) + sizeof(addr->sun_family) + 1; addr->sun_len = len; #else len = strlen(addr->sun_path) + sizeof(addr->sun_family) + 1; #endif return len; } #endif #ifndef AF_UNSPEC #define AF_UNSPEC 0 #endif static int setfamily(int family, const char *host) { const char *hc = host; if(!host) return family; if(!family || family == AF_UNSPEC) { #ifdef AF_INET6 if(strchr(host, ':')) family = AF_INET6; #endif #ifdef AF_UNIX if(*host == '/') family = AF_UNIX; #endif while((*hc >= '0' && *hc <= '9') || *hc == '.') ++hc; if(!*hc) family = AF_INET; } if(!family || family == AF_UNSPEC) family = query_family; return family; } static void bitmask(bit_t *bits, bit_t *mask, unsigned len) { assert(bits != NULL); assert(mask != NULL); while(len--) *(bits++) &= *(mask++); } static void bitimask(bit_t *bits, bit_t *mask, unsigned len) { assert(bits != NULL); assert(mask != NULL); while(len--) *(bits++) |= ~(*(mask++)); } static void bitset(bit_t *bits, unsigned blen) { assert(bits != NULL); bit_t mask; while(blen) { mask = (bit_t)(1 << 7); while(mask && blen) { *bits |= mask; mask >>= 1; --blen; } ++bits; } } static unsigned bitcount(bit_t *bits, unsigned len) { assert(bits != NULL); unsigned count = 0; bit_t mask, test; while(len--) { mask = (bit_t)(1<<7); test = *bits++; while(mask) { if(!(mask & test)) return count; ++count; mask >>= 1; } } return count; } #ifdef _MSWINDOWS_ static bool _started = false; static void _socketcleanup(void) { if(_started) WSACleanup(); } void Socket::init(void) { static bool initialized = false; unsigned short version; WSADATA status; if(initialized) return; initialized = true; version = MAKEWORD(2,2); status.wVersion = 0; WSAStartup(version, &status); crit(status.wVersion == version, "socket init failure"); atexit(_socketcleanup); _started = true; } #else void Socket::init(void) { } #endif void Socket::init(const char *progname) { assert(progname != NULL); Socket::init(); #ifdef HAVE_SOCKS const char *cp; #ifdef _MSWINDOWS_ char path[65]; cp = strrchr(progname, '/'); if(!cp) cp = strrchr(progname, '\\'); if(!cp) cp = strrchr(progname, ':'); if(cp) progname = ++cp; String::set(path, sizeof(path), progname); const char *ext = strrchr(path, '.'); if(ext && (case_eq(ext, ".exe") || case_eq(ext, ".com"))) *ext = 0; progname = path; #else cp = strrchr(progname, '/'); if(cp) progname = ++cp; #endif SOCKSinit((char *)progname); #endif } void Socket::v4mapping(bool enable) { if(enable) v6only = 0; else v6only = 1; } void Socket::query(int querymode) { query_family = querymode; } cidr::cidr() : LinkedObject() { Family = AF_UNSPEC; memset(&Network, 0, sizeof(Network)); memset(&Netmask, 0, sizeof(Netmask)); Name[0] = 0; } cidr::cidr(const char *cp) : LinkedObject() { assert(cp != NULL && *cp != 0); set(cp); Name[0] = 0; } cidr::cidr(policy **policy, const char *cp) : LinkedObject(policy) { assert(policy != NULL); assert(cp != NULL && *cp != 0); set(cp); Name[0] = 0; } cidr::cidr(policy **policy, const char *cp, const char *id) : LinkedObject(policy) { assert(policy != NULL); assert(cp != NULL && *cp != 0); assert(id != NULL && *id != 0); set(cp); String::set(Name, sizeof(Name), id); } cidr::cidr(const cidr ©) : LinkedObject() { Family = copy.Family; memcpy(&Network, ©.Network, sizeof(Network)); memcpy(&Netmask, ©.Netmask, sizeof(Netmask)); memcpy(&Name, ©.Name, sizeof(Name)); } unsigned cidr::mask(void) const { switch(Family) { case AF_INET: return bitcount((bit_t *)&Netmask.ipv4, sizeof(struct in_addr)); #ifdef AF_INET6 case AF_INET6: return bitcount((bit_t *)&Netmask.ipv6, sizeof(struct in6_addr)); #endif default: return 0; } } const cidr *cidr::find(const policy *policy, const struct sockaddr *s) { assert(policy != NULL); assert(s != NULL); const cidr *member = NULL; unsigned top = 0; linked_pointer p = policy; while(p) { if(p->is_member(s)) { if(p->getMask() > top) { top = p->getMask(); member = *p; } } p.next(); } return member; } const cidr *cidr::container(const policy *policy, const struct sockaddr *s) { assert(policy != NULL); assert(s != NULL); const cidr *member = NULL; unsigned top = 128; linked_pointer p = policy; while(p) { if(p->is_member(s)) { if(p->getMask() < top) { top = p->getMask(); member = *p; } } p.next(); } return member; } bool cidr::is_member(const struct sockaddr *s) const { assert(s != NULL); inethostaddr_t host; struct sockaddr_internet *addr = (struct sockaddr_internet *)s; if(addr->address.sa_family != Family) return false; switch(Family) { case AF_INET: memcpy(&host.ipv4, &addr->ipv4.sin_addr, sizeof(host.ipv4)); bitmask((bit_t *)&host.ipv4, (bit_t *)&Netmask, sizeof(host.ipv4)); if(!memcmp(&host.ipv4, &Network.ipv4, sizeof(host.ipv4))) return true; return false; #ifdef AF_INET6 case AF_INET6: memcpy(&host.ipv6, &addr->ipv6.sin6_addr, sizeof(host.ipv6)); bitmask((bit_t *)&host.ipv6, (bit_t *)&Netmask, sizeof(host.ipv6)); if(!memcmp(&host.ipv6, &Network.ipv6, sizeof(host.ipv6))) return true; return false; #endif default: return false; } } inethostaddr_t cidr::broadcast(void) const { inethostaddr_t bcast; switch(Family) { case AF_INET: memcpy(&bcast.ipv4, &Network.ipv4, sizeof(Network.ipv4)); bitimask((bit_t *)&bcast.ipv4, (bit_t *)&Netmask.ipv4, sizeof(bcast.ipv4)); return bcast; #ifdef AF_INET6 case AF_INET6: memcpy(&bcast.ipv6, &Network.ipv6, sizeof(Network.ipv6)); bitimask((bit_t *)&bcast.ipv6, (bit_t *)&Netmask.ipv6, sizeof(bcast.ipv6)); return bcast; #endif default: memset(&bcast, 0, sizeof(bcast)); return bcast; } } unsigned cidr::mask(const char *cp) const { assert(cp != NULL && *cp != 0); unsigned count = 0, rcount = 0, dcount = 0; const char *sp = strchr(cp, '/'); bool flag = false; const char *gp = cp; unsigned char dots[4]; uint32_t mask; switch(Family) { #ifdef AF_INET6 case AF_INET6: if(sp) return atoi(++sp); if(!strncmp(cp, "ff00:", 5)) return 8; if(!strncmp(cp, "ff80:", 5)) return 10; if(!strncmp(cp, "2002:", 5)) return 16; sp = strrchr(cp, ':'); while(*(++sp) == '0') ++sp; if(*sp) return 128; while(*cp && count < 128) { if(*(cp++) == ':') { count += 16; while(*cp == '0') ++cp; if(*cp == ':') { if(!flag) rcount = count; flag = true; } else flag = false; } } return rcount; #endif case AF_INET: if(sp) { if(!strchr(++sp, '.')) return atoi(sp); mask = inet_addr(sp); return bitcount((bit_t *)&mask, sizeof(mask)); } memset(dots, 0, sizeof(dots)); dots[0] = atoi(cp); while(*gp && dcount < 3) { if(*(gp++) == '.') dots[++dcount] = atoi(gp); } if(dots[3]) return 32; if(dots[2]) return 24; if(dots[1]) return 16; return 8; default: return 0; } } void cidr::set(const char *cp) { assert(cp != NULL && *cp != 0); char cbuf[128]; char *ep; unsigned dots = 0; #ifdef _MSWINDOWS_ DWORD addr4; int slen; struct sockaddr_in6 *paddr; #endif #ifdef AF_INET6 if(strchr(cp, ':')) Family = AF_INET6; else #endif Family = AF_INET; switch(Family) { case AF_INET: memset(&Netmask.ipv4, 0, sizeof(Netmask.ipv4)); bitset((bit_t *)&Netmask.ipv4, mask(cp)); String::set(cbuf, sizeof(cbuf), cp); ep = (char *)strchr(cbuf, '/'); if(ep) *ep = 0; cp = cbuf; while(NULL != (cp = strchr(cp, '.'))) { ++dots; ++cp; } while(dots++ < 3) String::add(cbuf, sizeof(cbuf), ".0"); #ifdef _MSWINDOWS_ addr4 = inet_addr(cp); memcpy(&Network.ipv4, &addr4, sizeof(Network.ipv4)); #else inet_aton(cbuf, &Network.ipv4); #endif bitmask((bit_t *)&Network.ipv4, (bit_t *)&Netmask.ipv4, sizeof(Network.ipv4)); break; #ifdef AF_INET6 case AF_INET6: memset(&Netmask.ipv6, 0, sizeof(Netmask)); bitset((bit_t *)&Netmask.ipv6, mask(cp)); String::set(cbuf, sizeof(cbuf), cp); ep = (char *)strchr(cp, '/'); if(ep) *ep = 0; #ifdef _MSWINDOWS_ struct sockaddr saddr; slen = sizeof(saddr); paddr = (struct sockaddr_in6 *)&saddr; WSAStringToAddress((LPSTR)cbuf, AF_INET6, NULL, &saddr, &slen); Network.ipv6 = paddr->sin6_addr; #else inet_pton(AF_INET6, cbuf, &Network.ipv6); #endif bitmask((bit_t *)&Network.ipv6, (bit_t *)&Netmask.ipv6, sizeof(Network.ipv6)); #endif default: break; } } Socket::address::address(int family, const char *a, int type, int protocol) { assert(a != NULL && *a != 0); list = NULL; #ifdef _MSWINDOWS_ Socket::init(); #endif set(family, a, type, protocol); } Socket::address::address(const char *host, in_port_t port) { assert(host != NULL && *host != 0); list = NULL; #ifdef _MSWINDOWS_ Socket::init(); #endif set(host, port); } Socket::address::address(int family, const char *host, const char *svc) { assert(host != NULL && *host != 0); assert(svc != NULL && *svc != 0); struct addrinfo hint; #ifdef _MSWINDOWS_ Socket::init(); #endif list = NULL; memset(&hint, 0, sizeof(hint)); hint.ai_family = family; getaddrinfo(host, svc, &hint, &list); } Socket::address::address(const in_addr& address, in_port_t port) : list(NULL) { sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr = address; addr.sin_port = htons(port); insert((sockaddr&)addr); } Socket::address::address(const in6_addr& address, in_port_t port) : list(NULL) { sockaddr_in6 addr; addr.sin6_family = AF_INET6; addr.sin6_addr = address; addr.sin6_port = htons(port); insert((sockaddr&)addr); } Socket::address::address() { list = NULL; } Socket::address::address(const address& from) { list = NULL; copy(from.list); } Socket::address& Socket::address::operator=(const address& rhs) { if (*this != rhs) { list = NULL; copy(rhs.list); } return *this; } Socket::address::address(const char *host, const char *service, int type) { list = NULL; set(host, service, type); } Socket::address::~address() { clear(); } void Socket::address::clear(void) { if(list) { freeaddrinfo(list); list = NULL; } } void Socket::release(struct addrinfo *list) { if(list) freeaddrinfo(list); } struct ::addrinfo *Socket::query(const char *hp, const char *svc, int type, int protocol) { assert(hp != NULL && *hp != 0); int family = DEFAULT_FAMILY; char hostbuf[256]; struct addrinfo hint; String::set(hostbuf, sizeof(hostbuf), hp); char *cp = strchr(hostbuf, '/'); char *host = hostbuf; memset(&hint, 0, sizeof(hint)); hint.ai_socktype = type; hint.ai_protocol = protocol; #ifdef PF_UNSPEC hint.ai_family = PF_UNSPEC; hint.ai_flags = AI_PASSIVE; #endif if(cp) *cp = 0; if(*host == '[') { cp = strchr(++host, ']'); if(cp) { *(cp++) = 0; if(*cp == ':') svc = ++cp; } #ifdef AF_INET6 family = AF_INET6; #else return NULL; #endif } else if(((cp = strrchr(host, ':')) != NULL) && (strchr(host, ':') == cp)) { *(cp++) = 0; svc = cp; } if(is_numeric(host)) { hint.ai_flags |= AI_NUMERICHOST; if(strchr(host, ':')) { #ifdef AF_INET6 family = AF_INET6; #else return NULL; #endif } else family = AF_INET; } if(family && family != AF_UNSPEC) hint.ai_family = family; #if defined(AF_INET6) && defined(AI_V4MAPPED) if(hint.ai_family == AF_INET6 && !v6only) hint.ai_flags |= AI_V4MAPPED; #endif #ifdef AI_NUMERICSERV if(svc && atoi(svc) > 0) hint.ai_flags |= AI_NUMERICSERV; #endif struct addrinfo *result = NULL; getaddrinfo(host, svc, &hint, &result); return result; } bool Socket::address::operator==(const address& other) const { struct addrinfo *node = list; struct addrinfo *node_o = other.list; while(node && node_o) { if(!equal(node->ai_addr, node_o->ai_addr)) return false; node = node->ai_next; node_o = node_o->ai_next; } if(node || node_o) return false; return true; } void Socket::address::set(const char *host, in_port_t port) { assert(host != NULL && *host != 0); char buf[16]; clear(); if(port) { snprintf(buf, sizeof(buf), "%u", port); list = Socket::query(host, buf); } else list = Socket::query(host, NULL); } void Socket::address::set(int family, const char *a, int type, int protocol) { assert(a != NULL && *a != 0); char *addr = strdup(a); char *host = strchr(addr, '@'); char *ep; char *svc = NULL; struct addrinfo hint; clear(); memset(&hint, 0, sizeof(hint)); #ifdef PF_UNSPEC hint.ai_family = PF_UNSPEC; hint.ai_socktype = SOCK_STREAM; hint.ai_flags = AI_PASSIVE; #endif if(!host) host = addr; else ++host; if(*host != '[') { ep = strchr(host, ':'); if(ep) { *(ep++) = 0; svc = ep; } goto proc; } #ifdef AF_INET6 if(*host == '[') { family = AF_INET6; ++host; ep = strchr(host, ']'); if(ep) { *(ep++) = 0; if(*ep == ':') svc = ++ep; } } #endif proc: hint.ai_family = family; hint.ai_socktype = type; hint.ai_protocol = protocol; #if defined(AF_INET6) && defined(AI_V4MAPPED) if(hint.ai_family == AF_INET6 && !v6only) hint.ai_flags |= AI_V4MAPPED; #endif getaddrinfo(host, svc, &hint, &list); strfree(addr); } struct sockaddr *Socket::address::get(void) const { if(!list) return NULL; return list->ai_addr; } int Socket::address::family(void) const { struct sockaddr *ap; if(!list) return 0; ap = list->ai_addr; if(!ap) return 0; return ap->sa_family; } void Socket::address::setPort(in_port_t port) { struct sockaddr *ap; struct addrinfo *lp; lp = list; while(lp) { ap = lp->ai_addr; setPort(ap, port); lp = lp->ai_next; } } Socket::address Socket::address::withPort(in_port_t port) const { Socket::address copy = *this; copy.setPort(port); return copy; } struct sockaddr *Socket::address::get(int family) const { struct sockaddr *ap; struct addrinfo *lp; lp = list; while(lp) { ap = lp->ai_addr; if(ap && ap->sa_family == family) return ap; lp = lp->ai_next; } return NULL; } void Socket::address::set(struct sockaddr *addr) { clear(); add(addr); } bool Socket::address::remove(const struct sockaddr *addr) { assert(addr != NULL); struct addrinfo *node = list, *prior = NULL; while(node) { if(node->ai_addr && equal(addr, node->ai_addr)) break; prior = node; node = node->ai_next; } if(!node) return false; if(!prior) list = node->ai_next; else prior->ai_next = node->ai_next; node->ai_next = NULL; freeaddrinfo(node); return true; } unsigned Socket::address::insert(const struct addrinfo *alist) { unsigned count = 0; while(alist) { if(insert(alist->ai_addr)) ++count; alist = alist->ai_next; } return count; } unsigned Socket::address::remove(const struct addrinfo *alist) { unsigned count = 0; while(alist) { if(remove(alist->ai_addr)) ++count; alist = alist->ai_next; } return count; } bool Socket::address::insert(const struct sockaddr *addr) { assert(addr != NULL); struct addrinfo *node = list; while(node && node->ai_addr) { if(node->ai_addr && equal(addr, node->ai_addr)) return false; node = node->ai_next; } node = (struct addrinfo *)malloc(sizeof(struct addrinfo)); if (!node) return false; memset(node, 0, sizeof(struct addrinfo)); node->ai_family = addr->sa_family; node->ai_addrlen = len(addr); node->ai_next = list; node->ai_addr = (struct sockaddr *)malloc(node->ai_addrlen); if (node->ai_addr) memcpy(node->ai_addr, addr, node->ai_addrlen); list = node; return true; } void Socket::address::copy(const struct addrinfo *addr) { struct addrinfo *last = NULL; struct addrinfo *node; clear(); while(addr) { node = (struct addrinfo *)malloc(sizeof(struct addrinfo)); if (!node) break; memcpy(node, addr, sizeof(struct addrinfo)); node->ai_next = NULL; node->ai_addr = dup(addr->ai_addr); if(last) last->ai_next = node; else list = node; last = node; addr = addr->ai_next; } } in_port_t Socket::address::getPort(const struct sockaddr *address) { if (address == NULL) return 0; switch (address->sa_family) { case AF_INET: return ntohs(reinterpret_cast(address)->sin_port); case AF_INET6: return ntohs(reinterpret_cast(address)->sin6_port); default: return 0; } } void Socket::address::setPort(struct sockaddr *address, in_port_t port) { if (address == NULL) return; switch (address->sa_family) { case AF_INET: reinterpret_cast(address)->sin_port = htons(port); break; case AF_INET6: reinterpret_cast(address)->sin6_port = htons(port); break; } } bool Socket::address::isAny(const struct sockaddr *address) { if (address == NULL) return false; switch (address->sa_family) { case AF_INET: return reinterpret_cast(address)->sin_addr.s_addr == INADDR_ANY; case AF_INET6: return memcmp( &reinterpret_cast(address)->sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0; default: return false; } } bool Socket::address::isLoopback(const struct sockaddr *address) { if (address == NULL) return false; switch (address->sa_family) { case AF_INET: return reinterpret_cast(address)->sin_addr.s_addr == htonl(INADDR_LOOPBACK); case AF_INET6: return memcmp( &reinterpret_cast(address)->sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback)) == 0; default: return false; } } void Socket::address::setAny(int sa_family) { if(sa_family == AF_UNSPEC) sa_family = family(); clear(); const sockaddr_storage sa = Socket::address::any(sa_family); insert(reinterpret_cast(&sa)); } void Socket::address::setLoopback(int sa_family) { if(sa_family == AF_UNSPEC) sa_family = family(); clear(); const sockaddr_storage sa = Socket::address::loopback(sa_family); insert(reinterpret_cast(&sa)); } void Socket::address::setAny(struct sockaddr *sa) { int family = sa->sa_family; memset(sa, 0, Socket::len(sa)); sa->sa_family = family; } void Socket::address::setLoopback(struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET: reinterpret_cast(sa)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); break; case AF_INET6: memcpy( &reinterpret_cast(sa)->sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback)); break; } } sockaddr_storage Socket::address::any(int family) { sockaddr_storage sa; memset(&sa, 0, sizeof(sockaddr_storage)); sa.ss_family = family; return sa; } sockaddr_storage Socket::address::loopback(int family) { sockaddr_storage sa = any(family); setLoopback((struct sockaddr*)&sa); return sa; } struct sockaddr_in *Socket::address::ipv4(struct sockaddr *addr) { if(addr == NULL || addr->sa_family != AF_INET) return NULL; return (struct sockaddr_in*)addr; } #ifdef AF_INET6 struct sockaddr_in6 *Socket::address::ipv6(struct sockaddr *addr) { if(addr == NULL || addr->sa_family != AF_INET6) return NULL; return (struct sockaddr_in6*)addr; } #endif struct sockaddr *Socket::address::dup(struct sockaddr *addr) { struct sockaddr *node; if(!addr) return NULL; size_t slen = len(addr); if(!slen) return NULL; node = (struct sockaddr *)malloc(slen); if (node) memcpy(node, addr, slen); return node; } void Socket::address::add(struct sockaddr *addr) { assert(addr != NULL); char buffer[80]; char svc[8]; Socket::query(addr, buffer, sizeof(buffer)); snprintf(svc, sizeof(svc), "%d", Socket::service(addr)); add(buffer, svc, addr->sa_family); } void Socket::address::set(const char *host, const char *svc, int socktype) { clear(); add(host, svc, socktype); } void Socket::address::add(const char *host, const char *svc, int socktype) { assert(host != NULL && *host != 0); assert(svc != NULL && *svc != 0); struct addrinfo *join = NULL, *last = NULL; join = Socket::query(host, svc, socktype); if(!join) return; if(!list) { list = join; return; } last = list; while(last->ai_next) last = last->ai_next; last->ai_next = join; } struct sockaddr *Socket::address::find(const struct sockaddr *addr) const { assert(addr != NULL); struct addrinfo *node = list; while(node) { if(equal(addr, node->ai_addr)) return node->ai_addr; node = node->ai_next; } return NULL; } size_t Socket::address::print(const sockaddr* addr, char *dst, size_t dst_sz, bool port, bool ipv6_brackets) { if(!addr || !dst || !dst_sz) return 0; memset(dst, 0, dst_sz); const char* ret = dst; const int af = addr->sa_family; const char *res = NULL; #if defined(AF_INET6) ipv6_brackets = (af == AF_INET6) ? ipv6_brackets || port : false; if(ipv6_brackets) { *dst++ = '['; dst_sz--; } #endif switch (af) { #ifdef _MSWINDOWS_ case AF_INET: struct sockaddr_in in; memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; memcpy(&in.sin_addr, &reinterpret_cast(addr)->sin_addr, sizeof(struct in_addr)); if(!getnameinfo((struct sockaddr *)&in, (socklen_t)sizeof(struct sockaddr_in), dst, (socksize_t)dst_sz, NULL, 0, NI_NUMERICHOST)) { res = dst; } break; #ifdef AF_INET6 case AF_INET6: struct sockaddr_in6 in6; memset(&in6, 0, sizeof(in6)); in6.sin6_family = AF_INET6; memcpy(&in6.sin6_addr, &reinterpret_cast(addr)->sin6_addr, sizeof(struct in_addr6)); if(!getnameinfo((struct sockaddr *)&in6, (socklen_t)sizeof(struct sockaddr_in6), dst, (socksize_t)dst_sz, NULL, 0, NI_NUMERICHOST)) { res = dst; } break; #endif #elif defined(HAVE_INET_NTOP) case AF_INET: res = ::inet_ntop(AF_INET, &reinterpret_cast(addr)->sin_addr, dst, dst_sz); break; #ifdef AF_INET6 case AF_INET6: res = ::inet_ntop(AF_INET6, &reinterpret_cast(addr)->sin6_addr, dst, dst_sz); break; #endif #else case AF_INET: ENTER_EXCLUSIVE String::set(dst, dst_sz, inet_ntoa(((const struct sockaddr_in *)(addr))->sin_addr)); LEAVE_EXCLUSIVE break; #endif default: res = NULL; } if(!res) return 0; size_t addr_len = strlen(res); dst = dst + addr_len; dst_sz -= addr_len; #if defined(AF_INET6) if(ipv6_brackets && dst_sz) { *dst++ = ']'; dst_sz--; } #endif if(port && dst_sz) { *dst++ = ':'; dst_sz--; snprintf(dst, dst_sz, "%u", getPort(addr)); } return strlen(ret); } Socket::Socket(const Socket &s) { #ifdef _MSWINDOWS_ HANDLE pidH = GetCurrentProcess(); HANDLE dupH; init(); if(DuplicateHandle(pidH, reinterpret_cast(s.so), pidH, &dupH, 0, FALSE, DUPLICATE_SAME_ACCESS)) so = reinterpret_cast(dupH); else so = INVALID_SOCKET; #else so = ::dup(s.so); #endif iowait = s.iowait; ioerr = 0; } Socket::Socket() { so = INVALID_SOCKET; iowait = Timer::inf; ioerr = 0; } Socket::Socket(const socket_t s) { so = s; iowait = Timer::inf; ioerr = 0; } Socket::Socket(const struct addrinfo *addr) { #ifdef _MSWINDOWS_ init(); #endif assert(addr != NULL); while(addr) { so = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); socket_mapping(addr->ai_family, so); if(so != INVALID_SOCKET) { if(!_connect_(so, addr->ai_addr, (socklen_t)addr->ai_addrlen)) return; } addr = addr->ai_next; } so = INVALID_SOCKET; iowait = Timer::inf; ioerr = 0; } Socket::Socket(int family, int type, int protocol) { so = create(family, type, protocol); iowait = Timer::inf; ioerr = 0; } Socket::Socket(const char *iface, const char *port, int family, int type, int protocol) { assert(iface != NULL && *iface != 0); assert(port != NULL && *port != 0); #ifdef _MSWINDOWS_ init(); #endif family = setfamily(family, iface); so = create(iface, port, family, type, protocol); iowait = Timer::inf; ioerr = 0; } socket_t Socket::create(const Socket::address &address) { socket_t so; struct addrinfo *res = *address; if(!res) return INVALID_SOCKET; so = create(res->ai_family, res->ai_socktype, res->ai_protocol); if(so == INVALID_SOCKET) return INVALID_SOCKET; if(connectto(so, res)) { release(so); return INVALID_SOCKET; } return so; } socket_t Socket::create(const char *iface, const char *port, int family, int type, int protocol) { assert(iface != NULL && *iface != 0); assert(port != NULL && *port != 0); struct addrinfo hint, *res; socket_t so; int reuse = 1; #ifdef _MSWINDOWS_ Socket::init(); #endif memset(&hint, 0, sizeof(hint)); hint.ai_flags = AI_PASSIVE | AI_NUMERICHOST; hint.ai_family = setfamily(family, iface); hint.ai_socktype = type; hint.ai_protocol = protocol; #if defined(AF_INET6) && defined(AI_V4MAPPED) if(hint.ai_family == AF_INET6 && !v6only) hint.ai_flags |= AI_V4MAPPED; #endif #if defined(AF_UNIX) && !defined(_MSWINDOWS_) if(iface && strchr(iface, '/')) { struct sockaddr_storage uaddr; socklen_t len = unixaddr((struct sockaddr_un *)&uaddr, iface); if(!type) type = SOCK_STREAM; so = create(AF_UNIX, type, 0); if(so == INVALID_SOCKET) return INVALID_SOCKET; if(_bind_(so, (struct sockaddr *)&uaddr, len)) { release(so); return INVALID_SOCKET; } return so; }; #endif if(iface && !strcmp(iface, "*")) iface = NULL; getaddrinfo(iface, port, &hint, &res); if(res == NULL) return INVALID_SOCKET; so = create(res->ai_family, res->ai_socktype, res->ai_protocol); if(so == INVALID_SOCKET) { freeaddrinfo(res); return INVALID_SOCKET; } setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (caddr_t)&reuse, sizeof(reuse)); if(res->ai_addr) { if(_bind_(so, res->ai_addr, (socklen_t)res->ai_addrlen)) { release(so); so = INVALID_SOCKET; } } freeaddrinfo(res); return so; } Socket::~Socket() { release(); } socket_t Socket::create(int family, int type, int protocol) { socket_t so; #ifdef _MSWINDOWS_ init(); #endif so = ::socket(family, type, protocol); socket_mapping(family, so); return so; } void Socket::cancel(void) { if(so != INVALID_SOCKET) ::shutdown(so, SHUT_RDWR); } void Socket::cancel(socket_t so) { if(so != INVALID_SOCKET) ::shutdown(so, SHUT_RDWR); } void Socket::release(socket_t so) { #ifdef _MSWINDOWS_ ::closesocket(so); #else if(!::shutdown(so, SHUT_RDWR)) ::close(so); #endif } void Socket::release(void) { if(so != INVALID_SOCKET) { #ifdef _MSWINDOWS_ ::closesocket(so); #else ::shutdown(so, SHUT_RDWR); ::close(so); #endif so = INVALID_SOCKET; } iowait = Timer::inf; ioerr = 0; } #ifdef _MSWINDOWS_ int Socket::error(void) { switch(WSAGetLastError()) { case WSANOTINITIALISED: case WSAENETDOWN: case WSASYSNOTREADY: return ENETDOWN; case WSAEFAULT: return EFAULT; case WSAEINTR: case WSAECANCELLED: case WSA_OPERATION_ABORTED: case WSA_IO_INCOMPLETE: case WSASYSCALLFAILURE: case WSA_E_CANCELLED: return EINTR; case WSA_IO_PENDING: case WSAEINPROGRESS: return EINPROGRESS; case WSAEINVAL: return EINVAL; case WSAEMFILE: return EMFILE; case WSAENETUNREACH: return ENETUNREACH; case WSAENOBUFS: case WSAETOOMANYREFS: case WSA_NOT_ENOUGH_MEMORY: return ENOMEM; case WSAEACCES: return EACCES; case WSAEBADF: case WSAENOTSOCK: case WSA_INVALID_HANDLE: return EBADF; case WSAEOPNOTSUPP: return ENOSYS; case WSAEWOULDBLOCK: case WSAEALREADY: return EAGAIN; case WSAENOPROTOOPT: return ENOPROTOOPT; case WSAEADDRINUSE: return EADDRINUSE; case WSAENETRESET: return ENETRESET; case WSAECONNABORTED: return ECONNABORTED; case WSAECONNRESET: return ECONNRESET; case WSAEISCONN: return EISCONN; case WSAENOTCONN: return ENOTCONN; case WSAESHUTDOWN: return ESHUTDOWN; case WSAETIMEDOUT: return ETIMEDOUT; case WSAECONNREFUSED: return ECONNREFUSED; case WSAEHOSTDOWN: return EHOSTDOWN; case WSAEHOSTUNREACH: return EHOSTUNREACH; } return EINVAL; } #else int Socket::error(void) { return errno; } #endif Socket::operator bool() { if(so == INVALID_SOCKET) return false; return true; } bool Socket::operator!() const { if(so == INVALID_SOCKET) return true; return false; } Socket &Socket::operator=(socket_t s) { release(); so = s; return *this; } size_t Socket::peek(void *data, size_t len) const { assert(data != NULL); assert(len > 0); if(iowait && iowait != Timer::inf && !Socket::wait(so, iowait)) return 0; ssize_t rtn = _recv_(so, (caddr_t)data, 1, MSG_DONTWAIT | MSG_PEEK); if(rtn < 1) return 0; return (size_t)rtn; } ssize_t Socket::recvinet(socket_t so, void *data, size_t len, int flags, struct sockaddr_internet *addr) { assert(data != NULL); assert(len > 0); socklen_t slen = sizeof(struct sockaddr_internet); return _recvfrom_(so, (caddr_t)data, (socksize_t)len, flags, (struct sockaddr *)addr, &slen); } ssize_t Socket::recvfrom(socket_t so, void *data, size_t len, int flags, struct sockaddr_storage *addr) { assert(data != NULL); assert(len > 0); socklen_t slen = sizeof(struct sockaddr_storage); return _recvfrom_(so, (caddr_t)data, (socksize_t)len, flags, (struct sockaddr *)addr, (socklen_t *)&slen); } size_t Socket::readfrom(void *data, size_t len, struct sockaddr_storage *from) { assert(data != NULL); assert(len > 0); // wait for input by timer if possible... if(iowait && iowait != Timer::inf && !Socket::wait(so, iowait)) return 0; socklen_t slen = sizeof(struct sockaddr_storage); ssize_t result = _recvfrom_(so, (caddr_t)data, (socksize_t)len, 0, (struct sockaddr *)from, (socklen_t *)&slen); if(result < 0) { ioerr = Socket::error(); return 0; } return (size_t)result; } size_t Socket::writeto(const void *data, size_t dlen, const struct sockaddr *dest) { assert(data != NULL); assert(len > 0); socklen_t slen = 0; if(dest) slen = len(dest); ssize_t result = _sendto_(so, (caddr_t)data, (socksize_t)dlen, MSG_NOSIGNAL, dest, (socklen_t)slen); if(result < 0) { ioerr = Socket::error(); return 0; } return (size_t)result; } ssize_t Socket::sendto(socket_t so, const void *data, size_t dlen, int flags, const struct sockaddr *dest) { assert(data != NULL); assert(len > 0); socklen_t slen = 0; if(dest) slen = len(dest); return _sendto_(so, (caddr_t)data, (socksize_t)dlen, MSG_NOSIGNAL | flags, dest, (socklen_t)slen); } size_t Socket::writes(const char *str) { if(!str) return 0; if(!*str) return 0; return writeto(str, strlen(str), NULL); } size_t Socket::readline(char *data, size_t max) { assert(data != NULL); assert(max > 0); *data = 0; ssize_t result = Socket::readline(so, data, max, iowait); if(result < 0) { ioerr = Socket::error(); return 0; } return (size_t)result; } size_t Socket::readline(String& s) { if(!s.c_mem()) return 0; ssize_t result = Socket::readline(so, s.c_mem(), s.size() + 1, iowait); if(result < 0) { ioerr = Socket::error(); s.clear(); return 0; } String::fix(s); return (size_t)result; } ssize_t Socket::readline(socket_t so, char *data, size_t max, timeout_t timeout) { assert(data != NULL); assert(max > 0); bool crlf = false; bool nl = false; size_t nleft = max - 1; // leave space for null byte int nstat, c; if(max < 1) return -1; data[0] = 0; while(nleft && !nl) { if(timeout) { if(!wait(so, timeout)) return 0; } nstat = _recv_(so, data, (socksize_t)nleft, MSG_PEEK); if(nstat < 0) return -1; if(nstat == 0) return (ssize_t)(max - nleft - 1); for(c = 0; c < nstat; ++c) { if(data[c] == '\n') { if(c > 0 && data[c - 1] == '\r') crlf = true; ++c; nl = true; break; } } nstat = _recv_(so, (caddr_t)data, c, 0); if(nstat < 0) break; if(crlf) { --nstat; data[nstat - 1] = '\n'; } data += nstat; nleft -= nstat; } if(nl) --data; *data = 0; return ssize_t(max - nleft - 1); } int Socket::loopback(socket_t so, bool enable) { union { struct sockaddr_storage saddr; struct sockaddr_in inaddr; } us; struct sockaddr *addr = (struct sockaddr *)&us.saddr; int family; socklen_t len = sizeof(us.saddr); int opt = 0; if(enable) opt = 1; if(so == INVALID_SOCKET) return EBADF; _getsockname_(so, addr, &len); family = us.inaddr.sin_family; switch(family) { case AF_INET: if(!setsockopt(so, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&opt, sizeof(opt))) return 0; break; #if defined(AF_INET6) && defined(IPROTO_IPV6) case AF_INET6: if(!setsockopt(so, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *)&opt, sizeof(opt))) return 0; #endif } int err = Socket::error(); if(!err) err = EIO; return err; } int Socket::ttl(socket_t so, unsigned char t) { union { struct sockaddr_storage saddr; struct sockaddr_in inaddr; } us; struct sockaddr *addr = (struct sockaddr *)&us.saddr; int family; socklen_t len = sizeof(us.saddr); if(so == INVALID_SOCKET) return EBADF; _getsockname_(so, addr, &len); family = us.inaddr.sin_family; switch(family) { case AF_INET: if(!setsockopt(so, IPPROTO_IP, IP_TTL, (char *)&t, sizeof(t))) return 0; break; #if defined(AF_INET6) && defined(IPPROTO_IPV6) case AF_INET6: if(!setsockopt(so, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *)&t, sizeof(t))) return 0; #endif } int err = Socket::error(); if(!err) err = EIO; return err; } int Socket::priority(socket_t so, int pri) { if(so == INVALID_SOCKET) return EBADF; #ifdef SO_PRIORITY if(!setsockopt(so, SOL_SOCKET, SO_PRIORITY, (char *)&pri, (socklen_t)sizeof(pri))) return 0; int err = Socket::error(); if(!err) err = EIO; return err; #else return ENOSYS; #endif } int Socket::tos(socket_t so, int ts) { if(so == INVALID_SOCKET) return EBADF; #ifdef SOL_IP if(!setsockopt(so, SOL_IP, IP_TOS,(char *)&ts, (socklen_t)sizeof(ts))) return 0; int err = Socket::error(); if(!err) err = EIO; return err; #else return ENOSYS; #endif } int Socket::broadcast(socket_t so, bool enable) { if(so == INVALID_SOCKET) return EBADF; int opt = (enable ? 1 : 0); if(!::setsockopt(so, SOL_SOCKET, SO_BROADCAST, (char *)&opt, (socklen_t)sizeof(opt))) return 0; int err = Socket::error(); if(!err) err = EIO; return err; } int Socket::nodelay(socket_t so) { if(so == INVALID_SOCKET) return EBADF; #if defined(TCP_NODELAY) int opt = 1; if(!::setsockopt(so, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, (socklen_t)sizeof(opt))) return 0; #else return ENOSYS; #endif int err = Socket::error(); if(!err) err = EIO; return err; } int Socket::keepalive(socket_t so, bool enable) { if(so == INVALID_SOCKET) return EBADF; #if defined(SO_KEEPALIVE) || defined(_MSWINDOWS_) int opt = (enable ? ~0 : 0); if(!::setsockopt(so, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, (socklen_t)sizeof(opt))) return 0; int err = Socket::error(); if(!err) err = EIO; return err; #else return ENOSYS; #endif } int Socket::multicast(socket_t so, unsigned ttl) { struct sockaddr_internet addr; socklen_t len = sizeof(addr); bool enable; int rtn; if(so == INVALID_SOCKET) return EBADF; if(ttl) enable = true; else enable = false; _getsockname_(so, (struct sockaddr *)&addr, &len); if(!enable) switch(addr.address.sa_family) { case AF_INET: memset(&addr.ipv4.sin_addr, 0, sizeof(addr.ipv4.sin_addr)); break; #ifdef AF_INET6 case AF_INET6: memset(&addr.ipv6.sin6_addr, 0, sizeof(addr.ipv6.sin6_addr)); break; #endif default: break; } switch(addr.address.sa_family) { #if defined(AF_INET6) && defined(IPPROTO_IPV6) case AF_INET6: rtn = ::setsockopt(so, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&addr.ipv6.sin6_addr, sizeof(addr.ipv6.sin6_addr)); if(!rtn) rtn = ::setsockopt(so, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ttl, sizeof(ttl)); if(rtn) { rtn = Socket::error(); if(!rtn) rtn = EIO; } return rtn; #endif case AF_INET: #ifdef IP_MULTICAST_IF rtn = ::setsockopt(so, IPPROTO_IP, IP_MULTICAST_IF, (char *)&addr.ipv4.sin_addr, sizeof(addr.ipv4.sin_addr)); if(!rtn) rtn = ::setsockopt(so, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl)); if(rtn) { rtn = Socket::error(); if(!rtn) rtn = EIO; } return rtn; #else return ENOSYS; #endif default: return ENOSYS; } } int Socket::join(const struct addrinfo *addr, const int ifindex) { int rtn = Socket::join(so, addr, ifindex); if(rtn) ioerr = rtn; return rtn; } int Socket::drop(const struct addrinfo *addr, const int ifindex) { int rtn = Socket::drop(so, addr, ifindex); if(rtn) ioerr = rtn; return rtn; } int Socket::wait(timeout_t timeout) { bool mode = true; if(timeout < Timer::inf) mode = false; int rtn = Socket::blocking(so, mode); if(!rtn) iowait = timeout; else ioerr = rtn; return rtn; } int Socket::blocking(socket_t so, bool enable) { if(so == INVALID_SOCKET) return EBADF; #if defined(_MSWINDOWS_) unsigned long flag = (enable ? 0 : 1); if(!ioctlsocket(so, FIONBIO, &flag)) return 0; #else long flags = fcntl(so, F_GETFL); if(enable) flags &=~ O_NONBLOCK; else flags |= O_NONBLOCK; if(!fcntl(so, F_SETFL, flags)) return 0; #endif int err = Socket::error(); if(!err) err = EIO; return err; } int Socket::disconnect(socket_t so) { union { struct sockaddr_storage saddr; struct sockaddr_in inaddr; } us; struct sockaddr *addr = (struct sockaddr *)&us.saddr; socklen_t len = sizeof(us.saddr); #if defined(_MSWINDOWS_) _getsockname_(so, addr, &len); int family = us.inaddr.sin_family; memset(addr, 0, sizeof(us.saddr)); us.inaddr.sin_family = family; #else memset(addr, 0, sizeof(us.saddr)); us.inaddr.sin_family = AF_UNSPEC; #endif if((size_t)len > sizeof(us.saddr)) len = sizeof(us.saddr); if(so == INVALID_SOCKET) return EBADF; if(!_connect_(so, addr, len)) return 0; int err = Socket::error(); if(!err) err = EIO; return err; } int Socket::join(socket_t so, const struct addrinfo *node, const int ifindex) { assert(node != NULL); struct multicast_internet mcast; struct sockaddr_internet addr; socklen_t len = sizeof(addr); const struct sockaddr_internet *target; int family; int rtn = 0; if(so == INVALID_SOCKET) return EBADF; _getsockname_(so, (struct sockaddr *)&addr, &len); while(!rtn && node && node->ai_addr) { target = (const struct sockaddr_internet *)node->ai_addr; family = node->ai_family; node = node->ai_next; if(family != addr.address.sa_family) continue; switch(addr.address.sa_family) { #if defined(AF_INET6) && defined(IPV6_ADD_MEMBERSHIP) && defined(IPPROTO_IPV6) case AF_INET6: mcast.ipv6.ipv6mr_interface = ifindex; memcpy(&mcast.ipv6.ipv6mr_multiaddr, &target->ipv6.sin6_addr, sizeof(target->ipv6.sin6_addr)); rtn = ::setsockopt(so, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcast, sizeof(mcast.ipv6)); break; #endif #if defined(IP_ADD_MEMBERSHIP) case AF_INET: mcast.ipv4.imr_interface.s_addr = INADDR_ANY; memcpy(&mcast.ipv4.imr_multiaddr, &target->ipv4.sin_addr, sizeof(target->ipv4.sin_addr)); rtn = ::setsockopt(so, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mcast, sizeof(mcast.ipv4)); break; #endif default: return ENOSYS; } } if(rtn) { rtn = Socket::error(); if(!rtn) rtn = EIO; } return rtn; } int Socket::drop(socket_t so, const struct addrinfo *node, const int ifindex) { assert(node != NULL); struct multicast_internet mcast; struct sockaddr_internet addr; socklen_t len = sizeof(addr); const struct sockaddr_internet *target; int family; int rtn = 0; if(so == INVALID_SOCKET) return EBADF; _getsockname_(so, (struct sockaddr *)&addr, &len); while(!rtn && node && node->ai_addr) { target = (const struct sockaddr_internet *)node->ai_addr; family = node->ai_family; node = node->ai_next; if(family != addr.address.sa_family) continue; switch(addr.address.sa_family) { #if defined(AF_INET6) && defined(IPV6_DROP_MEMBERSHIP) && defined(IPPROTO_IPV6) case AF_INET6: mcast.ipv6.ipv6mr_interface = ifindex; memcpy(&mcast.ipv6.ipv6mr_multiaddr, &target->ipv6.sin6_addr, sizeof(target->ipv6.sin6_addr)); rtn = ::setsockopt(so, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (char *)&mcast, sizeof(mcast.ipv6)); break; #endif #if defined(IP_DROP_MEMBERSHIP) case AF_INET: mcast.ipv4.imr_interface.s_addr = INADDR_ANY; memcpy(&mcast.ipv4.imr_multiaddr, &target->ipv4.sin_addr, sizeof(target->ipv4.sin_addr)); rtn = ::setsockopt(so, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mcast, sizeof(mcast.ipv4)); break; #endif default: return ENOSYS; } } if(rtn) { rtn = Socket::error(); if(!rtn) rtn = EIO; } return rtn; } socket_t Socket::create(const struct addrinfo *node, int stype, int sprotocol) { assert(node != NULL); socket_t so = INVALID_SOCKET; int sfamily = AF_UNSPEC; int cprotocol, ctype; while(node) { if(stype && node->ai_socktype && node->ai_socktype != stype) goto next; if(sprotocol && node->ai_protocol && node->ai_protocol != sprotocol) goto next; if(node->ai_family != sfamily) { if(so != INVALID_SOCKET) Socket::release(so); sfamily = node->ai_family; if(stype) ctype = stype; else ctype = node->ai_socktype; if(sprotocol) cprotocol = sprotocol; else cprotocol = node->ai_protocol; so = Socket::create(sfamily, ctype, cprotocol); } if(so != INVALID_SOCKET) { if(!_connect_(so, node->ai_addr, (socklen_t)node->ai_addrlen)) return so; } next: node = node->ai_next; } if(so != INVALID_SOCKET) Socket::release(so); return INVALID_SOCKET; } int Socket::connectto(struct addrinfo *node) { return (ioerr = connectto(so, node)); } int Socket::disconnect(void) { return (ioerr = disconnect(so)); } int Socket::connectto(socket_t so, struct addrinfo *node) { assert(node != NULL); int rtn = -1; int socket_family; if(so == INVALID_SOCKET) return EBADF; socket_family = family(so); while(node) { if(node->ai_family == socket_family) { if(!_connect_(so, node->ai_addr, (socklen_t)node->ai_addrlen)) { rtn = 0; goto exit; } } node = node->ai_next; } exit: #ifndef _MSWINDOWS_ if(!rtn || errno == EINPROGRESS) return 0; #endif if(rtn) { rtn = Socket::error(); if(!rtn) rtn = EIO; } return rtn; } int Socket::error(socket_t so) { assert(so != INVALID_SOCKET); int opt; socklen_t slen = sizeof(opt); if(getsockopt(so, SOL_SOCKET, SO_ERROR, (caddr_t)&opt, &slen)) return ENOSYS; return opt; } int Socket::sendwait(socket_t so, unsigned size) { assert(so != INVALID_SOCKET); #ifdef SO_SNDLOWAT if(!setsockopt(so, SOL_SOCKET, SO_SNDLOWAT, (caddr_t)&size, sizeof(size))) return 0; int err = Socket::error(); if(!err) err = EIO; return err; #else return ENOSYS; #endif } int Socket::sendsize(socket_t so, unsigned size) { assert(so != INVALID_SOCKET); #ifdef SO_SNDBUF if(!setsockopt(so, SOL_SOCKET, SO_SNDBUF, (caddr_t)&size, sizeof(size))) return 0; int err = Socket::error(); if(!err) err = EIO; return err; #else return ENOSYS; #endif } int Socket::recvsize(socket_t so, unsigned size) { #ifdef SO_RCVBUF if(!setsockopt(so, SOL_SOCKET, SO_RCVBUF, (caddr_t)&size, sizeof(size))) return 0; int err = Socket::error(); if(!err) err = EIO; return err; #else return ENOSYS; #endif } bool Socket::connected(void) const { char buf; if(so == INVALID_SOCKET) return false; if(!wait()) return true; if(_recv_(so, &buf, 1, MSG_DONTWAIT | MSG_PEEK) < 1) return false; return true; } bool Socket::is_pending(unsigned qio) { if(pending() >= qio) return true; return false; } #ifdef _MSWINDOWS_ unsigned Socket::pending(socket_t so) { u_long opt = 0; if(so == INVALID_SOCKET) return 0; ioctlsocket(so, FIONREAD, &opt); return (unsigned)opt; } #else unsigned Socket::pending(socket_t so) { int opt; if(so == INVALID_SOCKET) return 0; if(::ioctl(so, FIONREAD, &opt)) return 0; return (unsigned)opt; } #endif socket_t Socket::acceptfrom(socket_t so, struct sockaddr_storage *addr) { socklen_t len = sizeof(struct sockaddr_storage); if(addr) return _accept_(so, (struct sockaddr *)addr, &len); else return _accept_(so, NULL, NULL); } bool Socket::wait(timeout_t timeout) const { return wait(so, timeout); } bool Socket::wait(socket_t so, timeout_t timeout) { int status; #ifdef USE_POLL struct pollfd pfd; pfd.fd = so; pfd.revents = 0; pfd.events = POLLIN; if(so == INVALID_SOCKET) return false; status = 0; while(status < 1) { if(timeout == Timer::inf) status = _poll_(&pfd, 1, -1); else status = _poll_(&pfd, 1, timeout); if(status == -1 && errno == EINTR) continue; if(status < 0) return false; } if(pfd.revents & POLLIN) return true; return false; #else struct timeval tv; struct timeval *tvp = &tv; unsigned long to = (unsigned long)timeout; fd_set grp; if(so == INVALID_SOCKET) return false; if(timeout == Timer::inf) tvp = NULL; else { tv.tv_usec = (to % 1000) * 1000; tv.tv_sec = (to / 1000); } FD_ZERO(&grp); FD_SET(so, &grp); status = _select_((int)(so + 1), &grp, NULL, NULL, tvp); if(status < 1) return false; if(FD_ISSET(so, &grp)) return true; return false; #endif } bool Socket::waitSending(timeout_t timeout) const { int status; #ifdef USE_POLL struct pollfd pfd; pfd.fd = so; pfd.revents = 0; pfd.events = POLLOUT; if(so == INVALID_SOCKET) return false; status = 0; while(status < 1) { if(timeout == Timer::inf) status = _poll_(&pfd, 1, -1); else status = _poll_(&pfd, 1, timeout); if(status == -1 && errno == EINTR) continue; if(status < 0) return false; } if(pfd.revents & POLLOUT) return true; return false; #else struct timeval tv; struct timeval *tvp = &tv; unsigned long to = (unsigned long)timeout; fd_set grp; if(so == INVALID_SOCKET) return false; if(timeout == Timer::inf) tvp = NULL; else { tv.tv_usec = (to % 1000) * 1000; tv.tv_sec = to / 1000; } FD_ZERO(&grp); FD_SET(so, &grp); status = _select_((int)(so + 1), NULL, &grp, NULL, tvp); if(status < 1) return false; if(FD_ISSET(so, &grp)) return true; return false; #endif } ListenSocket::ListenSocket(const char *iface, const char *svc, unsigned backlog, int family, int type, int protocol) : Socket() { if(!iface) iface = "*"; assert(iface != NULL && *iface != 0); assert(svc != NULL && *svc != 0); assert(backlog > 0); so = create(iface, svc, backlog, family, type, protocol); } socket_t ListenSocket::create(const char *iface, const char *svc, unsigned backlog, int family, int type, int protocol) { if(!type) type = SOCK_STREAM; socket_t so = Socket::create(iface, svc, family, type, protocol); if(so == INVALID_SOCKET) return so; if(_listen_(so, backlog)) { release(so); return INVALID_SOCKET; } return so; } socket_t ListenSocket::accept(struct sockaddr_storage *addr) const { socklen_t len = sizeof(struct sockaddr_storage); if(addr) return _accept_(so, (struct sockaddr *)addr, &len); else return _accept_(so, NULL, NULL); } TCPServer::TCPServer(const char *address, const char *service, unsigned backlog) : ListenSocket(address, service, backlog) { } #ifdef _MSWINDOWS_ #undef AF_UNIX #endif struct ::addrinfo *Socket::hinting(socket_t so, struct addrinfo *hint) { assert(hint != NULL); union { struct sockaddr_storage st; struct sockaddr_in in; } us; struct sockaddr *sa = (struct sockaddr *)&us.st; socklen_t slen = sizeof(us.st); memset(hint, 0, sizeof(struct addrinfo)); memset(sa, 0, sizeof(us.st)); if(_getsockname_(so, sa, &slen)) return NULL; hint->ai_family = us.in.sin_family; slen = sizeof(hint->ai_socktype); getsockopt(so, SOL_SOCKET, SO_TYPE, (caddr_t)&hint->ai_socktype, &slen); return hint; } int Socket::type(socket_t so) { int sotype; socklen_t slen = sizeof(sotype); if(getsockopt(so, SOL_SOCKET, SO_TYPE, (caddr_t)&sotype, &slen)) return 0; return sotype; } bool Socket::ccid(socket_t so, uint8_t ccid) { uint8_t ccids[4]; socklen_t len = sizeof(ccids); bool supported = false; // maybe also not dccp socket... if(getsockopt(so, SOL_DCCP, DCCP_SOCKOPT_AVAILABLE_CCIDS, (char *)&ccids, &len) < 0) return false; for(unsigned pos = 0; pos < sizeof(ccids); ++pos) { if(ccid == ccids[pos]) { supported = true; break; } } if(!supported) return false; if(setsockopt(so, SOL_DCCP, DCCP_SOCKOPT_CCID, (char *)&ccid, sizeof(ccid)) < 0) return false; return true; } unsigned Socket::segsize(socket_t so, unsigned size) { #ifdef IP_MTU socklen_t alen = sizeof(size); #endif switch(type(so)) { case SOCK_STREAM: #ifdef TCP_MAXSEG if(size) setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&size, sizeof(size)); #endif break; case SOCK_DCCP: #ifdef DCCP_MAXSEG if(size) setsockopt(so, IPPROTO_DCCP, DCCP_MAXSEG, (char *)&size, sizeof(size)); #endif break; } #ifdef IP_MTU getsockopt(so, IPPROTO_IP, IP_MTU, &size, &alen); #else size = 0; #endif return size; } char *Socket::hostname(const struct sockaddr *sa, char *buf, size_t max) { assert(sa != NULL); assert(buf != NULL); assert(max > 0); socklen_t sl; #ifdef AF_UNIX const struct sockaddr_un *un = (const struct sockaddr_un *)sa; #endif switch(sa->sa_family) { #ifdef AF_UNIX case AF_UNIX: if(max > sizeof(un->sun_path)) max = sizeof(un->sun_path); else --max; strncpy(buf, un->sun_path, max); buf[max] = 0; return buf; #endif case AF_INET: sl = sizeof(struct sockaddr_in); break; #ifdef AF_INET6 case AF_INET6: sl = sizeof(struct sockaddr_in6); break; #endif default: return NULL; } if(getnameinfo(sa, (socklen_t)sl, buf, (socksize_t)max, NULL, 0, NI_NOFQDN)) return NULL; return buf; } socklen_t Socket::query(socket_t so, struct sockaddr_storage *sa, const char *host, const char *svc) { assert(sa != NULL); assert(host != NULL && *host != 0); assert(svc != NULL && *svc != 0); socklen_t len = 0; struct addrinfo hint, *res = NULL; #ifdef AF_UNIX if(strchr(host, '/')) return unixaddr((struct sockaddr_un *)sa, host); #endif if(!hinting(so, &hint) || !svc) return 0; if(getaddrinfo(host, svc, &hint, &res) || !res) goto exit; memcpy(sa, res->ai_addr, res->ai_addrlen); len = (socklen_t)res->ai_addrlen; exit: if(res) freeaddrinfo(res); return len; } int Socket::bindto(socket_t so, const struct sockaddr *iface) { if(!_bind_(so, iface, len(iface))) return 0; return Socket::error(); } int Socket::listento(socket_t so, const struct sockaddr *iface, int backlog) { if(_bind_(so, iface, len(iface))) return Socket::error(); if(_listen_(so, backlog)) return Socket::error(); return 0; } int Socket::bindto(socket_t so, const char *host, const char *svc, int protocol) { assert(so != INVALID_SOCKET); assert(host != NULL && *host != 0); assert(svc != NULL && *svc != 0); int rtn = -1; int reuse = 1; struct addrinfo hint, *res = NULL; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (caddr_t)&reuse, sizeof(reuse)); #ifdef AF_UNIX if(host && strchr(host, '/')) { struct sockaddr_storage uaddr; socklen_t len = unixaddr((struct sockaddr_un *)&uaddr, host); rtn = _bind_(so, (struct sockaddr *)&uaddr, len); goto exit; }; #endif if(!hinting(so, &hint) || !svc) return ENOSYS; hint.ai_protocol = protocol; if(host && !strcmp(host, "*")) host = NULL; #if defined(SO_BINDTODEVICE) && !defined(__QNX__) if(host && !strchr(host, '.') && !strchr(host, ':')) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_ifrn.ifrn_name, host, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ - 1] = '\0'; setsockopt(so, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)); host = NULL; } #endif hint.ai_flags = AI_PASSIVE | AI_NUMERICHOST; #if defined(AF_INET6) && defined(AI_V4MAPPED) if(hint.ai_family == AF_INET6 && !v6only) hint.ai_flags |= AI_V4MAPPED; #endif rtn = getaddrinfo(host, svc, &hint, &res); if(rtn) goto exit; rtn = _bind_(so, res->ai_addr, (socklen_t)res->ai_addrlen); exit: if(res) freeaddrinfo(res); if(rtn) rtn = Socket::error(); return rtn; } unsigned Socket::keyhost(const struct sockaddr *addr, unsigned keysize) { assert(addr != NULL); assert(keysize > 0); unsigned key = 0; caddr_t cp = NULL; unsigned len; switch(addr->sa_family) { #ifdef AF_INET6 case AF_INET6: cp = (caddr_t)(&((const struct sockaddr_in6 *)(addr))->sin6_addr); len = 16; break; #endif case AF_INET: cp = (caddr_t)(&((const struct sockaddr_in *)(addr))->sin_addr); len = 4; break; default: return 0; } while(len--) { key = key << 1; key ^= cp[len]; } return key % keysize; } unsigned Socket::keyindex(const struct sockaddr *addr, unsigned keysize) { assert(addr != NULL); assert(keysize > 0); unsigned key = 0; caddr_t cp = NULL; unsigned len; switch(addr->sa_family) { #ifdef AF_INET6 case AF_INET6: cp = (caddr_t)(&((const struct sockaddr_in6 *)(addr))->sin6_addr); len = 16; key = service(addr); break; #endif case AF_INET: cp = (caddr_t)(&((const struct sockaddr_in *)(addr))->sin_addr); len = 4; key = service(addr); break; default: return 0; } while(len--) { key = key << 1; key ^= cp[len]; } return key % keysize; } short Socket::service(const struct sockaddr *addr) { assert(addr != NULL); switch(addr->sa_family) { #ifdef AF_INET6 case AF_INET6: return ntohs(((const struct sockaddr_in6 *)(addr))->sin6_port); #endif case AF_INET: return ntohs(((const struct sockaddr_in *)(addr))->sin_port); } return 0; } char *Socket::query(const struct sockaddr *addr, char *name, socklen_t size) { assert(addr != NULL); assert(name != NULL); #ifdef _MSWINDOWS_ DWORD slen = size; #endif *name = 0; if(!addr) return NULL; switch(addr->sa_family) { #ifdef AF_UNIX case AF_UNIX: String::set(name, size, ((const struct sockaddr_un *)(addr))->sun_path); return name; #endif #ifdef _MSWINDOWS_ #ifdef AF_INET6 case AF_INET6: struct sockaddr_in6 saddr6; memcpy(&saddr6, addr, sizeof(saddr6)); saddr6.sin6_port = 0; WSAAddressToString((struct sockaddr *)&saddr6, sizeof(saddr6), NULL, name, &slen); return name; #endif case AF_INET: struct sockaddr_in saddr; memcpy(&saddr, addr, sizeof(saddr)); saddr.sin_port = 0; WSAAddressToString((struct sockaddr *)&saddr, sizeof(saddr), NULL, name, &slen); return name; #else #ifdef HAVE_INET_NTOP #ifdef AF_INET6 case AF_INET6: inet_ntop(addr->sa_family, &((const struct sockaddr_in6 *)(addr))->sin6_addr, name, size); return name; #endif case AF_INET: inet_ntop(addr->sa_family, &((const struct sockaddr_in *)(addr))->sin_addr, name, size); return name; #else case AF_INET: ENTER_EXCLUSIVE String::set(name, size, inet_ntoa(((const struct sockaddr_in *)(addr))->sin_addr)); LEAVE_EXCLUSIVE return name; #endif #endif } return NULL; } int Socket::via(struct sockaddr *iface, const struct sockaddr *dest) { assert(iface != NULL); assert(dest != NULL); int rtn = -1; socket_t so = INVALID_SOCKET; socklen_t slen = len(dest); if(slen) memset(iface, 0, slen); iface->sa_family = AF_UNSPEC; switch(dest->sa_family) { #ifdef AF_INET6 case AF_INET6: #endif case AF_INET: so = ::socket(dest->sa_family, SOCK_DGRAM, 0); if((socket_t)so == INVALID_SOCKET) return -1; socket_mapping(dest->sa_family, so); if(!_connect_(so, dest, slen)) rtn = _getsockname_(so, iface, &slen); break; default: return ENOSYS; } switch(iface->sa_family) { case AF_INET: ((struct sockaddr_in*)(iface))->sin_port = 0; break; #ifdef AF_INET6 case AF_INET6: ((struct sockaddr_in6*)(iface))->sin6_port = 0; break; #endif } if((socket_t)so != INVALID_SOCKET) { #ifdef _MSWINDOWS_ ::closesocket(so); #else ::shutdown(so, SHUT_RDWR); ::close(so); #endif } if(rtn) rtn = Socket::error(); return rtn; } bool Socket::eq_subnet(const struct sockaddr *s1, const struct sockaddr *s2) { assert(s1 != NULL && s2 != NULL); unsigned char *a1, *a2; if(s1->sa_family != s2->sa_family) return false; if(s1->sa_family != AF_INET) return true; a1 = (unsigned char *)&(((const struct sockaddr_in *)(s1))->sin_addr); a2 = (unsigned char *)&(((const struct sockaddr_in *)(s1))->sin_addr); if(*a1 == *a2 && *a1 < 128) return true; if(*a1 != *a2) return false; if(*a1 > 127 && *a1 < 192 && a1[1] == a2[1]) return true; if(a1[1] != a2[1]) return false; if(a1[2] != a2[2]) return false; return true; } unsigned Socket::store(struct sockaddr_internet *storage, const struct sockaddr *address) { if(storage == NULL || address == NULL) return 0; socklen_t slen = len(address); memcpy(storage, address, slen); return slen; } unsigned Socket::copy(struct sockaddr *s1, const struct sockaddr *s2) { if(s1 == NULL || s2 == NULL) return 0; socklen_t slen = len(s1); if(slen > 0) { memcpy(s1, s2, slen); return slen; } return 0; } bool Socket::eq_host(const struct sockaddr *s1, const struct sockaddr *s2) { assert(s1 != NULL && s2 != NULL); if(s1->sa_family != s2->sa_family) return false; switch(s1->sa_family) { case AF_INET: if(memcmp(&(((const struct sockaddr_in *)s1)->sin_addr), &(((const struct sockaddr_in *)s2)->sin_addr), 4)) return false; return true; #ifdef AF_INET6 case AF_INET6: if(memcmp(&(((const struct sockaddr_in6 *)s1)->sin6_addr), &(((const struct sockaddr_in6 *)s2)->sin6_addr), 4)) return false; return true; #endif default: if(memcmp(s1, s2, len(s1))) return false; return true; } return false; } bool Socket::equal(const struct sockaddr *s1, const struct sockaddr *s2) { assert(s1 != NULL && s2 != NULL); if(s1->sa_family != s2->sa_family) return false; switch(s1->sa_family) { case AF_INET: if(memcmp(&(((const struct sockaddr_in *)s1)->sin_addr), &(((const struct sockaddr_in *)s2)->sin_addr), 4)) return false; if(!((const struct sockaddr_in *)s1)->sin_port || !((const struct sockaddr_in *)s2)->sin_port) return true; if(((const struct sockaddr_in *)s1)->sin_port != ((const struct sockaddr_in *)s2)->sin_port) return false; return true; #ifdef AF_INET6 case AF_INET6: if(memcmp(&(((const struct sockaddr_in6 *)s1)->sin6_addr), &(((const struct sockaddr_in6 *)s2)->sin6_addr), 4)) return false; if(!((const struct sockaddr_in6 *)s1)->sin6_port || !((const struct sockaddr_in6 *)s2)->sin6_port) return true; if(((const struct sockaddr_in6 *)s1)->sin6_port != ((const struct sockaddr_in6 *)s2)->sin6_port) return false; return true; #endif default: if(memcmp(s1, s2, len(s1))) return false; return true; } return false; } size_t Socket::printf(const char *format, ...) { assert(format != NULL); char buf[1024]; va_list args; va_start(args, format); vsnprintf(buf, sizeof(buf), format, args); va_end(args); return writes(buf); } ssize_t Socket::printf(socket_t so, const char *format, ...) { assert(format != NULL); char buf[536]; va_list args; va_start(args, format); vsnprintf(buf, sizeof(buf), format, args); va_end(args); return sendto(so, buf, strlen(buf), 0, NULL); } socklen_t Socket::len(const struct sockaddr *sa) { if(!sa) return 0; switch(sa->sa_family) { case AF_INET: return sizeof(sockaddr_in); #ifdef AF_INET6 case AF_INET6: return sizeof(sockaddr_in6); #endif default: return sizeof(sockaddr_storage); } } int Socket::family(socket_t so) { assert(so != INVALID_SOCKET); #ifndef _MSWINDOWS_ union { struct sockaddr_storage saddr; struct sockaddr_in inaddr; } us; socklen_t len = sizeof(us.saddr); struct sockaddr *addr = (struct sockaddr *)(&us.saddr); if(_getsockname_(so, addr, &len)) return AF_UNSPEC; return us.inaddr.sin_family; #else // getsockname doesn't work on unbound windows sockets WSAPROTOCOL_INFO info; socklen_t len = sizeof(info); if(getsockopt(so, SOL_SOCKET, SO_PROTOCOL_INFO, (char *) &info, &len)) return AF_UNSPEC; return info.iAddressFamily; #endif } bool Socket::is_null(const char *str) { assert(str != NULL); while(*str && strchr("0:.*", *str) != NULL) ++str; // allow field separation... if(*str <= ' ') return true; if(*str) return false; return true; } bool Socket::is_numeric(const char *str) { assert(str != NULL); // if raw ipv6, then we can just exit, no chance to confuse with names if(strchr(str, ':')) return true; while(*str && strchr("0123456789.", *str) != NULL) ++str; // allow field separators if(*str <= ' ') return true; if(*str) return false; return true; } int Socket::local(socket_t sock, struct sockaddr_storage *addr) { socklen_t slen = sizeof(sockaddr_storage); return _getsockname_(sock, (struct sockaddr *)addr, &slen); } int Socket::remote(socket_t sock, struct sockaddr_storage *addr) { socklen_t slen = sizeof(sockaddr_storage); return _getpeername_(sock, (struct sockaddr *)addr, &slen); } String str(Socket& so, strsize_t size) { String s(size); so.readline(s.c_mem(), s.size()); String::fix(s); return s; } struct sockaddr *_getaddrinfo(struct addrinfo *list) { return list->ai_addr; } struct addrinfo *_nextaddrinfo(struct addrinfo *list) { if(!list) return NULL; return list->ai_next; } socket_t _getaddrsock(struct addrinfo *list) { if(!list) return INVALID_SOCKET; return ::socket(list->ai_family, list->ai_socktype, list->ai_protocol); } } // namespace ucommon ucommon-6.4.4/corelib/xml.cpp0000644000175000001440000003505012504370702013045 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include static bool isElement(char c) { return isalnum(c) || c == ':' || c == '-' || c == '.' || c == '_'; } namespace ucommon { XMLParser::XMLParser(unsigned size) { state = NONE; bufpos = 0; bufsize = size; buffer = new char[size]; ecount = dcount = 0; } XMLParser::~XMLParser() { if(buffer) { delete[] buffer; buffer = NULL; } } void XMLParser::putBuffer(char c) { buffer[bufpos++] = c; if(bufpos >= bufsize) { if(ecount) characters((caddr_t)buffer, bufpos); bufpos = 0; } } void XMLParser::clearBuffer(void) { if(bufpos && ecount) characters((caddr_t)buffer, bufpos); bufpos = 0; } bool XMLParser::parse(FILE *fp) { state = NONE; bufpos = 0; ecount = dcount = 0; int ch; unsigned char cp; while((ch = fgetc(fp)) != EOF) { switch(state) { case AMP: if((!bufpos && ch == '#') || isElement(ch)) { buffer[bufpos++] = ch; break; } if(ch != ';') return false; buffer[bufpos] = 0; if(buffer[0] == '#') cp = atoi(buffer + 1); else if(eq(buffer, "amp")) cp = '&'; else if(eq(buffer, "lt")) cp = '<'; else if(eq(buffer, "gt")) cp = '>'; else if(eq(buffer, "apos")) cp = '`'; else if(eq(buffer, "quot")) cp = '\"'; else return false; characters((caddr_t)&cp, 1); bufpos = 0; state = NONE; break; case TAG: if(ch == '>') { state = NONE; if(!parseTag()) return false; } else if(ch == '[' && bufpos == 7 && !strncmp(buffer, "![CDATA", 7)) { state = CDATA; } else if(ch == '-' && bufpos == 2 && !strncmp(buffer, "!-", 2)) { state = COMMENT; bufpos = 0; } else if(ch == '[' && !strncmp(buffer, "!DOCTYPE ", 9)) { state = DTD; bufpos = 0; } else putBuffer(ch); break; case COMMENT: if(ch == '>' && bufpos >= 2 && !strncmp(&buffer[bufpos - 2], "--", 2)) { bufpos -= 2; if(bufpos) comment((caddr_t)buffer, bufpos); bufpos = 0; state = NONE; } else { buffer[bufpos++] = ch; if(bufpos == bufsize) { comment((caddr_t)buffer, bufpos); bufpos = 0; } } break; case CDATA: putBuffer(ch); if(bufpos > 2) if(eq(&buffer[bufpos - 3], "]]>")) { bufpos -= 3; state = NONE; clearBuffer(); } break; case DTD: if(ch == '<') ++dcount; else if(ch == '>' && dcount) --dcount; else if(ch == '>') state = NONE; break; case NONE: if(ch == '<') { clearBuffer(); state = TAG; } else if(ecount && ch == '&') { clearBuffer(); state = AMP; } else if(ecount) putBuffer(ch); break; case END: return true; } if(state == END) return true; } // eof before end of ducument... return false; } bool XMLParser::parse(CharacterProtocol& io) { state = NONE; bufpos = 0; ecount = dcount = 0; int ch; unsigned char cp; while((ch = io.getchar()) != EOF) { switch(state) { case AMP: if((!bufpos && ch == '#') || isElement(ch)) { buffer[bufpos++] = ch; break; } if(ch != ';') return false; buffer[bufpos] = 0; if(buffer[0] == '#') cp = atoi(buffer + 1); else if(eq(buffer, "amp")) cp = '&'; else if(eq(buffer, "lt")) cp = '<'; else if(eq(buffer, "gt")) cp = '>'; else if(eq(buffer, "apos")) cp = '`'; else if(eq(buffer, "quot")) cp = '\"'; else return false; characters((caddr_t)&cp, 1); bufpos = 0; state = NONE; break; case TAG: if(ch == '>') { state = NONE; if(!parseTag()) return false; } else if(ch == '[' && bufpos == 7 && !strncmp(buffer, "![CDATA", 7)) { state = CDATA; } else if(ch == '-' && bufpos == 2 && !strncmp(buffer, "!-", 2)) { state = COMMENT; bufpos = 0; } else if(ch == '[' && !strncmp(buffer, "!DOCTYPE ", 9)) { state = DTD; bufpos = 0; } else putBuffer(ch); break; case COMMENT: if(ch == '>' && bufpos >= 2 && !strncmp(&buffer[bufpos - 2], "--", 2)) { bufpos -= 2; if(bufpos) comment((caddr_t)buffer, bufpos); bufpos = 0; state = NONE; } else { buffer[bufpos++] = ch; if(bufpos == bufsize) { comment((caddr_t)buffer, bufpos); bufpos = 0; } } break; case CDATA: putBuffer(ch); if(bufpos > 2) if(eq(&buffer[bufpos - 3], "]]>")) { bufpos -= 3; state = NONE; clearBuffer(); } break; case DTD: if(ch == '<') ++dcount; else if(ch == '>' && dcount) --dcount; else if(ch == '>') state = NONE; break; case NONE: if(ch == '<') { clearBuffer(); state = TAG; } else if(ecount && ch == '&') { clearBuffer(); state = AMP; } else if(ecount) putBuffer(ch); break; case END: return true; } if(state == END) return true; } // eof before end of ducument... return false; } bool XMLParser::partial(const char *data, size_t len) { if(state == END) state = NONE; unsigned char cp; while(len--) { switch(state) { case AMP: if((!bufpos && *data == '#') || isElement(*data)) { buffer[bufpos++] = *data; break; } if(*data != ';') return false; buffer[bufpos] = 0; if(buffer[0] == '#') cp = atoi(buffer + 1); else if(eq(buffer, "amp")) cp = '&'; else if(eq(buffer, "lt")) cp = '<'; else if(eq(buffer, "gt")) cp = '>'; else if(eq(buffer, "apos")) cp = '`'; else if(eq(buffer, "quot")) cp = '\"'; else return false; characters((caddr_t)&cp, 1); bufpos = 0; state = NONE; break; case TAG: if(*data == '>') { state = NONE; if(!parseTag()) return false; } else if(*data == '[' && bufpos == 7 && !strncmp(buffer, "![CDATA", 7)) { state = CDATA; } else if(*data == '-' && bufpos == 2 && !strncmp(buffer, "!-", 2)) { state = COMMENT; bufpos = 0; } else if(*data == '[' && !strncmp(buffer, "!DOCTYPE ", 9)) { state = DTD; bufpos = 0; } else putBuffer(*data); break; case COMMENT: if(*data == '>' && bufpos >= 2 && !strncmp(&buffer[bufpos - 2], "--", 2)) { bufpos -= 2; if(bufpos) comment((caddr_t)buffer, bufpos); bufpos = 0; state = NONE; } else { buffer[bufpos++] = *data; if(bufpos == bufsize) { comment((caddr_t)buffer, bufpos); bufpos = 0; } } break; case CDATA: putBuffer(*data); if(bufpos > 2) if(eq(&buffer[bufpos - 3], "]]>")) { bufpos -= 3; state = NONE; clearBuffer(); } break; case DTD: if(*data == '<') ++dcount; else if(*data == '>' && dcount) --dcount; else if(*data == '>') state = NONE; break; case NONE: case END: if(*data == '<') { clearBuffer(); state = TAG; } else if(ecount && *data == '&') { clearBuffer(); state = AMP; } else if(ecount) putBuffer(*data); } ++data; } return true; } bool XMLParser::parseTag(void) { size_t len = bufpos; const char *data = buffer; bool end = false; caddr_t attrib[128]; unsigned attr = 0; char *ep; if(*data == '/') { while(--len) { if(!isElement(*(++data))) break; } if(len) return false; buffer[bufpos] = 0; endElement((caddr_t)(buffer + 1)); bufpos = 0; --ecount; if(ecount < 0) return false; if(!ecount) { state = END; endDocument(); } } else if(*data == '!') { bufpos = 0; return true; // dtd } else if(*data == '?') { if(!strnicmp(data, "?xml version=\"", 14)) { // version info } bufpos = 0; } else if(!isElement(*data)) return false; else { end = false; if(buffer[bufpos - 1] == '/') { --bufpos; end = true; } len = 0; data = buffer; while(len < bufpos) { if(!isElement(*data)) break; ++len; ++data; } if(len == bufpos) { if(!ecount) startDocument(); ++ecount; attrib[0] = attrib[1] = NULL; buffer[bufpos] = 0; startElement((caddr_t)buffer, attrib); if(end) { ending: --ecount; endElement((caddr_t)buffer); if(!ecount) { state = END; endDocument(); } } bufpos = 0; return true; } if(!ecount) startDocument(); ++ecount; // attributes, name is between data and len for(;;) { while(!isElement(buffer[len]) && len < bufpos) { if(!isspace(buffer[len])) return false; buffer[len++] = 0; } if(len == bufpos) break; attrib[attr++] = (caddr_t)(buffer + len); while(len < bufpos && isElement(buffer[len])) ++len; if(len == bufpos) return false; if(buffer[len] != '=') return false; buffer[len++] = 0; if(len == bufpos) { attrib[attr++] = (caddr_t)""; break; } if(isspace(buffer[len])) { attrib[attr++] = (caddr_t)""; continue; } if(buffer[len] == '\'' || buffer[len] == '\"') { ep = strchr(buffer + len + 1, buffer[len]); if(!ep) return false; attrib[attr++] = (caddr_t)buffer + len + 1; *(ep++) = 0; len = ep - buffer; continue; } if(!isElement(buffer[len])) return false; attrib[attr++] = (caddr_t)buffer; while(isElement(buffer[len]) && len < bufpos) ++len; if(len == bufpos) { buffer[len] = 0; break; } } attrib[attr++] = NULL; attrib[attr++] = NULL; startElement((caddr_t)buffer, attrib); if(end) goto ending; bufpos = 0; return true; } return true; } // all our lovely base virtuals stubbed out so if we are lazy and forget to // implement something we want to ignore anyway (say comments...) we don't // bring whatever it is crashing down one day when we choose to add a // comment into an xml stream... void XMLParser::startDocument() { } void XMLParser::endDocument() { } void XMLParser::comment(caddr_t text, size_t len) { } void XMLParser::characters(caddr_t text, size_t len) { } } // namespace ucommon ucommon-6.4.4/corelib/object.cpp0000644000175000001440000000633212504370415013515 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include namespace ucommon { CountedObject::CountedObject() { count = 0; } CountedObject::CountedObject(const ObjectProtocol &source) { count = 0; } void CountedObject::dealloc(void) { delete this; } void CountedObject::retain(void) { ++count; } void CountedObject::release(void) { if(count > 1) { --count; return; } dealloc(); } auto_object::auto_object(ObjectProtocol *o) { if(o) o->retain(); object = o; } auto_object::auto_object() { object = 0; } void auto_object::release(void) { if(object) object->release(); object = 0; } auto_object::~auto_object() { release(); } auto_object::auto_object(const auto_object &from) { object = from.object; if(object) object->retain(); } bool auto_object::operator!() const { return (object == 0); } auto_object::operator bool() const { return (object != 0); } bool auto_object::operator==(ObjectProtocol *o) const { assert(o != NULL); return object == o; } bool auto_object::operator!=(ObjectProtocol *o) const { assert(o != NULL); return object != o; } void auto_object::operator=(ObjectProtocol *o) { if(object == o) return; if(o) o->retain(); if(object) object->release(); object = o; } SparseObjects::SparseObjects(unsigned m) { assert(m > 0); max = m; vector = new ObjectProtocol *[m]; memset(vector, 0, sizeof(ObjectProtocol *) * m); } SparseObjects::~SparseObjects() { purge(); } void SparseObjects::purge(void) { if(!vector) return; for(unsigned pos = 0; pos < max; ++ pos) { if(vector[pos]) vector[pos]->release(); } delete[] vector; vector = NULL; } unsigned SparseObjects::count(void) { unsigned c = 0; for(unsigned pos = 0; pos < max; ++pos) { if(vector[pos]) ++c; } return c; } ObjectProtocol *SparseObjects::invalid(void) const { return NULL; } ObjectProtocol *SparseObjects::get(unsigned pos) { ObjectProtocol *obj; if(pos >= max) return invalid(); if(!vector[pos]) { obj = create(); if(!obj) return invalid(); obj->retain(); vector[pos] = obj; } return vector[pos]; } } // namespace ucommon ucommon-6.4.4/corelib/protocols.cpp0000664000175000017500000003252512551014424014301 00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #undef getc #undef putc #undef puts #undef gets namespace ucommon { void MemoryProtocol::fault(void) const { } char *MemoryProtocol::dup(const char *str) { if(!str) return NULL; size_t len = strlen(str) + 1; char *mem = static_cast(alloc(len)); if(mem) String::set(mem, len, str); else fault(); return mem; } void *MemoryProtocol::dup(void *obj, size_t size) { assert(obj != NULL); assert(size > 0); char *mem = static_cast(alloc(size)); if(mem) memcpy(mem, obj, size); else fault(); return mem; } void *MemoryProtocol::zalloc(size_t size) { void *mem = alloc(size); if(mem) memset(mem, 0, size); else fault(); return mem; } MemoryProtocol::~MemoryProtocol() { } MemoryRedirect::MemoryRedirect(MemoryProtocol *protocol) { target = protocol; } void *MemoryRedirect::_alloc(size_t size) { // a null redirect uses the heap... if(!target) return malloc(size); return target->_alloc(size); } BufferProtocol::BufferProtocol() : CharacterProtocol() { end = true; eol = "\r\n"; input = output = buffer = NULL; } BufferProtocol::BufferProtocol(size_t size, mode_t mode) { end = true; eol = "\r\n"; input = output = buffer = NULL; allocate(size, mode); } BufferProtocol::~BufferProtocol() { release(); } void BufferProtocol::fault(void) const { } void BufferProtocol::release(void) { if(buffer) { flush(); free(buffer); input = output = buffer = NULL; end = true; } } void BufferProtocol::allocate(size_t size, mode_t mode) { release(); _clear(); if(!size) return; back = 0; switch(mode) { case RDWR: input = buffer = (char *)malloc(size * 2); if(buffer) output = buffer + size; else fault(); break; case RDONLY: input = buffer = (char *)malloc(size); if(!buffer) fault(); break; case WRONLY: output = buffer = (char *)malloc(size); if(!buffer) fault(); break; } bufpos = insize = outsize = 0; bufsize = size; if(buffer) end = false; } bool BufferProtocol::_blocking(void) { return false; } size_t BufferProtocol::put(const void *address, size_t size) { size_t count = 0; if(!output || !address || !size) return 0; const char *cp = (const char *)address; while(count < size) { if(outsize == bufsize) { outsize = 0; if(_push(output, bufsize) < bufsize) { output = NULL; end = true; // marks a disconnection... return count; } } output[outsize++] = cp[count++]; } return count; } size_t BufferProtocol::get(void *address, size_t size) { size_t count = 0; if(!input || !address || !size) return 0; char *cp = (char *)address; while(count < size) { if(bufpos == insize) { if(end) return count; insize = _pull(input, bufsize); bufpos = 0; if(insize == 0) end = true; else if(insize < bufsize && !_blocking()) end = true; if(!insize) return count; } cp[count++] = input[bufpos++]; } return count; } int BufferProtocol::_getch(void) { if(!input) return EOF; if(back) { back = 0; return back; } if(bufpos == insize) { if(end) return EOF; insize = _pull(input, bufsize); bufpos = 0; if(insize == 0) end = true; else if(insize < bufsize && !_blocking()) end = true; if(!insize) return EOF; } return input[bufpos++]; } size_t CharacterProtocol::putchars(const char *address, size_t size) { size_t count = 0; if(!address) return 0; if(!size) size = strlen(address); while(count < size) { if(_putch(*address) == EOF) break; ++count; ++address; } return count; } int BufferProtocol::_putch(int ch) { if(!output) return EOF; if(ch == 0) { puts(eol); flush(); return 0; } if(outsize == bufsize) { outsize = 0; if(_push(output, bufsize) < bufsize) { output = NULL; end = true; // marks a disconnection... return EOF; } } output[outsize++] = ch; return ch; } size_t BufferProtocol::printf(const char *pformat, ...) { va_list args; int result; size_t count; if(!flush() || !output || !pformat) return 0; va_start(args, pformat); result = vsnprintf(output, bufsize, pformat, args); va_end(args); if(result < 1) return 0; if((size_t)result > bufsize) result = (int)bufsize; count = _push(output, result); if(count < (size_t)result) { output = NULL; end = true; } return count; } void BufferProtocol::purge(void) { outsize = insize = bufpos = 0; } bool BufferProtocol::_flush(void) { if(!output) return false; if(!outsize) return true; if(_push(output, outsize) == outsize) { outsize = 0; return true; } output = NULL; end = true; return false; } char *BufferProtocol::gather(size_t size) { if(!input || size > bufsize) return NULL; if(size + bufpos > insize) { if(end) return NULL; size_t adjust = outsize - bufpos; memmove(input, input + bufpos, adjust); insize = adjust + _pull(input, bufsize - adjust); bufpos = 0; if(insize < bufsize) end = true; } if(size + bufpos <= insize) { char *bp = input + bufpos; bufpos += size; return bp; } return NULL; } char *BufferProtocol::request(size_t size) { if(!output || size > bufsize) return NULL; if(size + outsize > bufsize) flush(); size_t offset = outsize; outsize += size; return output + offset; } size_t CharacterProtocol::putline(const char *string) { size_t count = 0; while(string && *string && (EOF != _putch(*string))) ++count; string = eol; while(string && *string && (EOF != _putch(*string))) ++count; return count; } size_t CharacterProtocol::getline(String& s) { size_t result = getline(s.c_mem(), s.size() + 1); String::fix(s); return result; } size_t CharacterProtocol::getline(char *string, size_t size) { size_t count = 0; unsigned eolp = 0; const char *eols = eol; bool eof = false; if(!eols) eols = "\0"; if (string) string[0] = 0; else return 0; while(count < size - 1) { int ch = _getch(); if(ch == EOF) { eolp = 0; eof = true; break; } string[count++] = ch; if(ch == eols[eolp]) { ++eolp; if(eols[eolp] == 0) break; } else eolp = 0; // special case for \r\n can also be just eol as \n if(eq(eol, "\r\n") && ch == '\n') { ++eolp; break; } } count -= eolp; string[count] = 0; if(!eof) ++count; return count; } size_t CharacterProtocol::print(const PrintProtocol& f) { const char *cp = f._print(); if(cp == NULL) return putchar(0); return putchars(cp); } size_t CharacterProtocol::input(InputProtocol& f) { int c; size_t count = 0; for(;;) { if(back) { c = back; back = 0; } else c = _getch(); c = f._input(c); if(c) { if(c != EOF) back = c; else ++count; break; } ++count; } return count; } size_t CharacterProtocol::load(StringPager *list) { if(!list) return 0; size_t used = 0; size_t size = list->size() - 64; char *tmp = (char *)malloc(size); while(getline(tmp, size)) { if(!list->filter(tmp, size)) break; ++used; } free(tmp); return used; } size_t CharacterProtocol::save(const StringPager *list) { size_t used = 0; if(!list) return 0; StringPager::iterator sp = list->begin(); while(is(sp) && putline(sp->get())) { ++used; sp.next(); } return used; } void BufferProtocol::reset(void) { insize = bufpos = 0; } bool BufferProtocol::eof(void) { if(!input) return true; if(end && bufpos == insize) return true; return false; } bool BufferProtocol::_pending(void) { if(!input) return false; if(!bufpos) return false; return true; } void LockingProtocol::_lock(void) { } void LockingProtocol::_unlock(void) { } LockingProtocol::~LockingProtocol() { } CharacterProtocol::CharacterProtocol() { back = 0; eol = "\n"; } CharacterProtocol::~CharacterProtocol() { } ObjectProtocol::~ObjectProtocol() { } KeyProtocol::~KeyProtocol() { } bool KeyProtocol::equal(const KeyProtocol& key) const { if(keytype() != key.keytype()) return false; if(keysize() != key.keysize() || !keysize()) return false; if(memcmp(keydata(), key.keydata(), keysize())) return false; return true; } ObjectProtocol *ObjectProtocol::copy(void) { retain(); return this; } CharacterProtocol& _character_operators::print(CharacterProtocol& p, const char& c) { p.putchar((int)c); return p; } CharacterProtocol& _character_operators::input(CharacterProtocol& p, char& c) { int code = p.getchar(); if(code == EOF) code = 0; c = code; return p; } CharacterProtocol& _character_operators::print(CharacterProtocol& p, const char *str) { if(!str) p.putline(""); else p.putchars(str); return p; } CharacterProtocol& _character_operators::input(CharacterProtocol& p, String& str) { if(str.c_mem()) { p.getline(str.c_mem(), str.size()); String::fix(str); } return p; } CharacterProtocol& _character_operators::print(CharacterProtocol& p, const long& v) { char buf[40]; snprintf(buf, sizeof(buf), "%ld", v); p.putchars(buf); return p; } CharacterProtocol& _character_operators::print(CharacterProtocol& p, const double& v) { char buf[40]; snprintf(buf, sizeof(buf), "%f", v); p.putchars(buf); return p; } class __LOCAL _input_long : public InputProtocol { public: long* ref; size_t pos; char buf[32]; _input_long(long& v); int _input(int code); }; class __LOCAL _input_double : public InputProtocol { public: double* ref; bool dot; bool e; size_t pos; char buf[60]; _input_double(double& v); int _input(int code); }; _input_long::_input_long(long& v) { ref = &v; v = 0l; pos = 0; } _input_double::_input_double(double& v) { dot = e = false; v = 0.0; pos = 0; ref = &v; } int _input_long::_input(int code) { if(code == '-' && !pos) goto valid; if(isdigit(code) && pos < sizeof(buf) - 1) goto valid; buf[pos] = 0; if(pos) sscanf(buf, "%ld", ref); return code; valid: buf[pos++] = code; return 0; } int _input_double::_input(int code) { if((code == '-') && !pos) goto valid; if((code == '-') && buf[pos] == 'e') goto valid; if(tolower(code) == 'e' && !e) { e = true; code = 'e'; goto valid; } if((code == '.') && !dot) { dot = true; goto valid; } if(isdigit(code) && pos < sizeof(buf) - 1) goto valid; buf[pos] = 0; if(pos) sscanf(buf, "%lf", ref); return code; valid: buf[pos++] = code; return 0; } CharacterProtocol& _character_operators::input(CharacterProtocol& p, long& v) { _input_long lv(v); p.input(lv); return p; } CharacterProtocol& _character_operators::input(CharacterProtocol& p, double& v) { _input_double lv(v); p.input(lv); return p; } PrintProtocol::~PrintProtocol() { } InputProtocol::~InputProtocol() { } } // namespace ucommon ucommon-6.4.4/corelib/memory.cpp0000664000175000017500000007525212555235012013573 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #ifdef HAVE_STDALIGN_H #include #endif #if !defined(HAVE_ALIGNED_ALLOC) && defined(_MSC_VER) && _MSC_VER >= 1800 #include #define HAVE_ALIGNED_ALLOC 1 #define aligned_alloc(a, s) _aligned_malloc(s, a) #endif namespace ucommon { extern "C" { static int ncompare(const void *o1, const void *o2) { assert(o1 != NULL); assert(o2 != NULL); const StringPager::member * const *n1 = static_cast(o1); const StringPager::member * const *n2 = static_cast(o2); return String::collate((*n1)->get(), (*n2)->get()); } } void memalloc::assign(memalloc& source) { memalloc::purge(); pagesize = source.pagesize; align = source.align; count = source.count; page = source.page; limit = source.limit; source.count = 0; source.page = NULL; } memalloc::memalloc(size_t ps) { #ifdef HAVE_SYSCONF size_t paging = sysconf(_SC_PAGESIZE); #elif defined(PAGESIZE) size_t paging = PAGESIZE; #elif defined(PAGE_SIZE) size_t paging = PAGE_SIZE; #else size_t paging = 1024; #endif if(!ps) ps = paging; else if(ps > paging) ps = (((ps + paging - 1) / paging)) * paging; #ifdef HAVE_POSIX_MEMALIGN if(ps >= paging) align = sizeof(void *); else align = 0; switch(align) { case 2: case 4: case 8: case 16: break; default: align = 0; } #endif pagesize = ps; count = 0; limit = 0; page = NULL; } memalloc::~memalloc() { memalloc::purge(); } unsigned memalloc::utilization(void) const { unsigned long used = 0, alloc = 0; page_t *mp = page; while(mp) { alloc += (unsigned long)pagesize; used += mp->used; mp = mp->next; } if(!used) return 0; alloc /= 100; used /= alloc; return used; } void memalloc::purge(void) { page_t *next; while(page) { next = page->next; free(page); page = next; } count = 0; } void memalloc::fault(void) const { cpr_runtime_error("mempager exhausted"); } memalloc::page_t *memalloc::pager(void) { page_t *npage = NULL; #ifdef HAVE_POSIX_MEMALIGN void *addr; #endif if(limit && count >= limit) fault(); #if defined(HAVE_POSIX_MEMALIGN) if(align && !posix_memalign(&addr, align, pagesize)) { npage = (page_t *)addr; goto use; } #elif defined(HAVE_ALIGNED_ALLOC) if(align) { npage = (page_t *)aligned_alloc(align, pagesize); goto use; } #endif npage = (page_t *)malloc(pagesize); #if defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_ALIGNED_ALLOC) use: #endif if (!npage) { fault(); return NULL; } ++count; npage->used = sizeof(page_t); npage->next = page; page = npage; if((size_t)(npage) % sizeof(void *)) npage->used += sizeof(void *) - ((size_t)(npage) % sizeof(void *)); return npage; } void *memalloc::_alloc(size_t size) { assert(size > 0); caddr_t mem; page_t *p = page; if(size > (pagesize - sizeof(page_t))) { fault(); return NULL; } while(size % sizeof(void *)) ++size; while(p) { if(size <= pagesize - p->used) break; p = p->next; } if(!p) p = pager(); mem = ((caddr_t)(p)) + p->used; p->used += (unsigned)size; return mem; } mempager::mempager(size_t ps) : memalloc(ps) { pthread_mutex_init(&mutex, NULL); } mempager::~mempager() { memalloc::purge(); pthread_mutex_destroy(&mutex); } void mempager::_lock(void) { pthread_mutex_lock(&mutex); } void mempager::_unlock(void) { pthread_mutex_unlock(&mutex); } unsigned mempager::utilization(void) { unsigned long used; pthread_mutex_lock(&mutex); used = memalloc::utilization(); pthread_mutex_unlock(&mutex); return used; } void mempager::purge(void) { pthread_mutex_lock(&mutex); memalloc::purge(); pthread_mutex_unlock(&mutex); } void mempager::dealloc(void *mem) { } void *mempager::_alloc(size_t size) { assert(size > 0); void *mem; pthread_mutex_lock(&mutex); mem = memalloc::_alloc(size); pthread_mutex_unlock(&mutex); return mem; } void mempager::assign(mempager& source) { pthread_mutex_lock(&source.mutex); pthread_mutex_lock(&mutex); memalloc::assign(source); pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&source.mutex); } ObjectPager::member::member(LinkedObject **root) : LinkedObject(root) { mem = NULL; } ObjectPager::member::member() : LinkedObject() { mem = NULL; } ObjectPager::ObjectPager(size_t objsize, size_t size) : memalloc(size) { members = 0; root = NULL; last = NULL; index = NULL; typesize = objsize; } void ObjectPager::assign(ObjectPager& source) { members = source.members; root = source.root; last = source.last; index = source.index; typesize = source.typesize; memalloc::assign(source); source.members = 0; source.root = NULL; source.last = NULL; source.index = NULL; } void *ObjectPager::get(unsigned ind) const { linked_pointer list = root; if(ind >= members) return invalid(); while(ind--) list.next(); return list->mem; } void ObjectPager::clear(void) { memalloc::purge(); members = 0; root = NULL; last = NULL; index = NULL; } void *ObjectPager::pull(void) { if(!members) return invalid(); member *mem = (member *)root; void *result = mem->mem; --members; if(!members) { root = NULL; last = NULL; } else root = mem->Next; index = NULL; return result; } void *ObjectPager::push(void) { void *mem = memalloc::_alloc(sizeof(member)); member *node; node = new(mem) member(&root); if (!node) return NULL; if(!last) last = node; ++members; node->mem = memalloc::_alloc(typesize); index = NULL; return node->mem; } void *ObjectPager::pop(void) { void *out = NULL; if(!root) return invalid(); index = NULL; if(root == last) { out = last->mem; root = last = NULL; members = 0; return out; } linked_pointer np = root; while(is(np)) { if(np->Next == last) { out = last->mem; last = *np; np->Next = NULL; --members; break; } np.next(); } return out; } void *ObjectPager::invalid(void) const { return NULL; } void *ObjectPager::add(void) { void *mem = memalloc::_alloc(sizeof(member)); member *node; index = NULL; if(members++) { node = new(mem) member(); last->set(node); } else node = new(mem) member(&root); last = node; node->mem = memalloc::_alloc(typesize); return node->mem; } void **ObjectPager::list(void) { void **dp = index; if(dp) return dp; unsigned pos = 0; index = (void **)memalloc::_alloc(sizeof(void *) * (members + 1)); linked_pointer mp = root; while(is(mp)) { index[pos++] = mp->mem; mp.next(); } index[pos] = NULL; return index; } StringPager::member::member(LinkedObject **root, const char *data) : LinkedObject(root) { text = data; } StringPager::member::member(const char *data) : LinkedObject() { text = data; } StringPager::StringPager(size_t size) : memalloc(size) { members = 0; root = NULL; last = NULL; index = NULL; } void StringPager::assign(StringPager& source) { members = source.members; root = source.root; last = source.last; index = source.index; memalloc::assign(source); source.members = 0; source.root = NULL; source.last = NULL; source.index = NULL; } StringPager::StringPager(char **list, size_t size) : memalloc(size) { members = 0; root = NULL; last = NULL; add(list); } bool StringPager::filter(char *buffer, size_t size) { add(buffer); return true; } unsigned StringPager::token(const char *text, const char *list, const char *quote, const char *end) { unsigned count = 0; const char *result; char *lastp = NULL; if(!text || !*text) return 0; strdup_t tmp = strdup(text); while(NULL != (result = String::token(tmp, &lastp, list, quote, end))) { ++count; add(result); } return count; } String StringPager::join(const char *prefix, const char *middle, const char *suffix) { string_t tmp; if(!members) return tmp; if(prefix && *prefix) tmp += prefix; linked_pointer mp = root; while(is(mp)) { tmp += mp->text; if(mp->Next && middle && *middle) tmp += middle; else if(mp->Next == NULL && suffix && *suffix) tmp += suffix; mp.next(); } return tmp; } unsigned StringPager::split(const char *text, const char *string, unsigned flags) { strdup_t tmp = String::dup(string); char *match = tmp; char *prior = tmp; size_t tcl = strlen(text); unsigned count = 0; bool found = false; // until end of string or end of matches... while(prior && *prior && match) { #if defined(_MSWINDOWS_) if((flags & 0x01) == String::INSENSITIVE) match = strstr(prior, text); #elif defined(HAVE_STRICMP) if((flags & 0x01) == String::INSENSITIVE) match = stristr(prior, text); #else if((flags & 0x01) == String::INSENSITIVE) match = strcasestr(prior, text); #endif else match = strstr(prior, text); if(match) found = true; // we must have at least one match to add trailing data... if(match == NULL && prior != NULL && found) { ++count; add(prior); } // if we have a current match see if anything to add in front of it else if(match) { *match = 0; if(match > prior) { ++count; add(prior); } prior = match + tcl; } } return count; } void StringPager::set(unsigned ind, const char *text) { linked_pointer list = root; if(ind >= members) while(ind--) list.next(); size_t size = strlen(text) + 1; char *str = (char *)memalloc::_alloc(size); #ifdef HAVE_STRLCPY strlcpy(str, text, size); #else strcpy(str, text); #endif list->text = str; } const char *StringPager::invalid(void) const { return NULL; } const char *StringPager::get(unsigned ind) const { linked_pointer list = root; if(ind >= members) return invalid(); while(ind--) list.next(); return list->get(); } void StringPager::clear(void) { memalloc::purge(); members = 0; root = NULL; last = NULL; index = NULL; } const char *StringPager::pull(void) { if(!members) return invalid(); member *mem = (member *)root; const char *result = mem->text; --members; if(!members) { root = NULL; last = NULL; } else root = mem->Next; index = NULL; return result; } void StringPager::push(const char *text) { if(!text) text = ""; size_t size = strlen(text) + 1; void *mem = memalloc::_alloc(sizeof(member)); char *str = (char *)memalloc::_alloc(size); #ifdef HAVE_STRLCPY strlcpy(str, text, size); #else strcpy(str, text); #endif member *node; node = new(mem) member(&root, str); if(!last) last = node; ++members; index = NULL; } const char *StringPager::pop(void) { const char *out = NULL; if(!root) return invalid(); index = NULL; if(root == last) { out = last->text; root = last = NULL; members = 0; return out; } linked_pointer np = root; while(is(np)) { if(np->Next == last) { out = last->text; last = *np; np->Next = NULL; --members; break; } np.next(); } return out; } void StringPager::add(const char *text) { if(!text) text = ""; size_t size = strlen(text) + 1; void *mem = memalloc::_alloc(sizeof(member)); char *str = (char *)memalloc::_alloc(size); #ifdef HAVE_STRLCPY strlcpy(str, text, size); #else strcpy(str, text); #endif member *node; index = NULL; if(members++) { node = new(mem) member(str); last->set(node); } else node = new(mem) member(&root, str); last = node; } void StringPager::set(char **list) { clear(); add(list); } void StringPager::push(char **list) { const char *cp; unsigned ind = 0; if(!list) return; while(NULL != (cp = list[ind++])) push(cp); } void StringPager::add(char **list) { const char *cp; unsigned ind = 0; if(!list) return; while(NULL != (cp = list[ind++])) add(cp); } void StringPager::sort(void) { if(!members) return; unsigned count = members; member **list = new member*[members]; unsigned pos = 0; linked_pointer mp = root; while(is(mp) && count--) { list[pos++] = *mp; mp.next(); } qsort(static_cast(list), members, sizeof(member *), &ncompare); root = NULL; while(pos) list[--pos]->enlist(&root); delete[] list; index = NULL; } char **StringPager::list(void) { if(index) return index; unsigned pos = 0; index = (char **)memalloc::_alloc(sizeof(char *) * (members + 1)); linked_pointer mp = root; while(is(mp)) { index[pos++] = (char *)mp->text; mp.next(); } index[pos] = NULL; return index; } DirPager::DirPager() : StringPager() { dir = NULL; } void DirPager::assign(DirPager& source) { dir = source.dir; StringPager::assign(source); source.dir = NULL; } DirPager::DirPager(const char *path) : StringPager() { dir = NULL; load(path); } bool DirPager::filter(char *fname, size_t size) { if(*fname != '.') add(fname); return true; } void DirPager::operator=(const char *path) { dir = NULL; clear(); load(path); } bool DirPager::load(const char *path) { dir_t ds; char buffer[128]; if(!fsys::is_dir(path)) return false; dir = dup(path); ds.open(path); if(!ds) return false; while(ds.read(buffer, sizeof(buffer)) > 0) { if(!filter(buffer, sizeof(buffer))) break; } ds.close(); sort(); return true; } autorelease::autorelease() { pool = NULL; } autorelease::~autorelease() { release(); } void autorelease::release() { LinkedObject *obj; while(pool) { obj = pool; pool = obj->getNext(); obj->release(); } } void autorelease::operator+=(LinkedObject *obj) { assert(obj != NULL); obj->enlist(&pool); } PagerObject::PagerObject() : LinkedObject(NULL), CountedObject() { } void PagerObject::reset(void) { CountedObject::reset(); LinkedObject::Next = NULL; } void PagerObject::dealloc(void) { pager->put(this); } void PagerObject::release(void) { CountedObject::release(); } PagerPool::PagerPool() { freelist = NULL; pthread_mutex_init(&mutex, NULL); } PagerPool::~PagerPool() { pthread_mutex_destroy(&mutex); } void PagerPool::put(PagerObject *ptr) { assert(ptr != NULL); pthread_mutex_lock(&mutex); ptr->enlist(&freelist); pthread_mutex_unlock(&mutex); } PagerObject *PagerPool::get(size_t size) { assert(size > 0); PagerObject *ptr; pthread_mutex_lock(&mutex); ptr = static_cast(freelist); if(ptr) freelist = ptr->Next; pthread_mutex_unlock(&mutex); if(!ptr) ptr = new((_alloc(size))) PagerObject; else ptr->reset(); if (ptr) ptr->pager = this; return ptr; } keyassoc::keydata::keydata(keyassoc *assoc, const char *kid, unsigned max, unsigned bufsize) : NamedObject(assoc->root, strdup(kid), max) { assert(assoc != NULL); assert(kid != NULL && *kid != 0); assert(max > 1); String::set(text, bufsize, kid); data = NULL; Id = text; } keyassoc::keyassoc(unsigned pathmax, size_t strmax, size_t ps) : mempager(ps) { assert(pathmax > 1); assert(strmax > 1); assert(ps > 1); paths = pathmax; keysize = strmax; keycount = 0; root = (NamedObject **)_alloc(sizeof(NamedObject *) * pathmax); memset(root, 0, sizeof(NamedObject *) * pathmax); if(keysize) { list = (LinkedObject **)_alloc(sizeof(LinkedObject *) * (keysize / 8)); memset(list, 0, sizeof(LinkedObject *) * (keysize / 8)); } else list = NULL; } keyassoc::~keyassoc() { purge(); } void keyassoc::purge(void) { mempager::purge(); list = NULL; root = NULL; } void *keyassoc::locate(const char *id) { assert(id != NULL && *id != 0); keydata *kd; _lock(); kd = static_cast(NamedObject::map(root, id, paths)); _unlock(); if(!kd) return NULL; return kd->data; } void *keyassoc::remove(const char *id) { assert(id != NULL && *id != 0); keydata *kd; LinkedObject *obj; void *data; unsigned path = NamedObject::keyindex(id, paths); unsigned size = (unsigned)strlen(id); if(!keysize || size >= keysize || !list) return NULL; _lock(); kd = static_cast(NamedObject::map(root, id, paths)); if(!kd) { _unlock(); return NULL; } data = kd->data; obj = static_cast(kd); obj->delist((LinkedObject**)(&root[path])); obj->enlist(&list[size / 8]); --keycount; _unlock(); return data; } void *keyassoc::allocate(const char *id, size_t dsize) { assert(id != NULL && *id != 0); assert(dsize != 0); void *dp = NULL; keydata *kd; LinkedObject *obj; unsigned size = (unsigned)strlen(id); if(keysize && size >= keysize) return NULL; _lock(); kd = static_cast(NamedObject::map(root, id, paths)); if(kd) { _unlock(); return NULL; } void *ptr = NULL; size /= 8; if(list && list[size]) { obj = list[size]; list[size] = obj->getNext(); ptr = obj; } if(ptr == NULL) { ptr = memalloc::_alloc(sizeof(keydata) + size * 8); dp = memalloc::_alloc(dsize); } else dp = ((keydata *)(ptr))->data; kd = new(ptr) keydata(this, id, paths, 8 + size * 8); if (kd) kd->data = dp; else dp = NULL; ++keycount; _unlock(); return dp; } bool keyassoc::create(const char *id, void *data) { assert(id != NULL && *id != 0); assert(data != NULL); keydata *kd; LinkedObject *obj; unsigned size = (unsigned)strlen(id); if(keysize && size >= keysize) return false; _lock(); kd = static_cast(NamedObject::map(root, id, paths)); if(kd) { _unlock(); return false; } void *ptr = NULL; size /= 8; if(list && list[size]) { obj = list[size]; list[size] = obj->getNext(); ptr = obj; } if(ptr == NULL) ptr = memalloc::_alloc(sizeof(keydata) + size * 8); kd = new(ptr) keydata(this, id, paths, 8 + size * 8); bool rtn = true; if (kd) kd->data = data; else rtn = false; ++keycount; _unlock(); return rtn; } bool keyassoc::assign(const char *id, void *data) { assert(id != NULL && *id != 0); assert(data != NULL); keydata *kd; LinkedObject *obj; unsigned size = (unsigned)strlen(id); if(keysize && size >= keysize) return false; _lock(); kd = static_cast(NamedObject::map(root, id, paths)); if(!kd) { caddr_t ptr = NULL; size /= 8; if(list && list[size]) { obj = list[size]; list[size] = obj->getNext(); ptr = (caddr_t)obj; } if(ptr == NULL) ptr = (caddr_t)memalloc::_alloc(sizeof(keydata) + size * 8); kd = new(ptr) keydata(this, id, paths, 8 + size * 8); ++keycount; } bool rtn = true; if (kd) kd->data = data; else rtn = false; _unlock(); return rtn; } chartext::chartext() : CharacterProtocol() { pos = NULL; max = 0; } chartext::chartext(char *buf) : CharacterProtocol() { pos = buf; max = 0; } chartext::chartext(char *buf, size_t size) : CharacterProtocol() { pos = buf; max = size; } chartext::~chartext() { } int chartext::_getch(void) { if(!pos || !*pos || max) return EOF; return *(pos++); } int chartext::_putch(int code) { if(!pos || !max) return EOF; if(code == 0) { *(pos++) = 0; max = 0; return EOF; } *(pos++) = code; *pos = 0; --max; return code; } bufpager::bufpager(size_t ps) : memalloc(ps), CharacterProtocol() { first = last = current = freelist = NULL; ccount = 0; cpos = 0; eom = false; } void bufpager::assign(bufpager& source) { first = source.first; last = source.last; current = source.current; freelist = source.freelist; ccount = source.ccount; cpos = source.cpos; eom = source.eom; memalloc::assign(source); source.first = source.last = source.current = source.freelist = NULL; source.ccount = 0; source.cpos = 0; source.eom = false; } void bufpager::set(const char *text) { reset(); add(text); } void bufpager::put(const char *text, size_t iosize) { if(eom) return; while(text && (iosize--)) { if(!last || last->used == last->size) { cpage_t *next; if(freelist) { next = freelist; freelist = next->next; } else { next = (cpage_t *)memalloc::_alloc(sizeof(cpage_t)); if(!next) { return; } page_t *p = page; unsigned size = 0; while(p) { size = (unsigned)(pagesize - p->used); if(size) break; p = p->next; } if(!p) p = pager(); if(!p) return; next->text = ((char *)(p)) + p->used; next->used = 0; next->size = size; p->used = (unsigned)pagesize; } if(last) last->next = next; if(!first) first = next; last = next; } ++ccount; last->text[last->used++] = *(text++); } } char *bufpager::copy(size_t *iosize) { char *result = NULL; *iosize = 0; if(!current || (current->next == NULL && cpos >= current->used)) return NULL; if(cpos >= current->used) { current = current->next; cpos = 0l; } if(current) { result = current->text + cpos; *iosize = current->used - cpos; } else *iosize = 0l; cpos = 0l; if(current) current = current->next; return result; } char *bufpager::request(size_t *iosize) { if(eom) return NULL; *iosize = 0; if(!last || last->used >= last->size) { cpage_t *next; if(freelist) { next = freelist; freelist = next->next; } else { next = (cpage_t *)memalloc::_alloc(sizeof(cpage_t)); if(!next) { eom = true; return NULL; } page_t *p = page; unsigned size = 0; while(p) { size = (unsigned)(pagesize - p->used); if(size) break; p = p->next; } if(!p) p = pager(); if(!p) { eom = true; return NULL; } next->text = ((char *)(p)) + p->used; next->used = 0; next->size = size; p->used = (unsigned)pagesize; } if(last) last->next = next; if(!first) first = next; last = next; } *iosize = last->size - last->used; return last->text + last->used; } void bufpager::update(size_t iosize) { last->used += (unsigned)iosize; } size_t bufpager::get(char *text, size_t iosize) { if(!ccount) return 0; unsigned long index = 0; while(index < iosize && current) { if(cpos >= current->used) { if(!current->next) break; current = current->next; cpos = 0l; } text[index++] = current->text[cpos++]; } if(index < iosize) text[index] = 0; return index; } void bufpager::add(const char *text) { if(eom) return; while(text && *text) { if(!last || last->used == last->size) { cpage_t *next; if(freelist) { next = freelist; freelist = next->next; } else { next = (cpage_t *)memalloc::_alloc(sizeof(cpage_t)); if(!next) { eom = true; return; } page_t *p = page; unsigned size = 0; while(p) { size = (unsigned)(pagesize - p->used); if(size) break; p = p->next; } if(!p) p = pager(); if(!p) { eom = true; return; } next->text = ((char *)(p)) + p->used; next->used = 0; next->size = size; p->used = (unsigned)pagesize; } if(last) last->next = next; if(!first) first = next; last = next; } ++ccount; last->text[last->used++] = *(text++); } } char *bufpager::dup(void) { if(!ccount) return NULL; char *text = (char *)malloc(ccount + 1l); if(!text) return NULL; unsigned long index = 0, pos = 0; cpage_t *cpage = first; while(index < ccount && cpage) { if(pos >= cpage->used) { if(!cpage->next) break; cpage = cpage->next; pos = 0l; } text[index++] = cpage->text[pos++]; } text[index] = 0; return text; } int bufpager::_getch(void) { if(!current) current = first; if(!current) return EOF; if(cpos >= current->used) { if(!current->next) return EOF; current = current->next; cpos = 0; } if(cpos >= current->used) return EOF; char ch = current->text[cpos++]; return ch; } int bufpager::_putch(int code) { if(eom) return EOF; if(!last || last->used == last->size) { cpage_t *next; if(freelist) { next = freelist; freelist = next->next; } else { next = (cpage_t *)memalloc::_alloc(sizeof(cpage_t)); if(!next) { eom = true; return EOF; } page_t *p = page; unsigned size = 0; while(p) { size = (unsigned)(pagesize - p->used); if(size) break; p = p->next; } if(!p) p = pager(); if(!p) { eom = true; return EOF; } next->text = ((char *)(p)) + p->used; next->used = 0; next->size = size; p->used = (unsigned)pagesize; } if(last) last->next = next; if(!first) first = next; last = next; } ++ccount; last->text[last->used++] = code; if(code == 0) { eom = true; return EOF; } return code; } void *bufpager::_alloc(size_t size) { void *ptr = memalloc::_alloc(size); return ptr; } void bufpager::rewind(void) { cpos = 0; current = first; } void bufpager::reset(void) { eom = false; cpos = 0; ccount = 0; current = first; while(current) { current->used = 0; current = current->next; } freelist = first; first = last = current = NULL; } charmem::charmem(char *memaddr, size_t memsize) : CharacterProtocol() { dynamic = false; buffer = NULL; set(memaddr, memsize); } charmem::charmem(size_t memsize) { buffer = NULL; set(size); } charmem::charmem() { buffer = NULL; dynamic = false; inp = out = size = 0; } charmem::~charmem() { release(); } void charmem::set(size_t total) { release(); buffer = (char *)malloc(total); size = total; inp = out = 0; if (buffer) buffer[0] = 0; } void charmem::set(char *mem, size_t total) { release(); if(!mem) { buffer = NULL; inp = out = size = 0; return; } buffer = mem; size = total; inp = 0; out = strlen(mem); } void charmem::release(void) { if(buffer && dynamic) free(buffer); buffer = NULL; dynamic = false; } int charmem::_getch(void) { if(!buffer || inp == size || buffer[inp] == 0) return EOF; return buffer[inp++]; } int charmem::_putch(int code) { if(!buffer || out > size - 1) return EOF; buffer[out++] = code; if(code == 0) { out = size; return EOF; } buffer[out] = 0; return code; } } // namespace ucommon ucommon-6.4.4/corelib/cpr.cpp0000644000175000001440000001176612504370234013041 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #ifndef UCOMMON_SYSRUNTIME #include #endif #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #ifdef _MSWINDOWS_ int cpr_setenv(const char *sym, const char *val, int flag) { char buf[128]; if(!flag) { if(GetEnvironmentVariable(sym, buf, sizeof(buf)) > 0) return 0; if(GetLastError() != ERROR_ENVVAR_NOT_FOUND) return -1; } if(SetEnvironmentVariable(sym, val) == 0) return -1; return 0; } #endif void cpr_runtime_error(const char *str) { assert(str != NULL); #ifndef UCOMMON_SYSRUNTIME throw std::runtime_error(str); #endif abort(); } // just become we need to get binary types in a specific binary endian order. extern "C" uint16_t lsb_getshort(uint8_t *b) { assert(b != NULL); return (b[1] * 256) + b[0]; } extern "C" uint32_t lsb_getlong(uint8_t *b) { assert(b != NULL); return (b[3] * 16777216l) + (b[2] * 65536l) + (b[1] * 256) + b[0]; } extern "C" uint16_t msb_getshort(uint8_t *b) { assert(b != NULL); return (b[0] * 256) + b[1]; } extern "C" uint32_t msb_getlong(uint8_t *b) { assert(b != NULL); return (b[0] * 16777216l) + (b[1] * 65536l) + (b[2] * 256) + b[3]; } extern "C" void lsb_setshort(uint8_t *b, uint16_t v) { assert(b != NULL); b[0] = v & 0x0ff; b[1] = (v / 256) & 0xff; } extern "C" void msb_setshort(uint8_t *b, uint16_t v) { assert(b != NULL); b[1] = v & 0x0ff; b[0] = (v / 256) & 0xff; } // oh, and we have to be able to set them in order too... extern "C" void lsb_setlong(uint8_t *b, uint32_t v) { assert(b != NULL); b[0] = (uint8_t)(v & 0x0ff); b[1] = (uint8_t)((v / 256) & 0xff); b[2] = (uint8_t)((v / 65536l) & 0xff); b[3] = (uint8_t)((v / 16777216l) & 0xff); } extern "C" void msb_setlong(uint8_t *b, uint32_t v) { assert(b != NULL); b[3] = (uint8_t)(v & 0x0ff); b[2] = (uint8_t)((v / 256) & 0xff); b[1] = (uint8_t)((v / 65536l) & 0xff); b[0] = (uint8_t)((v / 16777216l) & 0xff); } extern "C" void *cpr_newp(void **handle, size_t size) { assert(handle != NULL); if(*handle) free(*handle); *handle = malloc(size); return *handle; } extern "C" void cpr_freep(void **handle) { assert(handle != NULL); if(*handle) { free(*handle); *handle = NULL; } } extern "C" void cpr_memswap(void *s1, void *s2, size_t size) { assert(s1 != NULL); assert(s2 != NULL); assert(size > 0); char *buf = new char[size]; memcpy(buf, s1, size); memcpy(s1, s2, size); memcpy(s2, buf, size); delete[] buf; } // if malloc ever fails, we probably should consider that a critical error and // kill the leaky dingy, which this does for us here.. extern "C" void *cpr_memalloc(size_t size) { void *mem; if(!size) ++size; mem = malloc(size); crit(mem != NULL, "memory alloc failed"); return mem; } extern "C" void *cpr_memassign(size_t size, caddr_t addr, size_t max) { assert(addr); crit((size <= max), "memory assign failed"); return addr; } #ifdef UCOMMON_SYSRUNTIME #ifdef __GNUC__ // here we have one of those magic things in gcc, and what to do when // we have an unimplemented virtual function if we build ucommon without // a stdc++ runtime library. extern "C" void __cxa_pure_virtual(void) { abort(); } #endif void *operator new(size_t size) { return cpr_memalloc(size); } void *operator new[](size_t size) { return cpr_memalloc(size); } void *operator new[](size_t size, void *address) { return cpr_memassign(size, address, size); } void *operator new[](size_t size, void *address, size_t known) { return cpr_memassign(size, address, known); } #if __cplusplus <= 199711L void operator delete(void *object) #else void operator delete(void *object) noexcept (true) #endif { free(object); } #if __cplusplus <= 199711L void operator delete[](void *array) #else void operator delete[](void *array) noexcept(true) #endif { free(array); } #endif ucommon-6.4.4/corelib/tcpbuffer.cpp0000664000175000017500000000714112544757717014256 00000000000000// Copyright (C) 2010-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include #include #include namespace ucommon { TCPBuffer::TCPBuffer() : BufferProtocol() { so = INVALID_SOCKET; } TCPBuffer::TCPBuffer(const char *host, const char *service, size_t size) : BufferProtocol() { so = INVALID_SOCKET; open(host, service, size); } TCPBuffer::TCPBuffer(const TCPServer *server, size_t size) : BufferProtocol() { so = INVALID_SOCKET; open(server, size); } TCPBuffer::~TCPBuffer() { TCPBuffer::close(); } void TCPBuffer::open(const char *host, const char *service, size_t size) { struct addrinfo *list = Socket::query(host, service, SOCK_STREAM, 0); if(!list) return; so = Socket::create(list, SOCK_STREAM, 0); Socket::release(list); if(so == INVALID_SOCKET) return; _buffer(size); } void TCPBuffer::open(const TCPServer *server, size_t size) { close(); so = server->accept(); if(so == INVALID_SOCKET) return; _buffer(size); } void TCPBuffer::close(void) { if(so == INVALID_SOCKET) return; BufferProtocol::release(); Socket::release(so); so = INVALID_SOCKET; } void TCPBuffer::_buffer(size_t size) { unsigned iobuf = 0; unsigned mss = (unsigned)size; unsigned max = 0; #ifdef TCP_MAXSEG socklen_t alen = sizeof(max); #endif if(size < 80) { allocate(size); return; } #ifdef TCP_MAXSEG if(mss) setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&max, sizeof(max)); getsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&max, &alen); #endif if(max && max < mss) mss = max; if(mss) { if(mss < 80) mss = 80; if(mss * 7 < 64000u) iobuf = mss * 7; else if(size * 6 < 64000u) iobuf = mss * 6; else iobuf = mss * 5; Socket::sendsize(so, iobuf); Socket::recvsize(so, iobuf); if(mss < 512) Socket::sendwait(so, mss * 4); } allocate(size); } int TCPBuffer::_err(void) const { return ioerr; } void TCPBuffer::_clear(void) { ioerr = 0; } bool TCPBuffer::_blocking(void) { if(iowait) return true; return false; } size_t TCPBuffer::_push(const char *address, size_t len) { if(ioerr) return 0; return writeto(address, len); } size_t TCPBuffer::_pull(char *address, size_t len) { if (ioerr) return 0; return readfrom(address, len); } bool TCPBuffer::_pending(void) { if(input_pending()) return true; if(is_input() && iowait && iowait != Timer::inf) return Socket::wait(so, iowait); return Socket::wait(so, 0); } } // namespace ucommon ucommon-6.4.4/corelib/mapped.cpp0000664000175000017500000003127612551014424013525 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include #include #ifdef HAVE_FCNTL_H #include #endif #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_MMAN_H #undef __EXTENSIONS__ #define __EXTENSIONS__ #ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200112L #include #undef _POSIX_C_SOURCE #else #include #endif #include #endif #ifdef HAVE_FTOK #include #ifdef HAVE_SYS_SHM_H #include #endif #endif #include #include #include #if _POSIX_PRIORITY_SCHEDULING > 0 #include #endif #if defined(__APPLE__) && defined(__MACH__) #define INSERT_OFFSET 16 #endif #ifndef INSERT_OFFSET #define INSERT_OFFSET 0 #endif #if defined(__FreeBSD__) #undef HAVE_SHM_OPEN #endif #if defined(__ANDROID__) #include #include #include #include #define ASHMEM_DEVICE "/dev/ashmem" static int shmget(key_t key, size_t size, int shmflg) { int fd, ret; char key_str[11]; fd = open(ASHMEM_DEVICE, O_RDWR); if (fd < 0) return fd; sprintf(key_str, "%d", key); ret = ioctl(fd, ASHMEM_SET_NAME, key_str); if (ret < 0) goto error; ret = ioctl(fd, ASHMEM_SET_SIZE, size); if (ret < 0) goto error; return fd; error: close(fd); return ret; } static int shmctl(int shmid, int cmd, struct shmid_ds *buf) { int ret = 0; if (cmd == IPC_RMID) { int length = ioctl(shmid, ASHMEM_GET_SIZE, NULL); struct ashmem_pin pin = {0, length}; ret = ioctl(shmid, ASHMEM_UNPIN, &pin); close(shmid); } return ret; } static void *shmat(int shmid, const void *shmaddr, int shmflg) { size_t *ptr, size = ioctl(shmid, ASHMEM_GET_SIZE, NULL); ptr = (size_t *) mmap(NULL, size + sizeof(size_t), PROT_READ | PROT_WRITE, MAP_SHARED, shmid, 0); *ptr = size; // save size at beginning of buffer, for use with munmap return (void *) &ptr[1]; } static int shmdt(const void *shmaddr) { size_t *ptr, size; ptr = (size_t *) shmaddr; ptr--; size = *ptr; // find mmap size which we stored at the beginning of the buffer return munmap((void *) ptr, size + sizeof(size_t)); } #endif #if defined(HAVE_FTOK) && !defined(HAVE_SHM_OPEN) static void ftok_name(const char *name, char *buf, size_t max) { assert(name != NULL && *name != 0); assert(buf != NULL); assert(max > 0); struct stat ino; if(*name == '/') ++name; if(!stat("/var/run/ipc", &ino) && S_ISDIR(ino.st_mode)) snprintf(buf, max, "/var/run/ipc/%s", name); else snprintf(buf, max, "/tmp/.%s.ipc", name); } static key_t createipc(const char *name, char mode) { assert(name != NULL && *name != 0); char buf[65]; int fd; ftok_name(name, buf, sizeof(buf)); fd = ::open(buf, O_CREAT | O_EXCL | O_WRONLY, 0664); if(fd > -1) ::close(fd); return ftok(buf, mode); } static key_t accessipc(const char *name, char mode) { assert(name != NULL && *name != 0); char buf[65]; ftok_name(name, buf, sizeof(buf)); return ftok(buf, mode); } #endif static bool use_mapping = true; namespace ucommon { void MappedMemory::disable(void) { use_mapping = false; } MappedMemory::MappedMemory(const char *fn, size_t len) { assert(fn != NULL && *fn != 0); assert(len > 0); size = len; erase = true; String::set(idname, sizeof(idname), fn); create(fn, size); } MappedMemory::MappedMemory(const char *fn) { erase = false; assert(fn != NULL && *fn != 0); create(fn, 0); } MappedMemory::MappedMemory() { erase = false; size = 0; used = 0; map = NULL; } #if defined(_MSWINDOWS_) void MappedMemory::create(const char *fn, size_t len) { assert(fn != NULL && *fn != 0); int share = FILE_SHARE_READ; // int prot = FILE_MAP_READ; int mode = GENERIC_READ; size = 0; used = 0; map = NULL; if(!use_mapping) { assert(len > 0); // cannot use dummy for r/o... map = (caddr_t)malloc(len); if(!map) fault(); size = len; return; } if(*fn == '/') ++fn; if(len) { // prot = FILE_MAP_WRITE; mode |= GENERIC_WRITE; share |= FILE_SHARE_WRITE; fd = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)len, fn); } else fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, fn); if(fd == INVALID_HANDLE_VALUE || fd == NULL) return; map = (caddr_t)MapViewOfFile(fd, FILE_MAP_ALL_ACCESS, 0, 0, len); if(map) { size = len; VirtualLock(map, size); } else fault(); } MappedMemory::~MappedMemory() { release(); } void MappedMemory::remove(const char *id) { assert(id != NULL && *id != 0); } void MappedMemory::release(void) { if(map) { if(use_mapping) { VirtualUnlock(map, size); UnmapViewOfFile(fd); CloseHandle(fd); map = NULL; fd = INVALID_HANDLE_VALUE; } else { free(map); map = NULL; } } if(erase) { remove(idname); erase = false; } } #elif defined(HAVE_SHM_OPEN) void MappedMemory::create(const char *fn, size_t len) { assert(fn != NULL && *fn != 0); int prot = PROT_READ; struct stat ino; char fbuf[80]; size = 0; used = 0; if(!use_mapping) { assert(len > 0); map = NULL; if(len) map = (caddr_t)malloc(len); if(!map) fault(); size = mapsize = len; return; } if(*fn != '/') { snprintf(fbuf, sizeof(fbuf), "/%s", fn); fn = fbuf; } if(len) { len += INSERT_OFFSET; prot |= PROT_WRITE; fd = shm_open(fn, O_RDWR | O_CREAT, 0664); if(fd > -1) { if(ftruncate(fd, len)) { ::close(fd); fd = -1; } } } else { fd = shm_open(fn, O_RDONLY, 0664); if(fd > -1) { fstat(fd, &ino); len = ino.st_size; } } if(fd < 0) return; map = (caddr_t)mmap(NULL, len, prot, MAP_SHARED, fd, 0); if(!map) fault(); ::close(fd); if(map != (caddr_t)MAP_FAILED) { size = mapsize = len; mlock(map, mapsize); #if INSERT_OFFSET > 0 if(prot & PROT_WRITE) { size -= INSERT_OFFSET; snprintf(map, INSERT_OFFSET, "%ld", size); } else size = atol(map); map += INSERT_OFFSET; #endif } } MappedMemory::~MappedMemory() { release(); } void MappedMemory::release() { if(size) { if(use_mapping) { map -= INSERT_OFFSET; munlock(map, mapsize); munmap(map, mapsize); } else free(map); size = 0; } if(erase) { remove(idname); erase = false; } } void MappedMemory::remove(const char *fn) { assert(fn != NULL && *fn != 0); char fbuf[80]; if(!use_mapping) return; if(*fn != '/') { snprintf(fbuf, sizeof(fbuf), "/%s", fn); fn = fbuf; } shm_unlink(fn); } #else void MappedMemory::remove(const char *name) { assert(name != NULL && *name != 0); key_t key; fd_t fd; if(!use_mapping) return; key = accessipc(name, 'S'); if(key) { fd = shmget(key, 0, 0); if(fd > -1) shmctl(fd, IPC_RMID, NULL); } } void MappedMemory::create(const char *name, size_t len) { assert(name != NULL && *name != 0); struct shmid_ds stat; size = 0; used = 0; key_t key; if(!use_mapping) { assert(len > 0); map = (caddr_t)malloc(len); if(!map) fault(); size = len; return; } if(len) { key = createipc(name, 'S'); remake: fd = shmget(key, len, IPC_CREAT | IPC_EXCL | 0664); if(fd == -1 && errno == EEXIST) { fd = shmget(key, 0, 0); if(fd > -1) { shmctl(fd, IPC_RMID, NULL); goto remake; } } } else { key = accessipc(name, 'S'); fd = shmget(key, 0, 0); } if(fd > -1) { if(len) size = len; else if(shmctl(fd, IPC_STAT, &stat) == 0) size = stat.shm_segsz; else fd = -1; } map = (caddr_t)shmat(fd, NULL, 0); if(!map) fault(); #ifdef SHM_LOCK if(fd > -1) shmctl(fd, SHM_LOCK, NULL); #endif } MappedMemory::~MappedMemory() { release(); } void MappedMemory::release(void) { if(size > 0) { if(use_mapping) { #ifdef SHM_UNLOCK shmctl(fd, SHM_UNLOCK, NULL); #endif shmdt(map); fd = -1; } else free(map); size = 0; } if(erase) { remove(idname); erase = false; } } #endif void *MappedMemory::invalid(void) const { abort(); return NULL; } void MappedMemory::fault(void) const { abort(); } void *MappedMemory::sbrk(size_t len) { assert(len > 0); void *mp = (void *)(map + used); if(used + len > size) fault(); used += len; return mp; } bool MappedMemory::copy(size_t offset, void *buffer, size_t bufsize) const { if(!map || (offset + bufsize > size)) { fault(); return false; } const void *member = (const void *)(map + offset); do { memcpy(buffer, member, bufsize); } while(memcmp(buffer, member, bufsize)); return true; } void *MappedMemory::offset(size_t offset) const { if(offset >= size) return invalid(); return (void *)(map + offset); } MappedReuse::MappedReuse(const char *name, size_t osize, unsigned count) : ReusableAllocator(), MappedMemory(name, osize * count) { assert(name != NULL && *name != 0); assert(osize > 0 && count > 0); objsize = (unsigned)osize; reading = 0; } MappedReuse::MappedReuse(size_t osize) : ReusableAllocator(), MappedMemory() { assert(osize > 0); objsize = (unsigned)osize; reading = 0; } bool MappedReuse::avail(void) const { bool rtn = false; __AUTOLOCK__ if(freelist || used < size) rtn = true; return rtn; } ReusableObject *MappedReuse::request(void) { ReusableObject *obj = NULL; __AUTOLOCK__ if(freelist) { obj = freelist; freelist = next(obj); } else if(used + objsize <= size) obj = (ReusableObject *)sbrk(objsize); return obj; } ReusableObject *MappedReuse::get(void) { return getTimed(Timer::inf); } void MappedReuse::removeLocked(ReusableObject *obj) { assert(obj != NULL); obj->retain(); obj->enlist((LinkedObject **)&freelist); } ReusableObject *MappedReuse::getLocked(void) { ReusableObject *obj = NULL; if(freelist) { obj = freelist; freelist = next(obj); } else if(used + objsize <= size) obj = (ReusableObject *)sbrk(objsize); return obj; } ReusableObject *MappedReuse::getTimed(timeout_t timeout) { bool rtn = true; struct timespec ts; ReusableObject *obj = NULL; if(timeout && timeout != Timer::inf) set(&ts, timeout); __AUTOLOCK__ while(rtn && (!freelist || (freelist && reading)) && used >= size) { ++waiting; if(timeout == Timer::inf) wait(); else if(timeout) rtn = wait(&ts); else rtn = false; --waiting; } if(!rtn) { return NULL; } if(freelist) { obj = freelist; freelist = next(obj); } else if(used + objsize <= size) obj = (ReusableObject *)sbrk(objsize); return obj; } } // namespace ucommon ucommon-6.4.4/corelib/typeref.cpp0000664000175000017500000001332312557431651013741 00000000000000// Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include namespace ucommon { TypeRef::Counted::Counted(void *addr, size_t objsize) : ObjectProtocol() { this->memory = addr; this->size = objsize; } void TypeRef::Counted::dealloc() { delete this; ::free(memory); } void TypeRef::Counted::operator delete(void *addr) { } void TypeRef::Counted::retain(void) { count.fetch_add(); } void TypeRef::Counted::release(void) { if(count.fetch_sub() < 2) { dealloc(); } } TypeRef::TypeRef() { ref = NULL; } TypeRef::TypeRef(TypeRef::Counted *object) { ref = object; if(ref) ref->retain(); } TypeRef::TypeRef(const TypeRef& copy) { ref = copy.ref; if(ref) ref->retain(); } TypeRef::~TypeRef() { release(); } void TypeRef::release(void) { if(ref) ref->release(); ref = NULL; } void TypeRef::set(const TypeRef& ptr) { if(ptr.ref) ptr.ref->retain(); release(); ref = ptr.ref; } void TypeRef::set(TypeRef::Counted *object) { if(object) object->retain(); release(); ref = object; } caddr_t TypeRef::alloc(size_t size) { return (caddr_t)::malloc(size + 16); } caddr_t TypeRef::mem(caddr_t addr) { while(((uintptr_t)addr) & 0xf) ++addr; return addr; } stringref::value::value(caddr_t addr, size_t objsize, const char *str) : TypeRef::Counted(addr, objsize) { if(str) String::set(mem, objsize + 1, str); else mem[0] = 0; } void stringref::value::destroy(void) { count.clear(); release(); } stringref::stringref() : TypeRef() {} stringref::stringref(const stringref& copy) : TypeRef(copy) {} stringref::stringref(const char *str) : TypeRef() { size_t size = 0; if(str) size = strlen(str); caddr_t p = TypeRef::alloc(sizeof(value) + size); TypeRef::set(new(mem(p)) value(p, size, str)); } const char *stringref::operator()(ssize_t offset) const { value *v = polystatic_cast(ref); if(!v) return NULL; if(offset < 0 && offset < -((ssize_t)v->len())) return NULL; if(offset < 0) return &v->mem[v->len() + offset]; if(offset > (ssize_t)v->len()) return NULL; return &v->mem[v->len() + offset]; } const char *stringref::operator*() const { if(!ref) return NULL; value *v = polystatic_cast(ref); return &v->mem[0]; } stringref& stringref::operator=(const stringref& objref) { TypeRef::set(objref); return *this; } stringref& stringref::operator=(const char *str) { set(str); return *this; } void stringref::set(const char *str) { release(); size_t size = 0; if(str) size = strlen(str); caddr_t p = TypeRef::alloc(sizeof(value) + size); TypeRef::set(new(mem(p)) value(p, size, str)); } void stringref::assign(value *chars) { release(); chars->size = strlen(chars->mem); TypeRef::set(chars); } stringref& stringref::operator=(value *chars) { assign(chars); return *this; } stringref::value *stringref::create(size_t size) { caddr_t p = TypeRef::alloc(sizeof(value) + size); return new(mem(p)) value(p, size, NULL); } void stringref::destroy(stringref::value *chars) { if(chars) chars->destroy(); } void stringref::expand(stringref::value **handle, size_t size) { if(!handle || !*handle) return; stringref::value *change = create(size + (*handle)->max()); if(change) String::set(change->get(), change->max() + 1, (*handle)->get()); destroy(*handle); *handle = change; } byteref::value::value(caddr_t addr, size_t objsize, const uint8_t *str) : TypeRef::Counted(addr, objsize) { if(objsize) memcpy(mem, str, objsize); } byteref::value::value(caddr_t addr, size_t size) : TypeRef::Counted(addr, size) { } byteref::byteref() : TypeRef() {} byteref::byteref(const byteref& copy) : TypeRef(copy) {} byteref::byteref(const uint8_t *str, size_t size) : TypeRef() { caddr_t p = TypeRef::alloc(sizeof(value) + size); TypeRef::set(new(mem(p)) value(p, size, str)); } void byteref::value::destroy(void) { count.clear(); release(); } const uint8_t *byteref::operator*() const { if(!ref) return NULL; value *v = polystatic_cast(ref); return &v->mem[0]; } byteref& byteref::operator=(const byteref& objref) { TypeRef::set(objref); return *this; } byteref& byteref::operator=(value *bytes) { assign(bytes); return *this; } void byteref::set(const uint8_t *str, size_t size) { release(); caddr_t p = TypeRef::alloc(sizeof(value) + size); TypeRef::set(new(mem(p)) value(p, size, str)); } void byteref::assign(value *bytes) { release(); TypeRef::set(bytes); } byteref::value *byteref::create(size_t size) { caddr_t p = TypeRef::alloc(sizeof(value) + size); return new(mem(p)) value(p, size); } void byteref::destroy(byteref::value *bytes) { if(bytes) bytes->destroy(); } } // namespace ucommon-6.4.4/corelib/bitmap.cpp0000644000175000001440000000657612504370166013540 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU C++ uCommon. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif namespace ucommon { bitmap::bitmap(size_t count) { size_t mem = count / 8; size = count; bus = BMALLOC; if(count % 8) ++mem; addr.a = ::malloc(mem); clear(); } bitmap::bitmap(void *ptr, size_t count, bus_t access) { assert(ptr != NULL); assert(access >= BMIN && access <= BMAX); addr.a = ptr; bus = access; } bitmap::~bitmap() { if(bus == BMALLOC && addr.b) ::free(addr.b); addr.b = NULL; } unsigned bitmap::memsize(void) const { switch(bus) { case B64: return 64; case B32: return 32; case B16: return 16; default: return 8; } } void bitmap::set(size_t offset, bool bit) { unsigned bs = memsize(); size_t pos = offset / bs; unsigned rem = offset % bs; uint64_t b64; uint32_t b32; uint16_t b16; uint8_t b8; if(offset >= size) return; switch(bus) { case B64: b64 = ((uint64_t)(1))<= size) return false; switch(bus) { #if !defined(_MSC_VER) || _MSC_VER >= 1400 case B64: return (addr.d[pos] & 1ll< 0; #endif case B32: return (addr.l[pos] & 1l< 0; case B16: return (addr.w[pos] & 1< 0; default: return (addr.b[pos] & 1< 0; } } void bitmap::clear(void) { unsigned bs = memsize(); if(size % bs) ++size; while(size--) { switch(bus) { #if !defined(_MSC_VER) || _MSC_VER >= 1400 case B64: *(addr.d++) = 0ll; break; #endif case B32: *(addr.l++) = 0l; break; case B16: *(addr.w++) = 0; break; default: *(addr.b++) = 0; } } } } // namespace ucommon ucommon-6.4.4/corelib/regex.cpp0000664000175000017500000001215412544454312013371 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include #include #ifdef HAVE_FCNTL_H #include #endif #include #ifdef HAVE_REGEX_H #include #endif namespace ucommon { String::regex::regex(const char *pattern, size_t size) { #ifdef HAVE_REGEX_H regex_t *r = (regex_t *)malloc(sizeof(regex_t)); if(regcomp(r, pattern, 0)) { regfree(r); free(r); r = NULL; } object = r; count = size; results = (regmatch_t *)malloc(sizeof(regmatch_t) * size); #else object = results = NULL; count = 0; #endif } String::regex::regex(size_t size) { #ifdef HAVE_REGEX_H count = size; results = (regmatch_t *)malloc(sizeof(regmatch_t) * size); object = NULL; #else object = results = NULL; count = 0; #endif } String::regex& String::regex::operator=(const char *pattern) { #ifdef HAVE_REGEX_H if(object) { regfree((regex_t *)object); free(object); } regex_t *r = (regex_t *)malloc(sizeof(regex_t)); if(regcomp(r, pattern, 0)) { regfree(r); free(r); r = NULL; } object = r; #endif return *this; } bool String::regex::operator*=(const char *text) { return match(text); } String::regex::~regex() { #ifdef HAVE_REGEX_H if(object) { regfree((regex_t *)object); free(object); } if(results) free(results); object = results = NULL; #endif } size_t String::regex::offset(unsigned member) { #ifdef HAVE_REGEX_H if(!results) return (size_t)-1; regmatch_t *r = (regmatch_t *)results; if(member >= count) return (size_t)-1; return (size_t)r[member].rm_so; #else return (size_t)-1; #endif } size_t String::regex::size(unsigned member) { #ifdef HAVE_REGEX_H if(!results) return 0; regmatch_t *r = (regmatch_t *)results; if(member >= count) return (size_t)-1; if(r[member].rm_so == -1) return 0; return (size_t)(r[member].rm_eo - r[member].rm_so); #else return (size_t)0; #endif } bool String::regex::match(const char *text, unsigned mode) { #ifdef HAVE_REGEX_H int flags = 0; if((mode & 0x01) == INSENSITIVE) flags |= REG_ICASE; if(!text || !object || !results) return false; if(regexec((regex_t *)object, text, count, (regmatch_t *)results, flags)) return false; return true; #else return false; #endif } const char *String::search(regex& expr, unsigned member, unsigned flags) const { if(!str) return NULL; #ifdef HAVE_REGEX_H if(expr.match(str->text, flags)) return NULL; if(member >= expr.members()) return NULL; if(expr.size(member) == 0) return NULL; return str->text + expr.offset(member); #else return NULL; #endif } unsigned String::replace(regex& expr, const char *cp, unsigned flags) { #ifdef HAVE_REGEX_H size_t cpl = 0; if(cp) cpl = strlen(cp); if(!str || str->len == 0) return 0; if(expr.match(str->text, flags)) return 0; ssize_t adjust = 0; unsigned member = 0; while(member < expr.members()) { ssize_t tcl = expr.size(member); ssize_t offset = (expr.offset(member) + adjust); if(!tcl) break; ++member; cut(offset, tcl); if(cpl) { paste(offset, cp); adjust += (cpl - tcl); } } return member; #else return 0; #endif } bool String::operator*=(regex& expr) { if(search(expr)) return true; return false; } unsigned StringPager::split(stringex_t& expr, const char *string, unsigned flags) { strdup_t tmp = String::dup(string); int prior = 0, match = 0; size_t tcl = strlen(string); unsigned count = 0, member = 0; if(!expr.match(string, flags)) return 0; while(member < expr.members()) { if(!expr.size(member)) break; match = (int)expr.offset(member++); if(match > prior) { tmp[match] = 0; add(tmp + (size_t)prior); ++count; } prior = (int)(match + tcl); } if(tmp[prior]) { add(tmp + (size_t)prior); ++count; } return count; } } // namespace ucommon ucommon-6.4.4/corelib/access.cpp0000644000175000001440000000431712504370127013511 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include namespace ucommon { UnlockAccess::~UnlockAccess() { } SharedAccess::~SharedAccess() { } ExclusiveAccess::~ExclusiveAccess() { } void SharedAccess::exclusive(void) { } void SharedAccess::share(void) { } shared_access::shared_access(SharedAccess *obj) { assert(obj != NULL); lock = obj; modify = false; state = 0; lock->shared_lock(); } exclusive_access::exclusive_access(ExclusiveAccess *obj) { assert(obj != NULL); lock = obj; lock->exclusive_lock(); } shared_access::~shared_access() { if(lock) { if(modify) lock->share(); lock->release_share(); lock = NULL; modify = false; } } exclusive_access::~exclusive_access() { if(lock) { lock->release_exclusive(); lock = NULL; } } void shared_access::release() { if(lock) { if(modify) lock->share(); lock->release_share(); lock = NULL; modify = false; } } void exclusive_access::release() { if(lock) { lock->release_exclusive(); lock = NULL; } } void shared_access::exclusive(void) { if(lock && !modify) { lock->exclusive(); modify = true; } } void shared_access::share(void) { if(lock && modify) { lock->share(); modify = false; } } } // namespace ucommon ucommon-6.4.4/corelib/fsys.cpp0000664000175000017500000010675012555734251013256 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #ifndef _MSC_VER #include #endif #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 600 #endif #include // broken BSD; XOPEN should not imply _POSIX_C_SOURCE, // _POSIX_C_SOURCE should not stop __BSD_VISIBLE #define u_int unsigned int #define u_short unsigned short #define u_long unsigned long #define u_char unsigned char #include #include #include #include #include #include #include #ifdef HAVE_SYSLOG_H #include #endif #ifdef HAVE_LINUX_VERSION_H #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) #ifdef HAVE_POSIX_FADVISE #undef HAVE_POSIX_FADVISE #endif #endif #endif #include #include #include #include #include #ifdef HAVE_POSIX_FADVISE #ifndef POSIX_FADV_RANDOM #undef HAVE_POSIX_FADVISE #endif #endif #ifdef HAVE_DIRENT_H #include #endif #ifdef _MSWINDOWS_ #include #include #include #endif #ifdef HAVE_SYS_INOTIFY_H #include #endif #ifdef HAVE_SYS_EVENT_H #include #endif namespace ucommon { const fsys::offset_t fsys::end = (offset_t)(-1); #ifdef _MSWINDOWS_ // removed from some sdk versions... struct LOCAL_REPARSE_DATA_BUFFER { DWORD ReparseTag; WORD ReparseDataLength; WORD Reserved; // IO_REPARSE_TAG_MOUNT_POINT specifics follow WORD SubstituteNameOffset; WORD SubstituteNameLength; WORD PrintNameOffset; WORD PrintNameLength; WCHAR PathBuffer[1]; }; int fsys::remapError(void) { DWORD err = GetLastError(); switch(err) { case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_INVALID_NAME: case ERROR_BAD_PATHNAME: return ENOENT; case ERROR_TOO_MANY_OPEN_FILES: return EMFILE; case ERROR_ACCESS_DENIED: case ERROR_WRITE_PROTECT: case ERROR_SHARING_VIOLATION: case ERROR_LOCK_VIOLATION: return EACCES; case ERROR_INVALID_HANDLE: return EBADF; case ERROR_NOT_ENOUGH_MEMORY: case ERROR_OUTOFMEMORY: return ENOMEM; case ERROR_INVALID_DRIVE: case ERROR_BAD_UNIT: case ERROR_BAD_DEVICE: return ENODEV; case ERROR_NOT_SAME_DEVICE: return EXDEV; case ERROR_NOT_SUPPORTED: case ERROR_CALL_NOT_IMPLEMENTED: return ENOSYS; case ERROR_END_OF_MEDIA: case ERROR_EOM_OVERFLOW: case ERROR_HANDLE_DISK_FULL: case ERROR_DISK_FULL: return ENOSPC; case ERROR_BAD_NETPATH: case ERROR_BAD_NET_NAME: return EACCES; case ERROR_FILE_EXISTS: case ERROR_ALREADY_EXISTS: return EEXIST; case ERROR_CANNOT_MAKE: case ERROR_NOT_OWNER: return EPERM; case ERROR_NO_PROC_SLOTS: return EAGAIN; case ERROR_BROKEN_PIPE: case ERROR_NO_DATA: return EPIPE; case ERROR_OPEN_FAILED: return EIO; case ERROR_NOACCESS: return EFAULT; case ERROR_IO_DEVICE: case ERROR_CRC: case ERROR_NO_SIGNAL_SENT: return EIO; case ERROR_CHILD_NOT_COMPLETE: case ERROR_SIGNAL_PENDING: case ERROR_BUSY: return EBUSY; case ERROR_DIR_NOT_EMPTY: return ENOTEMPTY; case ERROR_DIRECTORY: return ENOTDIR; default: return EINVAL; } } int dir::create(const char *path, unsigned perms) { if(!CreateDirectory(path, NULL)) return remapError(); if(perms & 06) perms |= 01; if(perms & 060) perms |= 010; if(perms & 0600) perms |= 0100; return mode(path, perms); } fd_t fsys::null(void) { SECURITY_ATTRIBUTES sattr; sattr.nLength = sizeof(SECURITY_ATTRIBUTES); sattr.bInheritHandle = TRUE; sattr.lpSecurityDescriptor = NULL; return CreateFile("nul", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sattr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } int fsys::pipe(fd_t& input, fd_t& output, size_t size) { input = output = NULL; SECURITY_ATTRIBUTES sattr; sattr.nLength = sizeof(SECURITY_ATTRIBUTES); sattr.bInheritHandle = TRUE; sattr.lpSecurityDescriptor = NULL; if(!CreatePipe(&input, &output, &sattr, (DWORD)size)) return remapError(); return 0; } int fsys::info(const char *path, struct stat *buf) { if(_stat(path, (struct _stat *)(buf))) return remapError(); return 0; } int fsys::trunc(offset_t offset) { if(fsys::seek(offset) != 0) return remapError(); if(SetEndOfFile(fd)) return 0; return remapError(); } int fsys::info(struct stat *buf) { int fn = _open_osfhandle((intptr_t)(fd), O_RDONLY); int rtn = _fstat(fn, (struct _stat *)(buf)); _close(fn); if(rtn) error = remapError(); return rtn; } int fsys::prefix(const char *path) { if (_chdir(path)) return remapError(); return 0; } int fsys::prefix(char *path, size_t len) { if (NULL == _getcwd(path, (socksize_t)len)) return remapError(); return 0; } int fsys::mode(const char *path, unsigned value) { if(_chmod(path, value)) return remapError(); return 0; } bool fsys::is_exists(const char *path) { if(_access(path, F_OK)) return false; return true; } bool fsys::is_readable(const char *path) { if(_access(path, R_OK)) return false; return true; } bool fsys::is_writable(const char *path) { if(_access(path, W_OK)) return false; return true; } bool fsys::is_executable(const char *path) { path = strrchr(path, '.'); if(!path) return false; if(eq_case(path, ".exe")) return true; if(eq_case(path, ".bat")) return true; if(eq_case(path, ".com")) return true; if(eq_case(path, ".cmd")) return true; if(eq_case(path, ".ps1")) return true; return false; } bool fsys::is_tty(fd_t fd) { if(fd == INVALID_HANDLE_VALUE) return false; DWORD type = GetFileType(fd); if(type == FILE_TYPE_CHAR) return true; return false; } bool fsys::is_tty(void) const { error = 0; if(fd == INVALID_HANDLE_VALUE) return false; DWORD type = GetFileType(fd); if(!type) error = remapError(); if(type == FILE_TYPE_CHAR) return true; return false; } void dir::close(void) { error = 0; if(ptr) { if(::FindClose(fd)) { delete ptr; ptr = NULL; fd = INVALID_HANDLE_VALUE; } else error = remapError(); } else error = EBADF; } int fsys::close(void) { error = 0; if(fd == INVALID_HANDLE_VALUE) return EBADF; if(::CloseHandle(fd)) fd = INVALID_HANDLE_VALUE; else error = remapError(); return error; } ssize_t dir::read(char *buf, size_t len) { ssize_t rtn = -1; if(ptr) { snprintf((char *)buf, len, ptr->cFileName); rtn = (ssize_t)strlen(ptr->cFileName); if(!FindNextFile(fd, ptr)) close(); return rtn; } return -1; } ssize_t fsys::read(void *buf, size_t len) { ssize_t rtn = -1; DWORD count; if(ReadFile(fd, (LPVOID) buf, (DWORD)len, &count, NULL)) rtn = count; else error = remapError(); return rtn; } ssize_t fsys::write(const void *buf, size_t len) { ssize_t rtn = -1; DWORD count; if(WriteFile(fd, (LPVOID) buf, (DWORD)len, &count, NULL)) rtn = count; else error = remapError(); return rtn; } int fsys::sync(void) { return 0; } fd_t fsys::input(const char *path) { SECURITY_ATTRIBUTES sattr; sattr.nLength = sizeof(SECURITY_ATTRIBUTES); sattr.bInheritHandle = TRUE; sattr.lpSecurityDescriptor = NULL; return CreateFile(path, GENERIC_READ, FILE_SHARE_READ, &sattr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } fd_t fsys::output(const char *path) { SECURITY_ATTRIBUTES sattr; sattr.nLength = sizeof(SECURITY_ATTRIBUTES); sattr.bInheritHandle = TRUE; sattr.lpSecurityDescriptor = NULL; return CreateFile(path, GENERIC_WRITE, 0, &sattr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); } fd_t fsys::append(const char *path) { SECURITY_ATTRIBUTES sattr; sattr.nLength = sizeof(SECURITY_ATTRIBUTES); sattr.bInheritHandle = TRUE; sattr.lpSecurityDescriptor = NULL; fd_t fd = CreateFile(path, GENERIC_WRITE, 0, &sattr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(fd != INVALID_HANDLE_VALUE) SetFilePointer(fd, 0, NULL, FILE_END); return fd; } void fsys::release(fd_t fd) { CloseHandle(fd); } void dir::open(const char *path) { close(); error = 0; char tpath[256]; DWORD attr = GetFileAttributes(path); if((attr == (DWORD)~0l) || !(attr & FILE_ATTRIBUTE_DIRECTORY)) { error = ENOTDIR; return; } snprintf(tpath, sizeof(tpath), "%s%s", path, "\\*"); ptr = new WIN32_FIND_DATA; fd = FindFirstFile(tpath, ptr); if(fd == INVALID_HANDLE_VALUE) { delete ptr; ptr = NULL; error = remapError(); } return; } void fsys::open(const char *path, access_t access) { bool append = false; DWORD amode = 0; DWORD smode = 0; DWORD attr = FILE_ATTRIBUTE_NORMAL; char buf[128]; close(); error = 0; if(access == DEVICE) { #ifdef _MSWINDOWS_ if(isalpha(path[0]) && path[1] == ':') { if(!QueryDosDevice(path, buf, sizeof(buf))) { error = ENODEV; return; } path = buf; } #else if(!strchr(path, '/')) { if(path[0] == 'S' && isdigit(path[1])) snprintf(buf, sizeof(buf) "/dev/tty%s", path); else if(strncmp(path, "USB", 3)) snprintf(buf, sizeof(buf), "/dev/tty%s", path); else snprintf(buf, sizeof(buf), "/dev/%s", path); char *cp = strchr(buf, ':'); if(cp) *cp = 0; path = buf; } #endif if(!is_device(buf)) { error = ENODEV; return; } } switch(access) { case STREAM: #ifdef FILE_FLAG_SEQUENTIAL_SCAN attr |= FILE_FLAG_SEQUENTIAL_SCAN; #endif case RDONLY: amode = GENERIC_READ; smode = FILE_SHARE_READ; break; case WRONLY: amode = GENERIC_WRITE; break; case DEVICE: smode = FILE_SHARE_READ; attr |= FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING; case EXCLUSIVE: amode = GENERIC_READ | GENERIC_WRITE; break; case RANDOM: attr |= FILE_FLAG_RANDOM_ACCESS; case REWRITE: amode = GENERIC_READ | GENERIC_WRITE; smode = FILE_SHARE_READ; break; case APPEND: amode = GENERIC_WRITE; append = true; break; case SHARED: amode = GENERIC_READ | GENERIC_WRITE; smode = FILE_SHARE_READ | FILE_SHARE_WRITE; break; } fd = CreateFile(path, amode, smode, NULL, OPEN_EXISTING, attr, NULL); if(fd != INVALID_HANDLE_VALUE && append) seek(end); else if(fd == INVALID_HANDLE_VALUE) error = remapError(); } void fsys::open(const char *path, unsigned fmode, access_t access) { bool append = false; DWORD amode = 0; DWORD cmode = 0; DWORD smode = 0; DWORD attr = FILE_ATTRIBUTE_NORMAL; fmode &= 0666; close(); error = 0; const char *cp = strrchr(path, '\\'); const char *cp2 = strrchr(path, '/'); if(cp2 > cp) cp = cp2; if(!cp) cp = path; else ++cp; if(*cp == '.') attr = FILE_ATTRIBUTE_HIDDEN; switch(access) { case DEVICE: error = ENOSYS; return; case RDONLY: amode = GENERIC_READ; cmode = OPEN_ALWAYS; smode = FILE_SHARE_READ; break; case STREAM: case WRONLY: amode = GENERIC_WRITE; cmode = CREATE_ALWAYS; break; case EXCLUSIVE: amode = GENERIC_READ | GENERIC_WRITE; cmode = OPEN_ALWAYS; break; case RANDOM: attr |= FILE_FLAG_RANDOM_ACCESS; case REWRITE: amode = GENERIC_READ | GENERIC_WRITE; cmode = OPEN_ALWAYS; smode = FILE_SHARE_READ; break; case APPEND: amode = GENERIC_WRITE; cmode = OPEN_ALWAYS; append = true; break; case SHARED: amode = GENERIC_READ | GENERIC_WRITE; cmode = OPEN_ALWAYS; smode = FILE_SHARE_READ | FILE_SHARE_WRITE; break; } fd = CreateFile(path, amode, smode, NULL, cmode, attr, NULL); if(fd != INVALID_HANDLE_VALUE && append) seek(end); else if(fd == INVALID_HANDLE_VALUE) error = remapError(); if(fd != INVALID_HANDLE_VALUE) mode(path, fmode); } fsys::fsys(const fsys& copy) { error = 0; fd = INVALID_HANDLE_VALUE; if(copy.fd == INVALID_HANDLE_VALUE) return; HANDLE pHandle = GetCurrentProcess(); if(!DuplicateHandle(pHandle, copy.fd, pHandle, &fd, 0, FALSE, DUPLICATE_SAME_ACCESS)) { fd = INVALID_HANDLE_VALUE; error = remapError(); } } int fsys::inherit(fd_t& from, bool enable) { HANDLE pHandle = GetCurrentProcess(); if(!enable) { if(!SetHandleInformation(from, HANDLE_FLAG_INHERIT, 0)) return remapError(); return 0; } fd_t fd; if(DuplicateHandle(pHandle, from, pHandle, &fd, 0, TRUE, DUPLICATE_SAME_ACCESS)) { release(from); from = fd; return 0; } return remapError(); } void fsys::operator=(fd_t from) { HANDLE pHandle = GetCurrentProcess(); if(fd != INVALID_HANDLE_VALUE) { if(!CloseHandle(fd)) { error = remapError(); return; } } if(DuplicateHandle(pHandle, from, pHandle, &fd, 0, FALSE, DUPLICATE_SAME_ACCESS)) error = 0; else { fd = INVALID_HANDLE_VALUE; error = remapError(); } } void fsys::operator=(const fsys& from) { HANDLE pHandle = GetCurrentProcess(); if(fd != INVALID_HANDLE_VALUE) { if(!CloseHandle(fd)) { error = remapError(); return; } } if(DuplicateHandle(pHandle, from.fd, pHandle, &fd, 0, FALSE, DUPLICATE_SAME_ACCESS)) error = 0; else { fd = INVALID_HANDLE_VALUE; error = remapError(); } } int fsys::drop(offset_t size) { error = ENOSYS; return ENOSYS; } int fsys::seek(offset_t pos) { DWORD rpos = pos; int mode = FILE_BEGIN; if(rpos == (DWORD)end) { rpos = 0; mode = FILE_END; } if(SetFilePointer(fd, rpos, NULL, mode) == INVALID_SET_FILE_POINTER) { error = remapError(); return error; } return 0; } #else ssize_t dir::read(char *buf, size_t len) { if(ptr) { dirent *entry = ::readdir((DIR *)ptr); if(!entry) return 0; String::set((char *)buf, len, entry->d_name); return strlen(entry->d_name); } return -1; } ssize_t fsys::read(void *buf, size_t len) { #ifdef __PTH__ int rtn = ::pth_read(fd, buf, len); #else int rtn = ::read(fd, buf, len); #endif if(rtn < 0) error = remapError(); return rtn; } int fsys::sync(void) { int rtn = ::fsync(fd); if(rtn < 0) error = remapError(); else return 0; return error; } ssize_t fsys::write(const void *buf, size_t len) { #ifdef __PTH__ int rtn = pth_write(fd, buf, len); #else int rtn = ::write(fd, buf, len); #endif if(rtn < 0) error = remapError(); return rtn; } fd_t fsys::null(void) { return ::open("/dev/null", O_RDWR); } int fsys::pipe(fd_t& input, fd_t& output, size_t size) { input = output = -1; int pfd[2]; if(::pipe(pfd)) return remapError(); input = pfd[0]; output = pfd[1]; return 0; } bool fsys::is_tty(fd_t fd) { if(isatty(fd)) return true; return false; } bool fsys::is_tty(void) const { if(isatty(fd)) return true; return false; } void dir::close(void) { error = 0; if(ptr) { if(::closedir((DIR *)ptr)) error = remapError(); ptr = NULL; } else error = EBADF; } int fsys::close(void) { error = 0; if(fd != INVALID_HANDLE_VALUE) { if(::close(fd) == 0) fd = INVALID_HANDLE_VALUE; else error = remapError(); } else return EBADF; // not opened, but state still error free return error; } fd_t fsys::input(const char *path) { return ::open(path, O_RDONLY); } fd_t fsys::output(const char *path) { return ::open(path, O_WRONLY | O_CREAT | O_TRUNC, EVERYONE); } fd_t fsys::append(const char *path) { return ::open(path, O_WRONLY | O_CREAT | O_APPEND, EVERYONE); } void fsys::release(fd_t fd) { ::close(fd); } void fsys::open(const char *path, unsigned fmode, access_t access) { unsigned flags = 0; close(); error = 0; switch(access) { case DEVICE: error = ENOSYS; return; case RDONLY: flags = O_RDONLY | O_CREAT; break; case STREAM: case WRONLY: flags = O_WRONLY | O_CREAT | O_TRUNC; break; case RANDOM: case SHARED: case REWRITE: case EXCLUSIVE: flags = O_RDWR | O_CREAT; break; case APPEND: flags = O_RDWR | O_APPEND | O_CREAT; break; } fd = ::open(path, flags, fmode); if(fd == INVALID_HANDLE_VALUE) error = remapError(); #ifdef HAVE_POSIX_FADVISE else { if(access == RANDOM) posix_fadvise(fd, (off_t)0, (off_t)0, POSIX_FADV_RANDOM); } #endif } int dir::create(const char *path, unsigned perms) { if(perms & 06) perms |= 01; if(perms & 060) perms |= 010; if(perms & 0600) perms |= 0100; if(::mkdir(path, perms)) return remapError(); return 0; } void dir::open(const char *path) { close(); error = 0; ptr = opendir(path); if(!ptr) error = remapError(); } void fsys::open(const char *path, access_t access) { unsigned flags = 0; close(); error = 0; switch(access) { case STREAM: #if defined(O_STREAMING) flags = O_RDONLY | O_STREAMING; break; #endif case RDONLY: flags = O_RDONLY; break; case WRONLY: flags = O_WRONLY; break; case EXCLUSIVE: case RANDOM: case SHARED: case REWRITE: case DEVICE: flags = O_RDWR | O_NONBLOCK; break; case APPEND: flags = O_RDWR | O_APPEND; break; } fd = ::open(path, flags); if(fd == INVALID_HANDLE_VALUE) { error = remapError(); return; } #ifdef HAVE_POSIX_FADVISE // Linux kernel bug prevents use of POSIX_FADV_NOREUSE in streaming... if(access == STREAM) posix_fadvise(fd, (off_t)0, (off_t)0, POSIX_FADV_SEQUENTIAL); else if(access == RANDOM) posix_fadvise(fd, (off_t)0, (off_t)0, POSIX_FADV_RANDOM); #endif if(access == DEVICE) { flags = fcntl(fd, F_GETFL); flags &= ~O_NONBLOCK; fcntl(fd, F_SETFL, flags); } } int fsys::info(const char *path, struct stat *ino) { if(::stat(path, ino)) return remapError(); return 0; } #ifdef HAVE_FTRUNCATE int fsys::trunc(offset_t offset) { if(fsys::seek(offset) != 0) return remapError(); if(::ftruncate(fd, offset) == 0) return 0; return remapError(); } #else int fsys::trunc(offset_t offset) { if(fsys::seek(offset) != 0) return remapError(); return ENOSYS; } #endif int fsys::info(struct stat *ino) { if(::fstat(fd, ino)) { error = remapError(); return error; } return 0; } int fsys::prefix(const char *path) { if(::chdir(path)) return remapError(); return 0; } int fsys::prefix(char *path, size_t len) { if(NULL == ::getcwd(path, len)) return remapError(); return 0; } int fsys::mode(const char *path, unsigned value) { if(::chmod(path, value)) return remapError(); return 0; } bool fsys::is_exists(const char *path) { if(::access(path, F_OK)) return false; return true; } bool fsys::is_readable(const char *path) { if(::access(path, R_OK)) return false; return true; } bool fsys::is_writable(const char *path) { if(::access(path, W_OK)) return false; return true; } bool fsys::is_executable(const char *path) { if(is_dir(path)) return false; if(::access(path, X_OK)) return false; return true; } fsys::fsys(const fsys& copy) { fd = INVALID_HANDLE_VALUE; error = 0; if(copy.fd != INVALID_HANDLE_VALUE) { fd = ::dup(copy.fd); } else fd = INVALID_HANDLE_VALUE; } int fsys::inherit(fd_t& fd, bool enable) { unsigned long flags; if(fd > -1) { flags = fcntl(fd, F_GETFL); if(enable) flags &= ~FD_CLOEXEC; else flags |= FD_CLOEXEC; if(fcntl(fd, F_SETFL, flags)) return remapError(); } return 0; } void fsys::operator=(fd_t from) { close(); if(fd == INVALID_HANDLE_VALUE && from != INVALID_HANDLE_VALUE) { fd = ::dup(from); if(fd == INVALID_HANDLE_VALUE) error = remapError(); } } void fsys::operator=(const fsys& from) { close(); if(fd == INVALID_HANDLE_VALUE && from.fd != INVALID_HANDLE_VALUE) { fd = ::dup(from.fd); if(fd == INVALID_HANDLE_VALUE) error = remapError(); } } int fsys::drop(offset_t size) { #ifdef HAVE_POSIX_FADVISE if(posix_fadvise(fd, (off_t)0, size, POSIX_FADV_DONTNEED)) { error = remapError(); return error; } return 0; #else error = ENOSYS; return ENOSYS; #endif } int fsys::seek(offset_t pos) { unsigned long rpos = pos; int mode = SEEK_SET; if(rpos == (unsigned long)end) { rpos = 0; mode = SEEK_END; } if(lseek(fd, rpos, mode) == ~0l) { error = remapError(); return error; } return 0; } #endif dso::dso() { ptr = 0; error = 0; } dso::dso(const char *path) { ptr = 0; error = 0; map(path); } dso::~dso() { release(); } dir::dir() : fsys() { ptr = NULL; } dir::~dir() { close(); } fsys::fsys() { fd = INVALID_HANDLE_VALUE; error = 0; } dir::dir(const char *path) : fsys() { ptr = NULL; open(path); } fsys::fsys(const char *path, access_t access) { fd = INVALID_HANDLE_VALUE; open(path, access); } fsys::fsys(const char *path, unsigned fmode, access_t access) { fd = INVALID_HANDLE_VALUE; open(path, fmode, access); } fsys::~fsys() { close(); } void fsys::operator*=(fd_t& from) { if(fd != INVALID_HANDLE_VALUE) close(); fd = from; from = INVALID_HANDLE_VALUE; } int fsys::linkinfo(const char *path, char *buffer, size_t size) { #if defined(_MSWINDOWS_) HANDLE h; DWORD rsize; char *reparse = (char *)_malloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); if (!reparse) return EINVAL; if(!fsys::is_link(path)) return EINVAL; h = CreateFile(path, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); if(!h || h == INVALID_HANDLE_VALUE) return EINVAL; memset(reparse, 0, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); LOCAL_REPARSE_DATA_BUFFER *rb = (LOCAL_REPARSE_DATA_BUFFER*)&reparse; if(!DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID *)rb, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &rsize, 0)) { CloseHandle(h); return remapError(); } #ifdef UNICODE String::set(buffer, size, rb.PathBuffer); #else WideCharToMultiByte(CP_THREAD_ACP, 0, rb->PathBuffer, rb->SubstituteNameLength / sizeof(WCHAR) + 1, buffer, (int)size, "", FALSE); #endif CloseHandle(h); return 0; #elif defined(HAVE_READLINK) if(::readlink(path, buffer, size)) return remapError(); return 0; #else return EINVAL; #endif } int fsys::hardlink(const char *path, const char *target) { #ifdef _MSWINDOWS_ if(!CreateHardLink(target, path, NULL)) return remapError(); return 0; #else if(::link(path, target)) return remapError(); return 0; #endif } int fsys::link(const char *path, const char *target) { #if defined(_MSWINDOWS_) TCHAR dest[512]; HANDLE h; char *part; DWORD size; WORD len; char *reparse = (char *)_malloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); if (!reparse) return EINVAL; lstrcpy(dest, "\\??\\"); dest[4] = 0; if(!GetFullPathName(path, sizeof(dest) - (4 * sizeof(TCHAR)), &dest[4], &part) || GetFileAttributes(&dest[4]) == INVALID_FILE_ATTRIBUTES) return remapError(); LOCAL_REPARSE_DATA_BUFFER *rb = (LOCAL_REPARSE_DATA_BUFFER*)&reparse; memset(rb, 0, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); if(!MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED, dest, lstrlenA(dest) + 1, rb->PathBuffer, lstrlenA(dest) + 1)) return remapError(); len = lstrlenW(rb->PathBuffer) * 2; rb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; rb->ReparseDataLength = len + 12; rb->SubstituteNameLength = len; rb->PrintNameOffset = len + 2; h = CreateFile(target, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); if(!h || h == INVALID_HANDLE_VALUE) return hardlink(path, target); if(!DeviceIoControl(h, FSCTL_SET_REPARSE_POINT, (LPVOID)rb, rb->ReparseDataLength + FIELD_OFFSET(LOCAL_REPARSE_DATA_BUFFER, SubstituteNameOffset), NULL, 0, &size, 0)) { CloseHandle(h); return hardlink(path, target); } CloseHandle(h); return 0; #elif defined(HAVE_SYMLINK) if(::symlink(path, target)) return remapError(); return 0; #else if(::link(path, target)) return remapError(); return 0; #endif } int fsys::unlink(const char *path) { #ifdef _MSWINDOWS_ HANDLE h = INVALID_HANDLE_VALUE; if(is_link(path)) h = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); if(h && h != INVALID_HANDLE_VALUE) { REPARSE_GUID_DATA_BUFFER rb; memset(&rb, 0, sizeof(rb)); DWORD size; rb.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; if(!DeviceIoControl(h, FSCTL_DELETE_REPARSE_POINT, &rb, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &size, 0)) { CloseHandle(h); return remapError(); } CloseHandle(h); ::remove(path); return 0; } #endif if(::remove(path)) return remapError(); return 0; } int fsys::erase(const char *path) { if(is_device(path)) return ENOSYS; if(::remove(path)) return remapError(); return 0; } int dir::remove(const char *path) { if(is_device(path)) return ENOSYS; #ifdef _MSWINDOWS_ if(RemoveDirectory(path)) return 0; int error = remapError(); if(error == ENOTEMPTY) return ENOTEMPTY; #else if(!::rmdir(path)) return 0; if(errno != ENOTDIR) return errno; #endif if(::remove(path)) return remapError(); return 0; } int fsys::copy(const char *oldpath, const char *newpath, size_t size) { int result = 0; char *buffer = new char[size]; fsys src, dest; ssize_t count = (ssize_t)size; if(!buffer) { result = ENOMEM; goto end; } remove(newpath); src.open(oldpath, fsys::STREAM); if(!is(src)) goto end; dest.open(newpath, GROUP_PUBLIC, fsys::STREAM); if(!is(dest)) goto end; while(count > 0) { count = src.read(buffer, size); if(count < 0) { result = src.err(); goto end; } if(count > 0) count = dest.write(buffer, size); if(count < 0) { result = dest.err(); goto end; } } end: if(is(src)) src.close(); if(is(dest)) dest.close(); if(buffer) delete[] buffer; if(result != 0) remove(newpath); return result; } int fsys::rename(const char *oldpath, const char *newpath) { if(::rename(oldpath, newpath)) return remapError(); return 0; } int fsys::load(const char *path) { dso module; module.map(path); #ifdef _MSWINDOWS_ if(module.ptr) { module.ptr = 0; return 0; } return remapError(); #else if(module.ptr) { module.ptr = 0; return 0; } return module.error; #endif } bool fsys::is_file(const char *path) { #ifdef _MSWINDOWS_ DWORD attr = GetFileAttributes(path); if(attr == (DWORD)~0l) return false; if(attr & FILE_ATTRIBUTE_DIRECTORY) return false; return true; #else struct stat ino; if(::stat(path, &ino)) return false; if(S_ISREG(ino.st_mode)) return true; return false; #endif } bool fsys::is_link(const char *path) { #if defined(_MSWINDOWS_) DWORD attr = GetFileAttributes(path); if (attr == 0xffffffff || !(attr & FILE_ATTRIBUTE_REPARSE_POINT)) return false; return true; #elif defined(HAVE_LSTAT) struct stat ino; if(::lstat(path, &ino)) return false; if(S_ISLNK(ino.st_mode)) return true; return false; #else return false; #endif } bool fsys::is_dir(const char *path) { #ifdef _MSWINDOWS_ DWORD attr = GetFileAttributes(path); if(attr == (DWORD)~0l) return false; if(attr & FILE_ATTRIBUTE_DIRECTORY) return true; return false; #else struct stat ino; if(::stat(path, &ino)) return false; if(S_ISDIR(ino.st_mode)) return true; return false; #endif } #ifdef _MSWINDOWS_ void dso::map(const char *path) { error = 0; ptr = LoadLibrary(path); if(!ptr) error = ENOEXEC; } void dso::release(void) { if(ptr) FreeLibrary(ptr); ptr = 0; } dso::addr_t dso::find(const char *sym) const { if(ptr == 0) return (dso::addr_t)NULL; return (addr_t)GetProcAddress(ptr, sym); } #elif defined(HAVE_DLFCN_H) #include #ifndef RTLD_GLOBAL #define RTLD_GLOBAL 0 #endif void dso::map(const char *path) { error = 0; ptr = dlopen(path, RTLD_NOW | RTLD_GLOBAL); if(ptr == NULL) error = ENOEXEC; } void dso::release(void) { if(ptr) dlclose(ptr); ptr = NULL; } dso::addr_t dso::find(const char *sym) const { if(!ptr) return (dso::addr_t)NULL; return (dso::addr_t)dlsym(ptr, (char *)sym); } #elif HAVE_MACH_O_DYLD_H #include void dso::map(const char *path) { NSObjectFileImage oImage; NSSymbol sym = NULL; NSModule mod; void (*init)(void); ptr = NULL; error = 0; if(NSCreateObjectFileImageFromFile(path, &oImage) != NSObjectFileImageSuccess) { error = ENOEXEC; return; } mod = NSLinkModule(oImage, path, NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_RETURN_ON_ERROR); NSDestroyObjectFileImage(oImage); if(mod == NULL) { error = ENOEXEC; return; } sym = NSLookupSymbolInModule(mod, "__init"); if(sym) { init = (void (*)(void))NSAddressOfSymbol(sym); init(); } ptr = (void *)mod; } void dso::release(void) { if(!ptr) return; NSModule mod = (NSModule)ptr; NSSymbol sym; void (*fini)(void); ptr = NULL; sym = NSLookupSymbolInModule(mod, "__fini"); if(sym != NULL) { fini = (void (*)(void))NSAddressOfSymbol(sym); fini(); } NSUnlinkModule(mod, NSUNLINKMODULE_OPTION_NONE); } dso::addr_t dso::find(const char *sym) const { if(!ptr) return NULL; NSModule mod = (NSModule)ptr; NSSymbol sym; sym = NSLookupSymbolInModule(mod, sym); if(sym != NULL) { return (dso::addr_t)NSAddressOfSymbol(sym); return (dso::addr_t)NULL; } #elif HAVE_SHL_LOAD #include void dso::map(const char *path) { error = 0; ptr = (void *)shl_load(path, BIND_IMMEDIATE, 0l); if(!ptr) error = ENOEXEC; } dso::addr_t dso::find(const char *sym) const { if(!ptr) return (dso::addr_t)NULL; shl_t image = (shl_t)ptr; if(shl_findsym(&image, sym, 0, &value) == 0) return (dso::addr_t)value; return (dso::addr_t)NULL; } void dso::release(void) { shl_t image = (shl_t)ptr; if(ptr) shl_unload(image); ptr = NULL; } #else void fsys::map(const char *path) { error = ENOEXEC; ptr = NULL; } void dso::release(void) { } dso::addr_t dso::find(const char *sym) const { return (dso::addr_t)NULL; } #endif bool fsys::is_device(const char *path) { if(!path) return false; #ifndef _MSWINDOWS_ if(is_dir(path)) return false; if(!strncmp(path, "/dev/", 5)) return true; return false; #else if(path[1] == ':' && !path[2] && isalpha(*path)) return true; if(!strncmp(path, "com", 3) || !strncmp(path, "lpt", 3)) { path += 3; while(isdigit(*path)) ++path; if(!path || *path == ':') return true; return false; } if(!strcmp(path, "aux") || !strcmp(path, "prn")) { if(!path[3] || path[3] == ':') return true; return false; } if(!strncmp(path, "\\\\.\\", 4)) return true; if(!strnicmp(path, "\\\\?\\Device\\", 12)) return true; return false; #endif } bool fsys::is_hidden(const char *path) { #ifdef _MSWINDOWS_ DWORD attr = GetFileAttributes(path); if(attr == (DWORD)~0l) return false; return ((attr & FILE_ATTRIBUTE_HIDDEN) != 0); #else const char *cp = strrchr(path, '/'); if(cp) ++cp; else cp = path; if(*cp == '.') return true; return false; #endif } fsys::fsys(fd_t handle) { fd = handle; error = 0; } void fsys::set(fd_t handle) { close(); fd = handle; error = 0; } fd_t fsys::release(void) { fd_t save = fd; fd = INVALID_HANDLE_VALUE; error = 0; return save; } int fsys::exec(const char *path, char **argv, char **envp) { shell::pid_t pid = shell::spawn(path, argv, envp); return shell::wait(pid); } #ifdef _MSWINDOWS_ static stringref_t sysprefix(void) { char *cp = _getcwd(NULL, 0); stringref result(cp); if(cp) ::free(cp); return result; } #else static stringref_t sysprefix(void) { size_t size = 40; charvalues_t buf = stringref::create(40); stringref_t out; for(;;) { if(NULL != (getcwd(buf->get(), buf->max()))) break; if(errno != ERANGE) { *(buf->get()) = 0; break; } stringref::expand(&buf, size); size += 40; } out.assign(buf); return out; } #endif string_t fsys::prefix(void) { stringref_t sys = sysprefix(); string_t out = *sys; return out; } } // namespace ucommon ucommon-6.4.4/corelib/atomic.cpp0000664000175000017500000001673412555201011013527 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include // blacklist some architectures...like sparc odd 24 bit atomics #if defined(sparc) #undef HAVE_ATOMICS #endif #ifdef HAVE_STDALIGN_H #include #endif #if !defined(HAVE_ALIGNED_ALLOC) && defined(_MSC_VER) && _MSC_VER >= 1800 #include #define HAVE_ALIGNED_ALLOC 1 #define aligned_alloc(a, s) _aligned_malloc(s, a) #endif namespace ucommon { atomic::counter::counter(atomic_t init) { value = init; } atomic::spinlock::spinlock() { value = 0; } #if !defined(__GNUC_PREREQ__) #if defined(__GNUC__) && defined(__GNUC_MINOR__) #define __GNUC_PREREQ__(maj, min) \ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) #else #define __GNUC_PREREQ__(maj, min) 0 #endif #endif #if defined(__has_feature) && defined(__has_extension) #if __has_feature(c_atomic) || __has_extension(c_atomic) #define __CLANG_ATOMICS #endif #endif #if defined(_MSWINDOWS_) atomic_t atomic::counter::fetch_add(atomic_t change) volatile { return InterlockedExchangeAdd(&value, change); } atomic_t atomic::counter::fetch_sub(atomic_t change) volatile { return InterlockedExchangeAdd(&value, -change); } atomic_t atomic::counter::get() volatile { return fetch_add(0); } void atomic::counter::clear() volatile { _InterlockedAnd(&value, 0); } bool atomic::spinlock::acquire() volatile { return !InterlockedBitTestAndSet(&value, 1); } void atomic::spinlock::wait() volatile { while(InterlockedBitTestAndSet(&value, 1)) { while(value) ; } } void atomic::spinlock::release() volatile { InterlockedBitTestAndReset(&value, 1); } #elif defined(__CLANG_ATOMICS) && defined(HAVE_ATOMICS) typedef _Atomic(atomic_t) *atomic_val; atomic_t atomic::counter::get() volatile { return __c11_atomic_load((atomic_val)(&value), __ATOMIC_SEQ_CST); } void atomic::counter::clear() volatile { __c11_atomic_fetch_and((atomic_val)(&value), (atomic_t)0, __ATOMIC_SEQ_CST); } atomic_t atomic::counter::fetch_add(atomic_t change) volatile { return __c11_atomic_fetch_add((atomic_val)(&value), change, __ATOMIC_SEQ_CST); } atomic_t atomic::counter::fetch_sub(atomic_t change) volatile { return __c11_atomic_fetch_sub((atomic_val)(&value), change, __ATOMIC_SEQ_CST); } bool atomic::spinlock::acquire(void) volatile { // if not locked by another already, then we acquired it... return (!__c11_atomic_exchange((atomic_val)(&value), 1, __ATOMIC_SEQ_CST)); } void atomic::spinlock::wait(void) volatile { while (__c11_atomic_exchange((atomic_val)(&value), 1, __ATOMIC_SEQ_CST)) { while (value) ; } } void atomic::spinlock::release(void) volatile { __c11_atomic_store((atomic_val)(&value), 0, __ATOMIC_SEQ_CST); } #elif __GNUC_PREREQ__(4, 7) && defined(HAVE_ATOMICS) atomic_t atomic::counter::fetch_add(atomic_t change) volatile { return __atomic_fetch_add(&value, change, __ATOMIC_SEQ_CST); } atomic_t atomic::counter::fetch_sub(atomic_t change) volatile { return __atomic_fetch_sub(&value, change, __ATOMIC_SEQ_CST); } atomic_t atomic::counter::get() volatile { return fetch_add(0); } void atomic::counter::clear() volatile { __atomic_fetch_and(&value, (atomic_t)0, __ATOMIC_SEQ_CST); } bool atomic::spinlock::acquire(void) volatile { // if not locked by another already, then we acquired it... return (!__atomic_test_and_set(&value, __ATOMIC_SEQ_CST)); } void atomic::spinlock::wait(void) volatile { while (__atomic_test_and_set(&value, __ATOMIC_SEQ_CST)) { while (value) ; } } void atomic::spinlock::release(void) volatile { __atomic_clear(&value, __ATOMIC_SEQ_CST); } #elif __GNUC_PREREQ__(4, 1) && defined(HAVE_ATOMICS) atomic_t atomic::counter::fetch_add(atomic_t change) volatile { return __sync_fetch_and_add(&value, change); } atomic_t atomic::counter::fetch_sub(atomic_t change) volatile { return __sync_fetch_and_sub(&value, change); } atomic_t atomic::counter::get() volatile { return fetch_add(0); } void atomic::counter::clear() volatile { __sync_fetch_and_and(&value, (atomic_t)0); } bool atomic::spinlock::acquire(void) volatile { // if not locked by another already, then we acquired it... return (!__sync_lock_test_and_set(&value, 1)); } void atomic::spinlock::wait(void) volatile { while (__sync_lock_test_and_set(&value, 1)) { while (value) ; } } void atomic::spinlock::release(void) volatile { __sync_lock_release(&value); } #else #define SIMULATED true atomic_t atomic::counter::get() volatile { atomic_t rval; Mutex::protect((void *)&value); rval = value; Mutex::release((void *)&value); return rval; } void atomic::counter::clear() volatile { Mutex::protect((void *)&value); value = 0; Mutex::release((void *)&value); } atomic_t atomic::counter::fetch_add(atomic_t change) volatile { atomic_t rval; Mutex::protect((void *)&value); rval = value; value += change; Mutex::release((void *)&value); return rval; } atomic_t atomic::counter::fetch_sub(atomic_t change) volatile { atomic_t rval; Mutex::protect((void *)&value); rval = value; value -= change; Mutex::release((void *)&value); return rval; } bool atomic::spinlock::acquire(void) volatile { bool rtn = true; Mutex::protect((void *)&value); if(value == 1) rtn = false; else value = 1; Mutex::release((void *)&value); return rtn; } void atomic::spinlock::wait(void) volatile { while(!acquire()) ; } void atomic::spinlock::release(void) volatile { Mutex::protect((void *)&value); value = 0; Mutex::release((void *)&value); } #endif #ifdef HAVE_POSIX_MEMALIGN void *atomic::alloc(size_t size) { void *addr = NULL; size = size + (size % 16); if(!posix_memalign(&addr, 16, size)) return NULL; return addr; } #elif HAVE_ALIGNED_ALLOC void *atomic::alloc(size_t size) { return aligned_alloc(16, size); } #else void *atomic::alloc(size_t size) { caddr_t addr = (caddr_t)::malloc(size + 16); if(!addr) return NULL; while(((uintptr_t)addr) & 0xf) ++addr; return addr; } #endif #ifdef SIMULATED const bool atomic::simulated = true; #else const bool atomic::simulated = false; #endif atomic_t atomic::counter::operator++() volatile { return fetch_add(1) + 1; } atomic_t atomic::counter::operator--() volatile { return fetch_sub(1) - 1; } atomic_t atomic::counter::operator+=(atomic_t change) volatile { return fetch_add(change) + change; } atomic_t atomic::counter::operator-=(atomic_t change) volatile { return fetch_sub(change) - change; } } // namespace ucommon ucommon-6.4.4/corelib/Makefile.in0000664000175000017500000006063412557431663013636 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015 Cherokees of Idaho. # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = corelib DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/autoconf/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/ucommon-config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libucommon_la_LIBADD = am_libucommon_la_OBJECTS = object.lo linked.lo string.lo mapped.lo \ counter.lo bitmap.lo timer.lo memory.lo socket.lo access.lo \ thread.lo fsys.lo cpr.lo vector.lo xml.lo stream.lo persist.lo \ keydata.lo numbers.lo datetime.lo unicode.lo atomic.lo file.lo \ regex.lo protocols.lo containers.lo tcpbuffer.lo shell.lo \ typeref.lo libucommon_la_OBJECTS = $(am_libucommon_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libucommon_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libucommon_la_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/autoconf/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(libucommon_la_SOURCES) DIST_SOURCES = $(libucommon_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CHECKFLAGS = @CHECKFLAGS@ CMAKE_CURRENT_SOURCE_DIR = @CMAKE_CURRENT_SOURCE_DIR@ CMAKE_INSTALL_FULL_DATADIR = @CMAKE_INSTALL_FULL_DATADIR@ CMAKE_INSTALL_FULL_INCLUDEDIR = @CMAKE_INSTALL_FULL_INCLUDEDIR@ CMAKE_INSTALL_FULL_LIBDIR = @CMAKE_INSTALL_FULL_LIBDIR@ CMAKE_INSTALL_PREFIX = @CMAKE_INSTALL_PREFIX@ COMPAT = @COMPAT@ COMPAT_CONFIG = @COMPAT_CONFIG@ COMPAT_PC = @COMPAT_PC@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_VERSION = @LT_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MODULE_FLAGS = @MODULE_FLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OPENSSL_CFLAGS = @OPENSSL_CFLAGS@ OPENSSL_LIBS = @OPENSSL_LIBS@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PKG_SECURE_LIBS = @PKG_SECURE_LIBS@ PKG_UCOMMON_FLAGS = @PKG_UCOMMON_FLAGS@ PKG_UCOMMON_INCLUDES = @PKG_UCOMMON_INCLUDES@ PKG_UCOMMON_LIBS = @PKG_UCOMMON_LIBS@ RANLIB = @RANLIB@ SECURE = @SECURE@ SECURE_LIBS = @SECURE_LIBS@ SECURE_LOCAL = @SECURE_LOCAL@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ UCOMMON_CFGPATH = @UCOMMON_CFGPATH@ UCOMMON_FLAGS = @UCOMMON_FLAGS@ UCOMMON_INCLUDES = @UCOMMON_INCLUDES@ UCOMMON_LIBC = @UCOMMON_LIBC@ UCOMMON_LIBS = @UCOMMON_LIBS@ UCOMMON_LINKED = @UCOMMON_LINKED@ UCOMMON_LOCALE = @UCOMMON_LOCALE@ UCOMMON_PREFIX = @UCOMMON_PREFIX@ UCOMMON_VARPATH = @UCOMMON_VARPATH@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ includes = @includes@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ libs = @libs@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ MAINTAINERCLEANFILES = Makefile.in Makefile RELEASE = -version-info $(LT_VERSION) AM_CXXFLAGS = -I$(top_srcdir)/inc $(UCOMMON_FLAGS) lib_LTLIBRARIES = libucommon.la libucommon_la_LDFLAGS = @UCOMMON_LIBS@ $(RELEASE) libucommon_la_SOURCES = object.cpp linked.cpp string.cpp mapped.cpp \ counter.cpp bitmap.cpp timer.cpp memory.cpp socket.cpp access.cpp \ thread.cpp fsys.cpp cpr.cpp vector.cpp xml.cpp stream.cpp persist.cpp \ keydata.cpp numbers.cpp datetime.cpp unicode.cpp atomic.cpp file.cpp \ regex.cpp protocols.cpp containers.cpp tcpbuffer.cpp shell.cpp \ typeref.cpp all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu corelib/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu corelib/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libucommon.la: $(libucommon_la_OBJECTS) $(libucommon_la_DEPENDENCIES) $(EXTRA_libucommon_la_DEPENDENCIES) $(AM_V_CXXLD)$(libucommon_la_LINK) -rpath $(libdir) $(libucommon_la_OBJECTS) $(libucommon_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/access.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atomic.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitmap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/containers.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/counter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datetime.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsys.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keydata.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linked.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mapped.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/numbers.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/persist.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocols.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shell.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcpbuffer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/typeref.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unicode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vector.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ucommon-6.4.4/corelib/Makefile.am0000664000175000017500000000211112555173716013607 00000000000000# Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015 Cherokees of Idaho. # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. MAINTAINERCLEANFILES = Makefile.in Makefile RELEASE = -version-info $(LT_VERSION) AM_CXXFLAGS = -I$(top_srcdir)/inc $(UCOMMON_FLAGS) lib_LTLIBRARIES = libucommon.la libucommon_la_LDFLAGS = @UCOMMON_LIBS@ $(RELEASE) libucommon_la_SOURCES = object.cpp linked.cpp string.cpp mapped.cpp \ counter.cpp bitmap.cpp timer.cpp memory.cpp socket.cpp access.cpp \ thread.cpp fsys.cpp cpr.cpp vector.cpp xml.cpp stream.cpp persist.cpp \ keydata.cpp numbers.cpp datetime.cpp unicode.cpp atomic.cpp file.cpp \ regex.cpp protocols.cpp containers.cpp tcpbuffer.cpp shell.cpp \ typeref.cpp ucommon-6.4.4/corelib/keydata.cpp0000664000175000017500000002440212555235012013674 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include #include namespace ucommon { keydata::keyvalue::keyvalue(keyfile *allocator, keydata *section, const char *kv, const char *dv) : OrderedObject(§ion->index) { assert(allocator != NULL); assert(section != NULL); assert(kv != NULL); id = allocator->dup(kv); if(dv) value = allocator->dup(dv); else value = ""; } keydata::keydata(keyfile *file, const char *id) : OrderedObject(&file->index), index() { assert(file != NULL); assert(id != NULL); name = file->dup(id); root = file; } keydata::keydata(keyfile *file) : OrderedObject(), index() { root = file; name = "-"; } const char *keydata::get(const char *key) const { assert(key != NULL); iterator keys = begin(); while(is(keys)) { if(eq_case(key, keys->id)) return keys->value; keys.next(); } return NULL; } void keydata::clear(const char *key) { assert(key != NULL); iterator keys = begin(); while(is(keys)) { if(eq_case(key, keys->id)) { keys->delist(&index); return; } keys.next(); } } void keydata::set(const char *key, const char *value) { assert(key != NULL); void *mem = root->alloc(sizeof(keydata::keyvalue)); keydata::iterator keys = begin(); while(is(keys)) { if(eq_case(key, keys->id)) { keys->delist(&index); break; } keys.next(); } new(mem) keydata::keyvalue(root, this, key, value); } keyfile::keyfile(size_t pagesize) : memalloc(pagesize), index() { errcode = 0; defaults = NULL; } keyfile::keyfile(const char *path, size_t pagesize) : memalloc(pagesize), index() { errcode = 0; defaults = NULL; load(path); } keyfile::keyfile(const keyfile& copy, size_t pagesize) : memalloc(pagesize), index() { errcode = 0; defaults = NULL; load(©); } void keyfile::assign(keyfile& source) { errcode = source.errcode; defaults = source.defaults; index.copy(source.index); memalloc::assign(source); source.errcode = 0; source.defaults = NULL; source.index.reset(); } void keyfile::release(void) { defaults = NULL; index.reset(); memalloc::purge(); } keydata *keyfile::get(const char *key) const { assert(key != NULL); iterator keys = begin(); while(is(keys)) { if(eq_case(key, keys->name)) return *keys; keys.next(); } return NULL; } keydata *keyfile::create(const char *id) { assert(id != NULL); void *mem = alloc(sizeof(keydata)); keydata *old = get(id); if(old) old->delist(&index); return new(mem) keydata(this, id); } #ifdef _MSWINDOWS_ bool keyfile::save(HKEY keys, keydata *section, const char *path) { HKEY subkey; if(path) { if(RegCreateKeyEx(keys, path, 0L, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &subkey, NULL) == ERROR_SUCCESS) { save(subkey, section); RegCloseKey(subkey); } else errcode = EBADF; return false; } if(!section) { if(defaults) save(keys, defaults); linked_pointer kp = begin(); while(is(kp)) { if(RegCreateKeyEx(keys, kp->get(), 0L, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &subkey, NULL) == ERROR_SUCCESS) { save(subkey, *kp); RegCloseKey(subkey); } kp.next(); } } else { linked_pointer kv = section->begin(); while(is(kv)) { const char *value = kv->value; RegSetValueEx(keys, kv->id, 0L, REG_SZ, (const BYTE *)value, (DWORD)strlen(value) + 1); } } return true; } void keyfile::load(HKEY keys, keydata *section, const char *path) { DWORD index = 0; TCHAR keyvalue[256]; TCHAR keyname[4096]; DWORD ksize = sizeof(keyname); DWORD vsize, vtype; FILETIME fTime; HKEY subkey; if(path) { if(RegOpenKeyEx(keys, path, 0, KEY_READ, &subkey) == ERROR_SUCCESS) { load(subkey, section); RegCloseKey(subkey); } else errcode = EBADF; return; } while(!section && RegEnumKeyEx(keys, index++, keyname, &ksize, NULL, NULL, NULL, &fTime) == ERROR_SUCCESS) { if(RegOpenKeyEx(keys, keyname, 0, KEY_READ, &subkey) == ERROR_SUCCESS) { section = create(keyname); load(subkey, section); RegCloseKey(subkey); } ksize = sizeof(keyname); } index = 0; vsize = sizeof(keyvalue); if(vsize > size() - 64) vsize = size() - 64; while((RegEnumValue(keys, index++, keyname, &ksize, NULL, &vtype, (BYTE *)keyvalue, &vsize) == ERROR_SUCCESS) && (vtype == REG_SZ) && (keyname[0] != 0)) { if(section) section->set(keyname, keyvalue); else defaults->set(keyname, keyvalue); ksize = sizeof(keyname); vsize = sizeof(keyvalue); if(vsize > size() - 64) vsize = size() - 64; } } #endif void keyfile::load(const keydata *copy) { keydata *section = get(copy->get()); if(!section) section = create(copy->get()); linked_pointer vp = copy->begin(); while(is(vp)) { section->set(vp->id, vp->value); vp.next(); } } void keyfile::load(const keyfile *copy) { linked_pointer vp = (keydata::keyvalue*)NULL; if(copy->defaults) vp = copy->defaults->begin(); if(copy->defaults && !defaults) { void *mem = alloc(sizeof(keydata)); defaults = new(mem) keydata(this); } while(is(vp)) { defaults->set(vp->id, vp->value); vp.next(); } keydata *section; linked_pointer kp = copy->begin(); while(is(kp)) { vp = kp->begin(); section = get(kp->get()); if(!section) section = create(kp->get()); while(section && is(vp)) { section->set(vp->id, vp->value); vp.next(); } kp.next(); } } bool keyfile::save(const char *path) { assert(path != NULL); if(!path[0]) return false; #ifdef _MSWINDOWS_ if(eq(path, "~\\", 2)) return save(HKEY_CURRENT_USER, NULL, path); else if(eq(path, "-\\", 2)) return save(HKEY_LOCAL_MACHINE, NULL, path); #endif FILE *fp = fopen(path, "w"); if(!fp) { errcode = EBADF; return false; } linked_pointer vp = (keydata::keyvalue*)NULL; if(defaults) vp = defaults->begin(); while(is(vp)) { if(strchr(vp->value, '\"')) fprintf(fp, "%s=%s\n", vp->id, vp->value); else fprintf(fp, "%s=\"%s\"\n", vp->id, vp->value); vp.next(); } fprintf(fp, "\n"); linked_pointer kp = begin(); while(is(kp)) { fprintf(fp, "[%s]\n", kp->get()); vp = kp->begin(); while(is(vp)) { if(strchr(vp->value, '\"')) fprintf(fp, "%s=%s\n", vp->id, vp->value); else fprintf(fp, "%s=\"%s\"\n", vp->id, vp->value); vp.next(); } fprintf(fp, "\n"); kp.next(); } fclose(fp); return true; } void keyfile::load(const char *path) { assert(path != NULL); if(!path[0]) return; #ifdef _MSWINDOWS_ if(eq(path, "~\\", 2)) { load(HKEY_CURRENT_USER, NULL, path); return; } else if(eq(path, "-\\", 2)) { load(HKEY_LOCAL_MACHINE, NULL, path); return; } #endif char linebuf[1024]; char *lp = linebuf; char *ep; size_t size = sizeof(linebuf); FILE *fp = fopen(path, "r"); keydata *section = NULL; const char *key; char *value; errcode = 0; if(!fp) { errcode = EBADF; return; } if(!defaults) { void *mem = alloc(sizeof(keydata)); defaults = new(mem) keydata(this); } for(;;) { *lp = 0; if(NULL == fgets(lp, (socksize_t)size, fp)) { errcode = ferror(fp); lp[0] = 0; } else String::chop(lp, "\r\n\t "); ep = lp + strlen(lp); if(ep != lp) { --ep; if(*ep == '\\') { lp = ep; size = (linebuf + sizeof(linebuf) - ep); continue; } } if(!linebuf[0] && feof(fp)) break; lp = linebuf; while(isspace(*lp)) ++lp; if(!*lp) goto next; if(*lp == '[') { ep = strchr(lp, ']'); if(!ep) goto next; *ep = 0; lp = String::strip(++lp, " \t"); section = get(lp); if (!section) section = create(lp); goto next; } else if(!isalnum(*lp) || !strchr(lp, '=')) goto next; ep = strchr(lp, '='); *ep = 0; key = String::strip(lp, " \t"); value = String::strip(++ep, " \t\r\n"); value = String::unquote(value, "\"\"\'\'{}()"); if(section) section->set(key, value); else defaults->set(key, value); next: lp = linebuf; size = sizeof(linebuf); } fclose(fp); } } // namespace ucommon ucommon-6.4.4/corelib/shell.cpp0000664000175000017500000015707412551014424013373 00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015 Cherokees of Idaho. // // This file is part of GNU uCommon C++. // // GNU uCommon C++ is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // GNU uCommon C++ 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with GNU uCommon C++. If not, see . #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #ifdef _MSWINDOWS_ #include #include #include #else #include #include #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_TERMIOS_H #include #endif #ifdef HAVE_TERMIO_H #include #endif #endif #ifdef HAVE_SYS_RESOURCE_H #include #include #endif #ifdef HAVE_SETLOCALE #include #else #define setlocale(s, t) #endif #ifndef HAVE_LIBINTL_H #undef HAVE_GETTEXT #endif #ifdef HAVE_GETTEXT #include #else #define dgettext(d, s) s #define gettext(s) s #define bindtextdomain(s, t) #define textdomain(s) #endif #ifdef HAVE_SYSLOG_H #include #endif #ifndef OPEN_MAX #define OPEN_MAX 20 #endif #ifndef WEXITSTATUS #define WEXITSTATUS(status) ((unsigned)(status) >> 8) #endif #ifndef _PATH_TTY #define _PATH_TTY "/dev/tty" #endif namespace ucommon { static shell::loglevel_t errlevel = shell::WARN; static shell::logmode_t errmode = shell::NONE; static const char *errname = NULL; static shell::logproc_t errproc = (shell::logproc_t)NULL; static mutex_t symlock; static char **_orig = NULL; static shell::Option *ofirst = NULL, *olast = NULL; static const char *_domain = NULL; static shell::exitproc_t _exitproc = NULL; static shell::numeric_t numeric_mode = shell::NO_NUMERIC; static long numeric_value = 0l; shell::Option::Option(char shortopt, const char *longopt, const char *value, const char *help) : LinkedObject() { if(olast) { olast->Next = this; olast = this; } else ofirst = olast = this; while(longopt && *longopt == '-') ++longopt; short_option = shortopt; long_option = longopt; uses_option = value; help_string = help; trigger_option = false; } shell::Option::~Option() { } void shell::Option::reset(void) { ofirst = olast = NULL; } LinkedObject *shell::Option::first(void) { return ofirst; } void shell::Option::disable(void) { short_option = 0; long_option = NULL; help_string = NULL; uses_option = NULL; } shell::flagopt::flagopt(char short_option, const char *long_option, const char *help_string, bool single_use) : shell::Option(short_option, long_option, NULL, help_string) { single = single_use; counter = 0; } const char *shell::flagopt::assign(const char *value) { if(single && counter) return shell::errmsg(shell::OPTION_USED); ++counter; return NULL; } shell::numericopt::numericopt(char short_option, const char *long_option, const char *help_string, const char *type, long def_value) : shell::Option(short_option, long_option, type, help_string) { used = false; number = def_value; } const char *shell::numericopt::assign(const char *value) { char *endptr = NULL; if(used) return errmsg(shell::OPTION_USED); used = true; number = strtol(value, &endptr, 0); if(!endptr || *endptr != 0) return errmsg(shell::BAD_VALUE); return NULL; } shell::counteropt::counteropt(char short_option, const char *long_option, const char *help_string, const char *type, long def_value) : shell::Option(short_option, long_option, type, help_string) { used = false; number = def_value; trigger_option = true; } const char *shell::counteropt::assign(const char *value) { char *endptr = NULL; // trigger option mode received... if(value == NULL) { ++number; used = true; return NULL; } if(used) return errmsg(shell::OPTION_USED); used = true; number = strtol(value, &endptr, 0); if(!endptr || *endptr != 0) return errmsg(shell::BAD_VALUE); return NULL; } shell::groupopt::groupopt(const char *help_string) : shell::Option(0, NULL, NULL, help_string) { } const char *shell::groupopt::assign(const char *value) { return NULL; } shell::stringopt::stringopt(char short_option, const char *long_option, const char *help_string, const char *type, const char *def_value) : shell::Option(short_option, long_option, type, help_string) { used = false; text = def_value; } const char *shell::stringopt::assign(const char *value) { if(used) return shell::errmsg(shell::OPTION_USED); text = value; used = true; return NULL; } shell::charopt::charopt(char short_option, const char *long_option, const char *help_string, const char *type, char def_value) : shell::Option(short_option, long_option, type, help_string) { used = false; code = def_value; } const char *shell::charopt::assign(const char *value) { long number; char *endptr = NULL; if(used) return shell::errmsg(shell::OPTION_USED); used = true; if(value[1] == 0) { code = value[0]; return NULL; } number = strtol(value, &endptr, 0); if(!endptr || *endptr != 0) return errmsg(shell::BAD_VALUE); if(number < 0 || number > 255) return errmsg(shell::BAD_VALUE); code = (char)(number); return NULL; } void shell::collapse(LinkedObject *first) { char **argv = _argv = (char **)mempager::_alloc(sizeof(char **) * (_argc + 1)); linked_pointer ap = first; while(is(ap)) { *(argv++) = ap->item; ap.next(); } *argv = NULL; } void shell::set0(char *argv0) { char prefix[256]; if(_argv0) return; if(argv0 && *argv0 != '/' && *argv0 != '\\' && argv0[1] != ':') { fsys::prefix(prefix, sizeof(prefix)); String::add(prefix, sizeof(prefix), "/"); String::add(prefix, sizeof(prefix), argv0); } else String::set(prefix, sizeof(prefix), argv0); argv0 = _exedir = dup(prefix); _argv0 = strrchr(argv0, '/'); #ifdef _MSWINDOWS_ if(!_argv0) _argv0 = strrchr(argv0, '\\'); if(!_argv0) _argv0 = strchr(argv0, ':'); #endif if(!_argv0) _argv0 = argv0; else (*_argv0++) = 0; if(eq(_argv0, "lt-", 3)) _argv0 += 3; // _argv0 = dup(_argv0); #ifdef _MSWINDOWS_ char *ext = strrchr(_argv0, '.'); if(eq_case(ext, ".exe") || eq_case(ext, ".com")) *ext = 0; #endif if(!_domain) bind(_argv0); } shell::shell(size_t pagesize) : mempager(pagesize) { _exedir = NULL; _argv0 = NULL; _argv = NULL; _argc = 0; _syms = NULL; } shell::shell(const char *string, size_t pagesize) : mempager(pagesize) { _argv0 = NULL; _argv = NULL; _argc = 0; _syms = NULL; parse(string); } shell::shell(int argc, char **argv, size_t pagesize) : mempager(pagesize) { _argv0 = NULL; _argv = NULL; _argc = 0; _syms = NULL; parse(argc, argv); } static const char *msgs[] = { _TEXT("missing command line arguments"), _TEXT("missing argument for option"), _TEXT("option does not have argument"), _TEXT("unknown command option"), _TEXT("option already used"), _TEXT("invalid argument used"), _TEXT("numeric value already set"), NULL}; const char *shell::errmsg(errmsg_t id) { return dgettext("ucommon", msgs[id]); } void shell::errmsg(errmsg_t id, const char *text) { msgs[id] = shell::text(text); } void shell::setNumeric(numeric_t mode) { numeric_mode = mode; numeric_value = 0l; } long shell::getNumeric(void) { return numeric_value; } unsigned shell::count(char **argv) { unsigned count = 0; while(argv && argv[count]) ++count; return count; } void shell::help(void) { linked_pointer