ucommon-7.0.0/0000755000175000017500000000000012633254127010201 500000000000000ucommon-7.0.0/cmake-abi.sh0000775000175000017500000000157112570431073012274 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-7.0.0/PKGBUILD.in0000664000175000017500000000117612570431073011656 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-7.0.0/SUPPORT0000664000175000017500000000077112570431073011224 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-7.0.0/ucommon-config.h.cmake0000644000175000017500000000704412606345104014272 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_OPENSSL_RSA_H 1 #cmakedefine HAVE_STDATOMIC_H 1 #cmakedefine HAVE_STDALIGN_H 1 #cmakedefine POSIX_TIMERS 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-7.0.0/inc/0000755000175000017500000000000012633254127010752 500000000000000ucommon-7.0.0/inc/ucommon/0000755000175000017500000000000012633254127012427 500000000000000ucommon-7.0.0/inc/ucommon/fsys.h0000644000175000017500000005007212606345104013504 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_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. */ fsys& 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. */ fsys& operator*=(fd_t& descriptor); /** * Assing file descriptor from system descriptor. * @param descriptor to dup from. */ fsys& 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); static stringref_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; __DELETE_COPY(dso); 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-7.0.0/inc/ucommon/thread.h0000644000175000017500000006437612622213473014004 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. * @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 #ifndef _UCOMMON_CONDITION_H_ #include #endif namespace ucommon { /** * A generic and portable implementation of Read/Write locking. This * class implements 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 implemetations 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 implemented to support exclusive_lock and * shared_lock referencing. Because of the thread locking semantics this * is part of thread rather than condition, and was originally called * ThreadLock in older ucommon/commoncpp releases. Our autolock semantics * are also different as we protect a target object, not a rwlock instance. * @author David Sugar */ class __EXPORT RWLock : private ConditionalAccess, public __PROTOCOL ExclusiveProtocol, public __PROTOCOL SharedProtocol { private: __DELETE_COPY(RWLock); protected: unsigned writers; pthread_t writeid; virtual void _share(void) __OVERRIDE; virtual void _lock(void) __OVERRIDE; virtual void _unlock(void) __OVERRIDE; virtual void _unshare(void) __OVERRIDE; public: typedef autoshared autoreader; typedef autoexclusive autowriter; /** * Apply automatic 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 reader { private: const void *object; __DELETE_COPY(reader); public: /** * Create an unitialized instance of guard. Usually used with a * guard = operator. */ reader(); /** * Construct a guard for a specific object. * @param object to guard. */ reader(const void *object); /** * Release mutex when guard falls out of scope. */ ~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); } /** * 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 lock(const void *object, timeout_t timeout = Timer::inf); }; /** * Apply automatic 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 writer { private: const void *object; __DELETE_COPY(writer); public: /** * Create an unitialized instance of guard. Usually used with a * guard = operator. */ writer(); /** * Construct a guard for a specific object. * @param object to guard. */ writer(const void *object); /** * Release mutex when guard falls out of scope. */ ~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); } /** * 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 lock(const void *object, timeout_t timeout = Timer::inf); }; /** * Create an instance of a rwlock. */ RWLock(); /** * 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); /** * 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); }; /** * 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; __DELETE_COPY(TimedEvent); 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 __PROTOCOL ExclusiveProtocol { private: __DELETE_COPY(RecursiveMutex); protected: unsigned waiting; unsigned lockers; pthread_t locker; virtual void _lock(void) __OVERRIDE; virtual void _unlock(void) __OVERRIDE; public: typedef autoexclusive autolock; /** * 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); }; /** * 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 { private: __DELETE_COPY(ReusableAllocator); 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); }; /** * 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 __PROTOCOL ExclusiveProtocol { private: __DELETE_COPY(Mutex); protected: mutable pthread_mutex_t mlock; virtual void _lock(void) __OVERRIDE; virtual void _unlock(void) __OVERRIDE; public: typedef autoexclusive autolock; /** * 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); }; /** * 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 AutoProtect { private: __DELETE_COPY(AutoProtect); protected: const void *object; /** * Create an unitialized instance of guard. Usually used with a * guard = operator. */ AutoProtect(); /** * 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); public: /** * Construct a guard for a specific object. * @param object to guard. */ AutoProtect(const void *object); /** * Release mutex when guard falls out of scope. */ ~AutoProtect(); inline operator bool() const { return object != NULL; } inline bool operator!() const { return object == NULL; } }; template class autoprotect : public AutoProtect { public: inline autoprotect() : AutoProtect() {}; inline autoprotect(const T *object) : AutoProtect(object) {}; inline void set(const T *object) { AutoProtect::set(object); } inline void release() { AutoProtect::release(); } inline autoprotect& operator=(const T* object) { AutoProtect::set(object); return *this; } inline T* operator->() const { return static_cast(object); } inline T& operator*() const { __THROW_DEREF(object); return *(static_cast(object)); } }; /** * 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 { private: __DELETE_COPY(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: class __EXPORT Local : public LinkedObject { private: friend class Thread; pthread_key_t key; static LinkedObject *list; __DELETE_COPY(Local); protected: Local(); virtual void release(void *instance) = 0; virtual void *allocate(); public: ~Local(); void *operator*(); void set(void *instance); void *get(void); inline void clear() { set(nullptr); } }; /** * 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); /** * Get cache line size. */ static size_t cache(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(); } static void release(void); }; /** * 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 { private: __DELETE_COPY(JoinableThread); 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 __OVERRIDE; virtual void run(void) __OVERRIDE = 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 { private: __DELETE_COPY(DetachedThread); 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) __OVERRIDE; bool is_active(void) const __OVERRIDE; virtual void run(void) __OVERRIDE = 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); }; /** * 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 RWLock rwlock_t; /** * Convenience type for using recursive exclusive locks. */ typedef RecursiveMutex rexlock_t; #define __AUTOLOCK(x) autolock __autolock__(x) #define __AUTOPROTECT(x) AutoProtect __autolock__(x) #define __SYNC(x) for(bool _sync_flag_ = Mutex::protect(x); _sync_flag_; _sync_flag_ = !Mutex::release(x)) } // namespace ucommon #endif ucommon-7.0.0/inc/ucommon/stream.h0000664000175000017500000003466612622362734014036 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 #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 { private: __DELETE_COPY(StreamBuffer); 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() __OVERRIDE; 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) __OVERRIDE; /** * 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) __OVERRIDE; 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 pipe socket connection. This creates a stream between * a parent and child process. As a stream class, data can be * exchanged 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); __DELETE_COPY(pipestream); 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) __OVERRIDE; /** * 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) __OVERRIDE; 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 file class based on low level fsys io. This differs from * the normal fstream classes as it may apply to other kinds of * file streams. * * @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) __OVERRIDE; /** * 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) __OVERRIDE; 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); void rewind(void); /** * Get error flag from last i/o operation. * @return last error. */ inline int err(void) const {return fd.err();} }; /** * Stream class to read from a memory buffer. May optionally be 0 byte * terminated if no length is specified. */ class __EXPORT imemstream : protected std::streambuf, public std::istream { private: __DELETE_DEFAULTS(imemstream); size_t count; const uint8_t *pos, *bp; public: imemstream(const uint8_t *data, size_t size); imemstream(const char *data); int underflow() __OVERRIDE; int uflow() __OVERRIDE; inline size_t remains() const { return count; } inline const uint8_t *mem() const { return bp; } inline const char *chr() const { return (const char *)bp; } inline size_t len() const { return (size_t)(pos - bp) + count; } }; /** * Stream class to write to memory buffer. */ class __EXPORT omemstream : protected std::streambuf, public std::ostream { private: __DELETE_DEFAULTS(omemstream); size_t count; uint8_t *pos, *bp; bool zb; public: explicit omemstream(uint8_t *data, size_t size); omemstream(char *data, size_t size); int overflow(int ch) __OVERRIDE; inline size_t remains() const { return count; } inline uint8_t *mem() const { return bp; } inline char *chr() const { return (char *)bp; } inline size_t len() const { return (size_t)(pos - bp); } }; bool __EXPORT getline(std::istream& in, char *buffer, size_t size); bool __EXPORT putline(std::ostream& out, const char *buffer); /** * At least with gcc, linking of stream operators was broken. This provides * an auxillory class to solve the issue. */ class __EXPORT _stream_operators { private: __DELETE_DEFAULTS(_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 namespace std { extern __EXPORT iostream& null; } #endif #endif ucommon-7.0.0/inc/ucommon/object.h0000644000175000017500000002722112616070251013765 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 __PROTOCOL 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) __OVERRIDE; /** * Decrease reference count when released. If no longer retained, then * the object is dealloc'd. */ void release(void) __OVERRIDE; }; /** * 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 AutoObject { protected: ObjectProtocol *object; AutoObject(); /** * Construct an auto-pointer referencing an existing object. * @param object we point to. */ AutoObject(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. */ AutoObject(const AutoObject &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. */ ~AutoObject(); /** * 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 set(ObjectProtocol *object); public: /** * 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; }; /** * 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; __DELETE_DEFAULTS(SparseObjects); 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 { private: __DELETE_DEFAULTS(sarray); 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 T& at(unsigned offset) { return reference_cast(SparseObjects::get(offset)); } inline const T* operator()(unsigned offset) const { return get(offset); } inline void operator()(unsigned offset, T value) { T& ref = at(offset); ref = value; } private: __LOCAL ObjectProtocol *create(void) __FINAL { return new T; } }; /** * 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 AutoObject { public: /** * Create a pointer with no reference. */ inline object_pointer() : AutoObject() {} /** * Create a pointer with a reference to a heap object. * @param object we are referencing. */ inline object_pointer(T* object) : AutoObject(object) {} inline object_pointer(const object_pointer& copy) : AutoObject(copy) {} /** * Reference object we are pointing to through pointer indirection. * @return pointer to object we are pointing to. */ inline T* operator*() const { return protocol_cast(object); } /** * Reference object we are pointing to through function reference. * @return object we are pointing to. */ inline T& operator()() const { return reference_cast(object); } /** * Reference member of object we are pointing to. * @return reference to member of pointed object. */ inline T* operator->() const { return protocol_cast(object); } /** * Get pointer to object. * @return pointer or NULL if we are not referencing an object. */ inline T* get(void) const { return protocol_cast(object); } /** * Perform assignment operator to existing object. * @param typed object to assign. */ inline object_pointer& operator=(T *typed) { AutoObject::set(polypointer_cast(typed)); return *this; } inline object_pointer& operator=(const object_pointer& from) { AutoObject::set(polypointer_cast(from.object)); return *this; } /** * See if pointer is set. */ inline operator bool() const { return object != NULL; } /** * See if pointer is not set. */ inline bool operator!() const { return object == NULL; } }; } // namespace ucommon #endif ucommon-7.0.0/inc/ucommon/ucommon.h0000664000175000017500000001307112611715570014201 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 #endif #endif ucommon-7.0.0/inc/ucommon/cpr.h0000644000175000017500000001312212606345104013277 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 setenv(const char *s, const char *v, int p); __EXPORT int gettimeofday(struct timeval *tv, void *tz); } #else #include #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" { #if !defined(_MSWINDOWS_) && !defined(__QNX__) __EXPORT int stricmp(const char *s1, const char *s2); __EXPORT int strnicmp(const char *s1, const char *s2, size_t size); #elif defined(_MSWINDOWS_) 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 size) {return _strnicmp(s1, s2, size);} #endif __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); __EXPORT long tzoffset(struct timezone *tz = NULL); } template T *newp(T **handle) { return static_cast(cpr_newp(handle, sizeof(T))); } template void freep(T **handle) { cpr_freep(handle); } #endif ucommon-7.0.0/inc/ucommon/string.h0000644000175000017500000014763712622076126014047 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 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 __PROTOCOL 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; __DELETE_COPY(regex); 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 { private: __DELETE_COPY(cstring); protected: virtual void dealloc(void) __OVERRIDE; public: #pragma pack(1) size_t max; /**< Allocated size of cstring text */ size_t len; /**< Current length of cstring text */ 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(size_t size); /** * Used to clear a string at specified offset. * @param offset to clear from. */ void clear(size_t offset); /** * 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(size_t offset, const char *text, size_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); /** * Adjust size of our string buffer by deleting characters from * start of buffer. * @param number of characters to delete. */ void inc(size_t number); /** * Adjust size of our string buffer by deleting characters from * end of buffer. * @param number of characters to delete. */ void dec(size_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. * @return new cstring object. */ cstring *create(size_t size) 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; 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) __OVERRIDE; /** * Decrease retention of our reference counted cstring. May be overridden * for memstring which has fixed cstring object. */ virtual void release(void) __OVERRIDE; /** * 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(size_t size = 0); size_t getStringSize(void) const; public: const static size_t npos = ((size_t)-1); const static char eos = '\0'; /** * Create a new empty string object. */ String(); /** * Create an empty string with a buffer pre-allocated to a specified size. * @param size of buffer to allocate. */ String(size_t size); /** * 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(size_t size, const char *format, ...); /** * 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, size_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(size_t offset, size_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. */ size_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. */ size_t vprintf(const char *format, va_list args) __PRINTF(2, 0); /** * Get memory text buffer of string object. * @return writable string buffer. */ char *data(void); inline char *c_mem() { return data(); } /** * 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(size_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(size_t offset, const char *text, size_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, size_t offset, size_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, size_t offset, size_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(size_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(size_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(size_t offset, size_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(size_t offset, const char *text, size_t size = 0); /** * Clear a field of a filled string with filler. * @param offset to start of field to clear. */ void clear(size_t offset); /** * 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. */ size_t ccount(const char *list) const; /** * Count all characters in the string (strlen). * @return count of characters. */ size_t count(void) const; /** * Get the size of currently allocated space for string. * @return size allocated for text. */ size_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. */ size_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, size_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, size_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, size_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, size_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(size_t offset); void fill(size_t size, char fill); /** * 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(size_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. */ size_t len(void) const; /** * 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, size_t size) const; /** * Convenience method for left of string. * @param size of substring to gather. * @return string object holding substring. */ inline String left(size_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(size_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(size_t offset, size_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. */ const String operator+(const char *text) const; /** * 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+=(size_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-=(size_t number); /** * Delete a specified number of characters from start of string. * @param number of characters to delete. */ String& operator*=(size_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 short 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); inline static 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); /** * 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); /** * 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(data(), 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(data(), 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(data(), 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); static size_t b64size(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. * @param ws flag to skip whitespaces. * @return number of characters actually decoded. */ static size_t b64decode(uint8_t *binary, const char *string, size_t size, bool ws = false); static size_t b64count(const char *str, bool ws = false); /** * 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 uint8_t *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 size_t hexdump(const uint8_t *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. * @param whitespace flag to ignore. * @return number of bytes processed. */ static size_t hexpack(uint8_t *binary, const char *string, const char *format); static size_t hex2bin(const char *string, uint8_t *binary, size_t maxsize, bool wsflag = false); static size_t hexsize(const char *format); static size_t hexcount(const char *str, bool ws = false); }; /** * 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: const static size_t header = sizeof(String::cstring); private: bool resize(size_t size) __FINAL; void cow(size_t adj = 0) __FINAL; void release(void) __FINAL; protected: cstring *c_copy(void) const __OVERRIDE; 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. */ memstring(void *memory, size_t size); /** * Destroy memory string. */ ~memstring(); /** * Create a memory string with memory allocated from the heap. * @param size of string to allocate. Automatically adds control size. */ static memstring *create(size_t size); /** * 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. */ static memstring *create(MemoryProtocol *pager, size_t size); }; /** * 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 { if(offset >= S) __THROW_RANGE("charbuf offset"); 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) { if(offset >= S) __THROW_RANGE("charbuf range"); 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()); } }; /** * 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; } 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 != nullptr; } inline bool operator!() const { return data == nullptr; } 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-7.0.0/inc/ucommon/secure.h0000644000175000017500000006127612633253131014014 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 { class __SHARED AutoClear { private: __DELETE_DEFAULTS(AutoClear); protected: size_t size; void *pointer; AutoClear(size_t alloc); public: virtual ~AutoClear(); }; template class autoclear : public AutoClear { private: __DELETE_COPY(autoclear); public: autoclear() : AutoClear(sizeof(T)) {}; inline operator T() { return *(static_cast(pointer)); } inline T& operator*() { return *(static_cast(pointer)); } inline T* operator->() { return static_cast(pointer); } }; template <> class autoclear : public AutoClear { private: __DELETE_COPY(autoclear); public: autoclear(size_t len) : AutoClear(len) {}; inline char *operator*() { return (char *)pointer; } }; template <> class autoclear : public AutoClear { private: __DELETE_COPY(autoclear); public: autoclear(size_t len) : AutoClear(len) {}; inline char *operator*() { return (char *)pointer; } }; /** * 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; typedef enum {NONE, SIGNED, VERIFIED} verify_t; typedef stringref string; typedef byteref keybytes; private: __DELETE_COPY(secure); 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 ssl certificate object. */ typedef void *cert_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); /** * 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. * @param paths of certificates to use. * @return a basic client security context. */ static client_t client(const char *authority = NULL, const char *paths = 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 secure::string pass(const char *prompt, size_t size); static secure::string uuid(void); inline operator bool() const { return is_valid(); } inline bool operator!() const { return !is_valid(); } }; /** * 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... uint8_t 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 uint8_t *salt = NULL, unsigned rounds = 1); Key(const char *cipher, const uint8_t *iv, size_t ivsize); Key(const char *cipher, secure::keybytes& iv); Key(const char *cipher, const char *digest); ~Key(); void set(const uint8_t *key, size_t size); inline secure::keybytes key() { return secure::keybytes(keybuf, keysize); } inline secure::keybytes iv() { return secure::keybytes(ivbuf, blksize); } bool set(const secure::keybytes& key); 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 uint8_t *salt, unsigned rounds); bool set(const char *cipher, const secure::keybytes& iv); void assign(const char *key, size_t size = 0); void clear(void); secure::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; } bool operator==(const Key& other) const; inline bool operator!=(const Key& other) const { return !operator==(other); } static void options(const uint8_t *salt = NULL, unsigned rounds = 1); }; typedef Key *key_t; private: Key keys; size_t bufsize, bufpos; mode_t bufmode; uint8_t *bufaddr; void *context; __DELETE_COPY(Cipher); protected: virtual void push(uint8_t *address, size_t size); void release(void); public: Cipher(); Cipher(const key_t key, mode_t mode, uint8_t *address = NULL, size_t size = 0); virtual ~Cipher(); void set(uint8_t *address, size_t size = 0); void set(const key_t key, mode_t mode, uint8_t *address, size_t size = 0); inline secure::keybytes iv() { return keys.iv(); } inline secure::keybytes key() { return keys.key(); } /** * 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 uint8_t *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 uint8_t *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(uint8_t *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; uint8_t buffer[MAX_DIGEST_HASHSIZE / 8]; char textbuf[MAX_DIGEST_HASHSIZE / 8 + 1]; __DELETE_COPY(Digest); protected: void release(void); const uint8_t *get(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; } secure::keybytes key(void); secure::string str(void); inline operator secure::string() { return str(); } void set(const char *id); inline Digest& operator=(const char *id) { set(id); return *this; }; inline bool operator *=(const char *text) { return puts(text); } inline bool operator +=(const char *text) { return puts(text); } inline secure::string operator*() { return 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 secure::string uuid(const char *name, const uint8_t *ns = NULL); /** * Shortcut for short md5 digests if supported... * @param text to create a digest for. * @return digest string. */ static secure::string md5(const char *text); static secure::string sha1(const char *text); static secure::string sha256(const char *text); static secure::string sha384(const char *text); static secure::keybytes md5(const uint8_t *mem, size_t size); static secure::keybytes sha1(const uint8_t *mem, size_t size); static secure::keybytes sha256(const uint8_t *mem, size_t size); static secure::keybytes sha384(const uint8_t *mem, size_t size); }; /** * 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; uint8_t buffer[MAX_DIGEST_HASHSIZE / 8]; char textbuf[MAX_DIGEST_HASHSIZE / 8 + 1]; __DELETE_COPY(HMAC); protected: void release(void); const uint8_t *get(void); public: HMAC(const char *digest, const secure::keybytes& key); 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; } secure::string str(void); secure::keybytes key(void); inline operator secure::string() { return str(); } inline bool operator *=(const char *text) { return puts(text); } void set(const char *digest, const secure::keybytes& key); inline bool operator +=(const char *text) { return puts(text); } inline secure::string operator*() { return 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); static secure::keybytes sha256(secure::keybytes key, const uint8_t *mem, size_t size); static secure::keybytes sha384(secure::keybytes key, const uint8_t *mem, size_t soze); }; /** * Cryptographically relevant random numbers. This is used both to gather * entropy pools and pseudo-random values. * @author David Sugar */ class __SHARED Random { private: __DELETE_DEFAULTS(Random); public: /** * Push entropic seed. * @param buffer of random data to push. * @param size of buffer. * @return true if successful. */ static bool seed(const uint8_t *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(uint8_t *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(uint8_t *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 secure::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 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. Being based on tcpstream, it also * inherits the character protocol. 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 { private: __DELETE_COPY(sstream); protected: secure::session_t ssl; secure::bufio_t bio; secure::cert_t cert; secure::verify_t verified; bool server; ssize_t _write(const char *address, size_t size) __OVERRIDE; ssize_t _read(char *address, size_t size) __OVERRIDE; bool _wait(void) __OVERRIDE; public: /** * Construct a ssl client stream. The context will be loaded with * relevant certificates from secure::client(). * @param context to use */ sstream(secure::client_t context); /** * Construct a ssl server stream. The context will be loaded with * relevant certificates from secure::server(). * @param server instance of tcp socket. * @param context to use. * @param size of streaming buffer. */ sstream(const TCPServer *server, secure::server_t context, size_t size = 536); /** * Destroy ssl stream. Clean up any resources used. */ ~sstream(); /** * Open a connection to a ssl server. * @param host name to connect with. * @param service id to connect to. * @param size of stream buffer to use. */ void open(const char *host, const char *service, size_t size = 536); /** * Close a connection with a ssl server. */ void close(void); /** * Release all ssl resources. */ void release(void); int sync() __OVERRIDE; inline void flush(void) { sync(); } /** * Get peer (x509) certificate for current stream if present. * @return certificate of peer or nullptr if none. */ inline secure::cert_t certificate(void) const { return cert; } /** * Check if ssl session active, otherwise pure tcp. * @return true if ssl session. */ inline bool is_secure(void) const { return bio != NULL; } /** * Check if a peer certificate is present. * @return true if peer certificate. */ inline bool is_certificate(void) const { return cert != NULL; } /** * Check if peer certificate is verified through an authority. * @return true if verified peer. */ inline bool is_verified(void) const { return verified == secure::VERIFIED; } /** * Check if peer certificate is present and at least self-signed. * @return true if signed or verified peer. */ inline bool is_signed(void) const { return verified != secure::NONE; } }; #endif // can be specialized... template void clearmem(T &var) { memset(&var, 0, sizeof(var)); } typedef secure::string keystring_t; } // namespace ucommon #endif ucommon-7.0.0/inc/ucommon/shared.h0000664000175000017500000001177312570431074013777 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 . /** * Common thread shared data types we will use. This is for specialized * data types that include locking to be thread-safe. * @file ucommon/shared.h */ #ifndef _UCOMMON_SHARED_H_ #define _UCOMMON_SHARED_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 #ifndef _UCOMMON_TYPEREF_H_ #include #endif #ifndef _UCOMMON_THREAD_H_ #include #endif #ifndef _UCOMMON_SOCKET_H_ #include #endif namespace ucommon { class __EXPORT SharedRef : protected TypeRef { private: __DELETE_COPY(SharedRef); protected: Mutex lock; SharedRef(); TypeRef get(); void get(TypeRef& object); void put(TypeRef& object); }; template class sharedref : private SharedRef { private: __DELETE_COPY(sharedref); public: inline sharedref() : SharedRef() {}; inline operator typeref() { lock.acquire(); typeref ptr(ref); lock.release(); return ptr; } inline typeref operator*() { lock.acquire(); typeref ptr(ref); lock.release(); return ptr; } inline void put(typeref& ptr) { SharedRef::put(ptr); } inline sharedref& operator=(typeref ptr) { SharedRef::get(ptr); return *this; } inline sharedref& operator=(T obj) { typeref ptr(obj); SharedRef::get(ptr); return *this; } }; class __EXPORT MappedPointer { private: __DELETE_COPY(MappedPointer); protected: class __EXPORT Index : public LinkedObject { public: explicit Index(LinkedObject **origin); const void *key; void *value; }; condlock_t *lock; LinkedObject *free, **list; memalloc pager; size_t paths; MappedPointer(size_t indexes, condlock_t *locking = NULL, size_t paging = 0); ~MappedPointer(); LinkedObject *access(size_t path); LinkedObject *modify(size_t path); void release(void *obj); void insert(const void *key, void *value, size_t path); void replace(Index *ind, void *value); void remove(Index *ind, size_t path); public: static size_t keypath(const uint8_t *addr, size_t size); }; template inline size_t mapped_keypath(const T *addr) { if(!addr) return 0; return MappedPointer::keypath((const uint8_t *)addr, sizeof(T)); } template inline bool mapped_keyequal(const T* key1, const T* key2) { if(!key1 || !key2) return false; return !memcmp(key1, key2, sizeof(T)); } template<> inline size_t mapped_keypath(const char *addr) { if(!addr) return 0; return MappedPointer::keypath((const uint8_t *)addr, strlen(addr)); } template<> inline bool mapped_keyequal(const char *k1, const char *k2) { if(!k1 || !k2) return false; return eq(k1, k2); } template<> inline size_t mapped_keypath(const struct sockaddr *addr) { if(!addr) return 0; return MappedPointer::keypath((const uint8_t *)addr, Socket::len(addr)); } template<> inline bool mapped_keyequal(const struct sockaddr *s1, const struct sockaddr *s2) { if(!s1 || !s2) return false; return Socket::equal(s1, s2); } template class mapped_pointer : public MappedPointer { public: inline mapped_pointer(size_t indexes = 37, condlock_t *locking = NULL, size_t paging = 0) : MappedPointer(indexes, locking, paging) {} inline void release(V* object) { MappedPointer::release(object); } void remove(const K* key) { size_t path = mapped_keypath(key); linked_pointer ip = modify(path); while(is(ip)) { if(mapped_keyequal((const K*)(ip->key), key)) { MappedPointer::remove(*ip, path); return; } ip.next(); } lock->commit(); } V* get(const K* key) { linked_pointer ip = access(mapped_keypath(key)); while(is(ip)) { if(mapped_keyequal((const K*)(ip->key), key)) { return static_cast(ip->value); } ip.next(); } lock->release(); return nullptr; } void set(const K* key, V* ptr) { size_t path = mapped_keypath(key); linked_pointer ip = modify(path); while(is(ip)) { if(mapped_keyequal((const K*)(ip->key), key)) { replace(*ip, ptr); return; } } insert((const void *)key, (void *)ptr, path); } }; } // namespace #endif ucommon-7.0.0/inc/ucommon/mapref.h0000664000175000017500000002166512570431074014004 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 . /** * Maps of thread-safe strongly typed heap objects. This is used for * maps of smart pointers to immutable heap instances of object types. * Shared and exclusive locking is used based on lookup or modify operations. * @file ucommon/mapref.h */ #ifndef _UCOMMON_MAPREF_H_ #define _UCOMMON_MAPREF_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 #ifndef _UCOMMON_TYPEREF_H_ #include #endif #ifndef _UCOMMON_LINKED_H_ #include #endif #ifndef _UCOMMON_THREAD_H_ #include #endif namespace ucommon { class __EXPORT MapRef : public TypeRef { protected: class Map; class Instance; class __EXPORT Index : public LinkedObject { private: __DELETE_COPY(Index); public: friend class Map; explicit Index(LinkedObject **origin); Index(); Counted *key, *value; }; class __EXPORT Map : public Counted { private: __DELETE_COPY(Map); protected: friend class Instance; virtual void dealloc() __OVERRIDE; public: friend class MapRef; memalloc pool; condlock_t lock; LinkedObject *free, *last; size_t count, alloc; explicit Map(void *addr, size_t indexes, size_t paging = 0); inline LinkedObject **get(void) { return reinterpret_cast(((caddr_t)(this)) + sizeof(Map)); } Index *create(size_t path); Index *append(); void remove(Index *index, size_t path); LinkedObject *modify(size_t key = 0); LinkedObject *access(size_t key = 0); }; class __EXPORT Instance { protected: Map *map; LinkedObject *index; size_t path; Instance(); Instance(MapRef& from); explicit Instance(Map *map); Instance(const Instance& copy); void assign(const Instance& copy); void assign(MapRef& from); void drop(void); Counted *key(); Counted *value(); public: ~Instance(); void rewind(); bool next(); bool eol(); bool top(); inline operator bool() { return index != NULL; } inline bool operator!() { return index == NULL; } }; MapRef(size_t paths, size_t paging = 0); MapRef(const MapRef& copy); MapRef(); void assign(TypeRef& key, TypeRef& value); static Map *create(size_t paths, size_t paging = 0); linked_pointer access(size_t keyvalue = 0); linked_pointer modify(size_t keyvalue = 0); void append(TypeRef& value); void add(size_t path, TypeRef& key, TypeRef& value); void update(Index *ind, TypeRef& value); void remove(Index *ind, size_t path = 0); void release(); void commit(); public: size_t count(void); size_t used(void); void purge(void); static size_t index(size_t& key, const uint8_t *addr, size_t len); }; template inline size_t mapkeypath(typeref& object) { size_t path = sizeof(T); return MapRef::index(path, (const uint8_t *)(object()), sizeof(T)); } template<> inline size_t mapkeypath(typeref& object) { size_t path = 1; return MapRef::index(path, (const uint8_t *)(*object), object.len()); } template<> inline size_t mapkeypath(typeref& object) { size_t path = object.size(); return MapRef::index(path, *object, object.size()); } template class mapref : public MapRef { protected: bool erase(typeref& key) { size_t path = mapkeypath(key); linked_pointer ip = modify(path); while(is(ip)) { typeref kv(ip->key); if(is(kv) && kv == key) { MapRef::remove(*ip, path); MapRef::commit(); return true; } ip.next(); } MapRef::commit(); return false; } public: class instance : public MapRef::Instance { public: inline instance(const instance& copy) : Instance(static_cast(copy)) {}; inline instance(mapref& from) : Instance(static_cast(from)) {}; inline instance() : Instance() {}; inline typeref key() { return typeref(Instance::key()); } inline typeref value() { return typeref(Instance::value()); } inline instance& operator++() { next(); return *this; } inline instance& operator=(const instance& copy) { assign(static_cast(copy)); return *this; } inline instance& operator=(mapref& from) { assign(static_cast(from)); return *this; } }; inline mapref(const mapref& copy) : MapRef(copy) {}; inline mapref(size_t paths = 37, size_t paging = 0) : MapRef(paths, paging) {}; inline mapref& operator=(const mapref& copy) { TypeRef::set(copy); return *this; } inline instance operator*() { return instance(this); } void value(typeref& key, typeref& val) { size_t path = mapkeypath(key); linked_pointer ip = modify(path); while(is(ip)) { typeref kv(ip->key); if(is(kv) && kv == key) { update(*ip, val); commit(); return; } ip.next(); } add(path, key, val); commit(); } typeref at(typeref& key) { linked_pointer ip = access(mapkeypath(key)); while(is(ip)) { typeref kv(ip->key); if(is(kv) && kv == key) { typeref result(ip->value); release(); return result; } ip.next(); } release(); return typeref(); } typeref take(typeref& key) { size_t path = mapkeypath(key); linked_pointer ip = modify(path); while(is(ip)) { typeref kv(ip->key); if(is(kv) && kv == key) { typeref result(ip->value); if(is(result.is)) MapRef::remove(*ip, path); commit(); return result; } ip.next(); } commit(); return typeref(); } inline bool remove(typeref& key) { return erase(key); } inline bool remove(K k) { typeref key(k); return erase(key); } inline typeref operator()(typeref& key) { return at(key); } inline typeref operator()(K k) { typeref key(k); return at(key); } inline void operator()(typeref& key, typeref& val) { value(key, val); } inline void operator()(K k, V v) { typeref key(k); typeref val(v); value(key, val); } }; template class listref : public MapRef { protected: bool erase(typeref& value) { linked_pointer ip = modify(); while(ip) { typeref kv(ip->value); if(is(kv) && kv == value) { MapRef::remove(*ip); MapRef::commit(); return true; } ip.next(); } MapRef::commit(); return false; } public: class instance : public MapRef::Instance { public: inline instance(const instance& copy) : Instance(static_cast(copy)) {}; inline instance(listref& from) : Instance(static_cast(from)) {}; inline instance() : Instance() {}; inline const T& operator*() { return *(Instance::value()); } inline const T* operator->() { return Instance::value(); } inline instance& operator++() { next(); return *this; } inline instance& operator=(const instance& copy) { assign(static_cast(copy)); return *this; } inline instance& operator=(listref& from) { assign(static_cast(from)); return *this; } }; inline listref(const listref& copy) : MapRef(copy) {}; inline listref(size_t paging = 0) : MapRef(1, paging) {}; inline listref& operator=(const listref& copy) { TypeRef::set(copy); return *this; } inline instance operator*() { return instance(this); } inline listref& operator<<(typeref& value) { append(value); return *this; } inline listref& operator<<(T t) { typeref v(t); append(v); return *this; } inline bool remove(typeref& key) { return erase(key); } inline bool remove(T t) { typeref key(t); return erase(key); } inline typeref take(size_t offset) { linked_pointer ip = modify(); while(is(ip) && offset--) { ip.next(); } typeref v(ip->value); if(is(v)) MapRef::remove(*ip); commit(); return v; } inline typeref at(size_t offset) { linked_pointer ip = access(); while(ip && offset--) { ip.next(); } typeref v(ip->value); release(); return v; } inline typeref operator[](size_t offset) { return at(offset); } }; } // namespace #endif ucommon-7.0.0/inc/ucommon/typeref.h0000644000175000017500000004201512633253131014172 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_GENERICS_H_ #include #endif #ifndef _UCOMMON_OBJECT_H_ #include #endif #ifndef _UCOMMON_THREAD_H_ #include #endif namespace ucommon { class TypeRelease; class typeref_guard; /** * Smart pointer base class for auto-retained objects. The underlying * container is heap allocated and page aligned. A heap object is * automatically de-referenced by release during destruction. The smart * pointer is a protected base class used to derive strongly typed * templates. * @author David Sugar */ class __EXPORT TypeRef { protected: friend class ArrayRef; friend class SharedRef; friend class MapRef; friend class TypeRelease; class Release; public: /** * Heap base-class container for typeref objects. This uses atomic * reference counters for thread safety with maximal performance. This * is used as a protected base class used for strongly typed heap * containers through templates. * @author David Sugar */ class __EXPORT Counted : public __PROTOCOL ObjectProtocol { private: __DELETE_COPY(Counted); protected: friend class TypeRef; friend class TypeRelease; union { TypeRelease *autorelease; Counted *linkrelease; }; mutable Atomic::counter count; unsigned offset; size_t size; /** * Construction of aligned container. This is used to inform the * object of the underlying real address it exists on the heap * since malloc is not assured to be atomically aligned by default. * @param address of actual allocation. * @param size of object allocated. * @param ar pool to use */ explicit Counted(void *address, size_t size, TypeRelease *ar = NULL); /** * Release memory and delete object when no longer referenced. * This gets called with the atomic reference counter < 1, such * as when the last smart pointer de-references. */ virtual void dealloc(void); public: /** * Is this object not empty? * @return true if not empty. */ inline bool is() const { return (count.get() > 0); } /** * Number of retains (smart pointers) referencing us. * @return number of copies of pointers referencing. */ inline unsigned copies() const { return ((unsigned)count.get()); } inline TypeRelease *getRelease() const { return autorelease; } /** * Override delete to de-allocate actual heap. This * is used because the object is atomically aligned, but * the heap may not be. * @param address of our object. */ void operator delete(void *address); /** * Retain a copy of this object. Usually a smart pointer * referencing. */ void retain(); /** * Release a copy of this object. Only when the reference * count reaches 0 is it destroyed. */ void release(); }; protected: Counted *ref; // heap reference... /** * Create a smart pointer referencing an existing heap object. * @param object to reference. */ TypeRef(Counted *object); /** * Create a smart pointer based on another pointer. Both * pointers then reference the same object. * @param pointer instance to share reference with. */ TypeRef(const TypeRef& pointer); /** * Create a smart pointer referencing nothing. */ TypeRef(); /** * Set our smart pointer to a specific heap container. If * we were pointing to something already we release that. * @param object to reference. */ void set(Counted *object); /** * Assign from a guarded typeref. */ void assign(const typeref_guard& ref); /** * Adjust memory pointer to atomic boundry. * @param address that was allocated. * @return address for actual atomic aligned object. */ static caddr_t mem(caddr_t address); public: /** * Destroy pointer when falling out of scope. This de-references * the heap container. */ virtual ~TypeRef(); /** * Set our smart pointer based on another pointer instance. If * we are already referencing, we release the current container. * @param pointer instance to share reference with. */ void set(const TypeRef& pointer); /** * Manually release the current container. */ void clear(void); /** * Get size of referenced heap object. * @return size of container or 0 if none. */ size_t size(void) const; /** * Get number of references to container. * @return total number of pointers referencing container. */ unsigned copies() const; /** * Check if pointer currently has a heap container. * @return true if we are referencing a container. */ inline operator bool() const { return ref != NULL; } /** * Check if we are currently not pointing to anything. * @return true if not referencing a container. */ inline bool operator!() const { return ref == NULL; } /** * Special weak-public means to copy a container reference. * This uses the base class container which is not public, so * only derived type specific smart pointers can actually use * this method. It is made public because making it protected * actually makes it inaccessible to template derived classes. * @param target smart pointer object to set. * @param object to have it reference. */ inline static void put(TypeRef& target, Counted *object) { target.set(object); } bool is_released(void); }; class __EXPORT TypeRelease { public: inline TypeRelease() { delegate = nullptr; } inline TypeRelease(TypeRelease *target) { delegate = target; } virtual unsigned purge(); virtual caddr_t allocate(size_t size); protected: friend class TypeRef::Counted; TypeRelease *delegate; void enlist(TypeRef::Counted **root, TypeRef::Counted *obj); TypeRef::Counted *delist(TypeRef::Counted **root); virtual void release(TypeRef::Counted *obj); void dealloc(TypeRef::Counted *obj); inline size_t size(TypeRef::Counted *obj) { return obj->size; } }; extern __EXPORT TypeRelease auto_release; extern __EXPORT TypeRelease secure_release; extern __EXPORT TypeRelease release_later; class __EXPORT typeref_guard : protected TypeRef { private: friend class TypeRef; mutable Mutex sync; public: inline typeref_guard() : TypeRef() {} inline typeref_guard(const typeref_guard& copy) : TypeRef(copy) {} inline typeref_guard(const TypeRef& pointer) : TypeRef(pointer) {} void set(const TypeRef& pointer); inline typeref_guard& operator=(const TypeRef& pointer) { set(pointer); return *this; } }; template class typeref : public TypeRef { private: class value : public Counted { private: __DELETE_COPY(value); public: T data; inline value(caddr_t mem, const T& object, TypeRelease *ar = &R) : Counted(mem, sizeof(value), ar) { data = object; } }; public: inline typeref() : TypeRef() {} inline typeref(const typeref_guard& global) : TypeRef() { TypeRef::assign(global); } inline typeref(const typeref& copy) : TypeRef(copy) {} inline typeref(const T& object, TypeRelease *ar = &R) : TypeRef() { caddr_t p = R.allocate(sizeof(value)); TypeRef::set(new(mem(p)) value(p, object, ar)); } inline explicit typeref(Counted *object) : TypeRef(object) {} inline const T* operator->() const { if(!ref) return NULL; value *v = polystatic_cast(ref); return &(v->data); } inline const T& operator*() const { value *v = polystatic_cast(ref); __THROW_DEREF(v); return *(&(v->data)); } inline const T* operator()() const { value *v = polystatic_cast(ref); if(!v) return nullptr; return &(v->data); } inline operator const T&() const { value *v = polystatic_cast(ref); __THROW_DEREF(v); return *(&(v->data)); } inline typeref& operator=(const typeref_guard& ptr) { TypeRef::assign(ptr); return *this; } inline typeref& operator=(const typeref& ptr) { TypeRef::set(ptr); return *this; } inline bool operator==(const typeref& ptr) const { value *v1 = polystatic_cast(ref); value *v2 = polystatic_cast(ptr.ref); if(!v1 || !v2) return false; return v1->data == v2->data; } inline bool operator==(const T& obj) const { value *v = polystatic_cast(ref); if(!v) return false; return v->data == obj; } inline bool operator!=(const typeref& ptr) const { return !(*this == ptr); } inline bool operator!=(const T& obj) const { return !(*this == obj); } inline void set(T& object, TypeRelease *pool = &R) { clear(); caddr_t p = R.allocate(sizeof(value)); TypeRef::set(new(mem(p)) value(p, object, pool)); } inline typeref& operator=(T& object) { set(object); return *this; } }; // The specializations are done as simple template specializations so that the // hard parts can be hard-coded rather than inline members. This means we do // not pass the autorelease as a specialization here, but we can do a secondary // template that does use releases with a lot less overhead. template<> class __EXPORT typeref : public TypeRef { public: class value : public Counted { private: __DELETE_COPY(value); protected: friend class typeref; char mem[1]; value(caddr_t addr, size_t size, const char *str, TypeRelease *ar = &auto_release); void destroy(void); public: inline char *get() { return &mem[0]; } inline size_t len() { return strlen(mem); } inline size_t max() { return size; } inline operator char *() { return &mem[0]; } }; typeref(); typeref(const typeref& copy); typeref(const char *str, TypeRelease *ar = &auto_release); typeref(size_t size, TypeRelease *ar = &auto_release); inline typeref(const typeref_guard& global) : TypeRef() { TypeRef::assign(global); } inline explicit typeref(Counted *object) : TypeRef(object) {} inline explicit typeref(value *value) : TypeRef(value) {} const char *operator*() const; inline operator const char *() const { return operator*(); } size_t len() const; bool operator==(const typeref& ptr) const; bool operator==(const char *obj) const; bool operator==(value *chars) const; inline bool operator!=(const typeref& ptr) const { return !(*this == ptr); } inline bool operator!=(value *chars) const { return !(*this == chars); } inline bool operator!=(const char *obj) const { return !(*this == obj); } bool operator<(const typeref& ptr) const; inline bool operator>(const typeref& ptr) const { return (ptr < *this); } inline bool operator<=(const typeref& ptr) const { return !(*this > ptr); } inline bool operator>=(const typeref& ptr) const { return !(*this < ptr); } typeref& operator=(const typeref& objref); typeref& operator=(const char *str); typeref& operator=(value *chars); const typeref operator+(const char *str) const; const typeref operator+(const typeref& ptr) const; const char *operator()(ssize_t offset) const; void set(const char *str, TypeRelease *ar = &auto_release); void hex(const uint8_t *mem, size_t size, TypeRelease *ar = &auto_release); void b64(const uint8_t *mem, size_t size, TypeRelease *ar = &auto_release); void assign(value *chars); static void expand(value **handle, size_t size); static value *create(size_t size, TypeRelease *ar = &auto_release); static void destroy(value *bytes); }; template<> class __EXPORT typeref : public TypeRef { public: class value : public Counted { private: __DELETE_COPY(value); protected: friend class typeref; uint8_t mem[1]; value(caddr_t addr, size_t size, const uint8_t *data = nullptr, TypeRelease *ar = &auto_release); void destroy(void); public: inline size_t max() { return size; } inline uint8_t *get() { return &mem[0]; } inline operator uint8_t*() { return &mem[0]; } }; typeref(); typeref(const typeref& copy); typeref(uint8_t *str, size_t size, TypeRelease *ar = &auto_release); typeref(size_t size, TypeRelease *ar = &auto_release); typeref(bool mode, size_t bits, TypeRelease *ar = &auto_release); inline typeref(const typeref_guard& global) : TypeRef() { TypeRef::assign(global); } inline explicit typeref(Counted *object) : TypeRef(object) {} const uint8_t *operator*() const; inline operator const uint8_t *() const { return operator*(); } typeref& operator=(const typeref& objref); typeref& operator=(value *bytes); bool operator==(const typeref& ptr) const; bool operator==(value *bytes) const; inline bool operator!=(const typeref& ptr) const { return !(*this == ptr); } inline bool operator!=(value *bytes) const { return !(*this == bytes); } const typeref operator+(const typeref& ptr) const; void set(const uint8_t *str, size_t size, TypeRelease *ar = &auto_release); size_t set(bool bit, size_t offset, size_t bits = 1); size_t hex(const char *str, bool ws = false, TypeRelease *ar = &auto_release); size_t b64(const char *str, bool ws = false, TypeRelease *ar = &auto_release); uint8_t *data(void); bool get(size_t offset); size_t count(size_t offset, size_t bits = 1); void assign(value *bytes); typeref hex(); typeref b64(); static value *create(size_t size, TypeRelease *ar = &auto_release); static void destroy(value *bytes); }; // convenience classes that roll up autorelease behavior for strings and // byte arrays into templates. template class stringref : public typeref { public: inline stringref() : typeref() {} inline stringref(const stringref& copy) : typeref(copy) {} inline stringref(const char *str) : typeref(str, &R) {} inline stringref(size_t size) : typeref(size, &R) {} inline explicit stringref(Counted *object) : typeref(object) {} inline void set(const char *str) { typeref::set(str, &R); } inline static value *create(size_t size) { return typeref::create(size, &R); } inline static stringref promote(typeref& str) { stringref result = *str; return result; } }; template class byteref : public typeref { public: inline byteref() : typeref() {} inline byteref(uint8_t *str, size_t size) : typeref(str, size, &R) {} inline byteref(size_t size) : typeref(size, &R) {} inline byteref(bool mode, size_t bits) : typeref(mode, bits, &R) {} inline explicit byteref(Counted *object) : typeref(object) {} inline void set(const uint8_t *str, size_t size) { typeref::set(str, size, &R); } inline size_t hex(const char *str, bool ws = false) { return typeref::hex(str, ws, &R); } inline size_t b64(const char *str, bool ws = false) { return typeref::b64(str, ws, &R); } inline stringref hex() { typeref str = typeref::hex(); stringref result = *str; return result; } inline stringref b64() { typeref str = typeref::b64(); stringref result = *str; return result; } inline static value *create(size_t size) { return typeref::create(size, &R); } inline static byteref promote(typeref& str) { byteref result = *str; return result; } }; // a namespace for aliasing things we may typically use as a typeref namespace Type { typedef int32_t Integer; typedef double Real; typedef const char *Chars; typedef const uint8_t *Bytes; typedef const uint8_t *Bools; } typedef typeref::value *charvalues_t; typedef typeref::value *bytevalues_t; typedef typeref stringref_t; typedef typeref byteref_t; typedef typeref boolref_t; template inline typeref typeref_cast(T x) { return typeref(x); } } // namespace #endif ucommon-7.0.0/inc/ucommon/linked.h0000644000175000017500000011725312616070251013772 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 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 __PROTOCOL ObjectProtocol { private: friend class OrderedIndex; friend class NamedObject; protected: 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(); LinkedObject(const LinkedObject& from); public: virtual ~LinkedObject(); /** * Release list, mark as no longer linked. Inherited from base Object. */ virtual void release(void) __OVERRIDE; /** * Retain by marking as self referenced list. Inherited from base Object. */ virtual void retain(void) __OVERRIDE; /** * 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) __OVERRIDE; 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 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 { private: friend class DLinkedObject; friend class OrderedIndex; protected: /** * 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(); OrderedObject(const OrderedObject& from); 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 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 DLinkedObject : public OrderedObject { protected: friend class ObjectQueue; DLinkedObject *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. */ DLinkedObject(OrderedIndex *index); /** * Construct an unlinked object. */ DLinkedObject(); DLinkedObject(const DLinkedObject& from); /** * Delete linked list object. If it is a member of a list of objects, * then the list is reformed around us. */ virtual ~DLinkedObject(); 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 DLinkedObject *getPrev(void) const { return static_cast(Prev); } /** * Get next node in the list when iterating. * @return next node in list. */ inline DLinkedObject *getNext(void) const { return static_cast(LinkedObject::getNext()); } /** * Insert object behind our object. * @param object to add to list. */ void insertTail(DLinkedObject *object); /** * Insert object in front of our object. * @param object to add to list. */ void insertHead(DLinkedObject *object); /** * Insert object, method in derived object. * @param object to add to list. */ virtual void insert(DLinkedObject *object); /** * Insert object behind our object. * @param object to add to list. */ inline DLinkedObject& operator+=(DLinkedObject *object) { insertTail(object); return *this; } /** * Insert object in front of our object. * @param object to add to list. */ inline DLinkedObject& operator-=(DLinkedObject *object) { insertHead(object); return *this; } /** * Insert object in list with our object. * @param object to add to list. */ inline DLinkedObject& operator*=(DLinkedObject *object) { insert(object); return *this; } }; /** * 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 O { protected: __DELETE_COPY(linked_value); public: T value; /** * 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); value = 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); value = typed_value; } inline void set(const T& typed_value) { value = typed_value; } /** * Assign embedded value from related type. * @param typed_value to assign. */ inline linked_value& operator=(const T& typed_value) { value = typed_value; return *this; } inline T& operator*() { return value; } inline operator T&() { return value; } inline void operator()(const T data) { value = data; } }; /** * 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); } inline bool is() 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 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()); } }; /** * Convenience typedef for root pointers of single linked lists. */ typedef LinkedObject *LinkedIndex; typedef DLinkedObject LinkedList; // compatibility for older code } // namespace ucommon #endif ucommon-7.0.0/inc/ucommon/stl.h0000664000175000017500000000246612570431074013332 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 #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 ucommon-7.0.0/inc/ucommon/atomic.h0000644000175000017500000001104512633253131013767 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 #if defined(_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 { private: __DELETE_DEFAULTS(Atomic); public: /** * 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; __DELETE_COPY(counter); public: counter(atomic_t initial = 0); // optimized reference count semantics atomic_t fetch_retain() volatile; atomic_t fetch_release() volatile; // 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 __DELETE_COPY(spinlock); 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; }; class __EXPORT Aligned { private: __DELETE_DEFAULTS(Aligned); protected: void *address; size_t offset; Aligned(size_t object, size_t offset = 0); public: virtual ~Aligned(); }; template class aligned : public Aligned { protected: inline T* get() const { return static_cast(address); } public: inline aligned() : Aligned(sizeof(T), alignment) { new((caddr_t)address) T; } inline T& operator*() const { return *(static_cast(address)); } inline operator T&() { return *get(); } inline void operator()(T value) { *get() = value; } }; static bool is_lockfree(void); }; } // namespace ucommon #endif ucommon-7.0.0/inc/ucommon/mapped.h0000644000175000017500000003774212606345104013777 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; __DELETE_COPY(MappedMemory); 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); 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; __DELETE_DEFAULTS(MappedReuse); 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 { private: __DELETE_COPY(mapped_array); 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 { private: __DELETE_COPY(mapped_reuse); 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 { private: __DELETE_DEFAULTS(mapped_view); 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-7.0.0/inc/ucommon/condition.h0000644000175000017500000004422712616070251014512 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 . /** * Condition classes for thread sychronization and timing. * 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 recursive exclusive locks. Using only * conditionals means we are not dependent on platform specific pthread * implementations that may not implement 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/condition.h */ #ifndef _UCOMMON_CONDITION_H_ #define _UCOMMON_CONDITION_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 { /** * Condition Mutex to pair with conditionals. Separating the mutex means * we can apply it either paired with a condition variable, or shared * among multiple condition variables. * @author David Sugar */ class __EXPORT ConditionMutex { private: friend class ConditionVar; friend class autolock; __DELETE_COPY(ConditionMutex); protected: #if defined(_MSTHREADS_) mutable CRITICAL_SECTION mutex; #else mutable pthread_mutex_t mutex; #endif public: /** * Initialize and construct conditional. */ ConditionMutex(); /** * Destroy conditional, release any blocked threads. */ ~ConditionMutex(); #ifdef _MSTHREADS_ inline void lock(void) { EnterCriticalSection(&mutex); } inline void unlock(void) { LeaveCriticalSection(&mutex); } #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); } #endif class __EXPORT autolock { private: #ifdef _MSTHREADS_ CRITICAL_SECTION *mutex; #else pthread_mutex_t *mutex; #endif __DELETE_COPY(autolock); public: inline autolock(const ConditionMutex* 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 } }; }; /** * The condition Var allows multiple conditions to share a mutex. This * can be used to form specialized thread synchronizing classes such as * ordered sempahores, or to create thread completion lists. * @author David Sugar */ class __EXPORT ConditionVar { private: __DELETE_DEFAULTS(ConditionVar); protected: friend class ConditionList; #if defined(_MSTHREADS_) mutable CONDITION_VARIABLE cond; #else mutable pthread_cond_t cond; #endif ConditionMutex *shared; public: /** * Initialize and construct conditional. */ ConditionVar(ConditionMutex *mutex); /** * Destroy conditional, release any blocked threads. */ ~ConditionVar(); /** * 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_ void wait(void); void signal(void); void broadcast(void); #else /** * Wait (block) until signalled. */ inline void wait(void) { pthread_cond_wait(&cond, &shared->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 }; /** * 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 : protected ConditionMutex { private: __DELETE_COPY(Conditional); protected: friend class ConditionalAccess; friend class ConditionVar; #if defined(_MSTHREADS_) mutable CONDITION_VARIABLE cond; #else #ifndef __PTH__ class __LOCAL attribute { public: pthread_condattr_t attr; attribute(); }; __LOCAL static attribute attr; #endif mutable pthread_cond_t cond; #endif 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_ void wait(void); void signal(void); void broadcast(void); #else /** * 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(); friend class autolock; public: #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 { private: __DELETE_COPY(ConditionalAccess); protected: #if defined _MSTHREADS_ CONDITION_VARIABLE bcast; #else mutable pthread_cond_t bcast; #endif static unsigned max_sharing; 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); }; /** * 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 __PROTOCOL SharedProtocol { private: __DELETE_COPY(ConditionalLock); protected: class Context : public LinkedObject { private: __DELETE_COPY(Context); public: inline Context(LinkedObject **root) : LinkedObject(root) {} pthread_t thread; unsigned count; }; LinkedObject *contexts; virtual void _share(void) __OVERRIDE; virtual void _unshare(void) __OVERRIDE; 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 implementation 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 implementation 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; __DELETE_DEFAULTS(Barrier); 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 __PROTOCOL SharedProtocol, protected Conditional { protected: unsigned count, waits, used; virtual void _share(void) __OVERRIDE; virtual void _unshare(void) __OVERRIDE; __DELETE_COPY(Semaphore); public: typedef autoshared autosync; /** * 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(); } }; /** * Convenience type for using conditional locks. */ typedef ConditionalLock condlock_t; /** * Convenience type for scheduling access. */ typedef ConditionalAccess accesslock_t; /** * Convenience type for using counting semaphores. */ typedef Semaphore semaphore_t; /** * Convenience type for using thread barriers. */ typedef Barrier barrier_t; } // namespace ucommon #endif ucommon-7.0.0/inc/ucommon/access.h0000644000175000017500000002224312616070251013757 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 { /** * 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 ExclusiveProtocol { protected: virtual ~ExclusiveProtocol(); virtual void _lock(void) = 0; virtual void _unlock(void) = 0; public: /** * 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 Locking { private: ExclusiveProtocol *lock; __DELETE_COPY(Locking); public: /** * Create an instance of an exclusive object reference. * @param object containing Exclusive base class protocol to lock. */ Locking(ExclusiveProtocol *object); /** * Destroy reference to exclusively locked object, release lock. */ ~Locking(); /** * 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); }; }; /** * 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 SharedProtocol { protected: virtual ~SharedProtocol(); /** * Access interface to share lock the object. */ virtual void _share(void) = 0; virtual void _unshare(void) = 0; public: /** * 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 Locking { private: SharedProtocol *lock; int state; bool modify; public: /** * Create an instance of an exclusive object reference. * @param object containing Exclusive base class protocol to lock. */ Locking(SharedProtocol *object); Locking(const Locking& copy); Locking& operator=(const Locking& copy); /** * Destroy reference to shared locked object, release lock. */ ~Locking(); /** * 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); }; /** * 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); }; /** * 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: SharedProtocol *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(SharedProtocol *object); shared_access(const shared_access& copy); shared_access& operator=(const shared_access& copy); /** * 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); }; template class autoexclusive : private ExclusiveProtocol::Locking { private: __DELETE_DEFAULTS(autoexclusive); public: inline autoexclusive(T *lock) : Locking(polystatic_cast(lock)) {}; }; template class autoshared : private SharedProtocol::Locking { private: __DELETE_DEFAULTS(autoshared); public: inline autoshared(T *lock) : Locking(polystatic_cast(lock)) {}; }; // 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(x) exclusive_access __autolock__ = x #define __SHARE(x) shared_access __autolock__ = x } // namespace ucommon #endif ucommon-7.0.0/inc/ucommon/export.h0000664000175000017500000000347412570431074014051 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-7.0.0/inc/ucommon/unicode.h0000644000175000017500000004036212616070251014146 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 { protected: inline utf8() {}; inline utf8(const utf8& copy) {}; 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, char *text, size_t size); /** * 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, const char *cp, size_t len); /** * 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(const char *cp); /** * 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 void put(ucs4_t character, char *buf); }; /** * 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(size_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, size_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(size_t codepoint, size_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, size_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(size_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(size_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(size_t offset, size_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(size_t offset, size_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(size_t offset, const char *text, size_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 size_t count(void) const { return (size_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, size_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, size_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-7.0.0/inc/ucommon/counter.h0000644000175000017500000001301412606345104014172 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 value; } }; /** * 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-7.0.0/inc/ucommon/platform.h0000644000175000017500000003526112617437737014367 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 #include #if __cplusplus >= 201103L #include #endif #if defined(sun) && defined(unix) #include #endif #ifndef _UCOMMON_PLATFORM_H_ #define _UCOMMON_PLATFORM_H_ #define UCOMMON_ABI 7 #ifndef UCOMMON_SYSRUNTIME #ifndef NEW_STDCPP #define NEW_STDCPP #endif #define _UCOMMON_EXTENDED_ #include #define __THROW_SIZE(x) throw std::length_error(x) #define __THROW_RANGE(x) throw std::out_of_range(x) #define __THROW_RUNTIME(x) throw std::runtime_error(x) #define __THROW_ALLOC() throw std::bad_alloc() #define __THROW_DEREF(v) if(v == nullptr) \ throw std::runtime_error("Dereference NULL") #define __THROW_UNDEF(v,x) if(v == nullptr) throw std::runtime_error(x) #else #define __THROW_RANGE(x) abort() #define __THROW_SIZE(x) abort() #define __THROW_RUNTIME(x) abort() #define __THROW_ALLOC() abort() #define __THROW_DEREF(v) if(v == nullptr) abort() #define __THROW_UNDEF(v,x) if(v == nullptr) abort() #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 #ifdef UCOMMON_RTTI #define __PROTOCOL virtual template T protocol_cast(S *s) { return dynamic_cast(s); } #else #define __PROTOCOL template T protocol_cast(S *s) { return static_cast(s); } #endif #if defined(__GNUC__) && (__GNUC < 3) && !defined(_GNU_SOURCE) #define _GNU_SOURCE #endif #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 __GNUC_PREREQ__(3,3) #define __PRINTF(x,y) __attribute__ ((format (printf, x, y))) #define __SCANF(x, y) __attribute__ ((format (scanf, x, y))) #define __MALLOC __attribute__ ((malloc)) #define __NORETURN __attribute__ ((__noreturn__)) #endif #define __UNUSED(x) (void)x #if __cplusplus >= 201103L #define __ALIGNED(x) alignas(x) #else #ifdef _MSC_VER #define __ALIGNED(x) __declspec(align(x)) #else #define __ALIGNED(x) __attribute__(align(x)) #endif #endif #if __cplusplus < 201103L #define __FINAL #define __OVERRIDE #define __DELETED #define __DELETE_COPY(x) inline x(const x&);\ inline x& operator=(const x&) #define __DELETE_DEFAULTS(x) inline x();\ __DELETE_COPY(x) #else #define __FINAL final #define __OVERRIDE override #define __DELETED =delete #define __DELETE_COPY(x) inline x(const x&) =delete;\ inline x& operator=(const x&) =delete #define __DELETE_DEFAULTS(x) inline x() =delete;\ __DELETE_COPY(x) #endif #if __cplusplus <= 199711L && !defined(_MSC_VER) #if defined(__GNUC_MINOR__) && !defined(__clang__) #define nullptr __null #elif !defined(__clang__) || (defined(__clang__) && defined(__linux__)) const class nullptr_t { public: template inline operator T*() const { return 0; } template inline operator T C::*() const { return 0; } private: void operator&() const; } nullptr = {}; #endif #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 #if _MSC_VER < 1500 #warning "Probably won't build, need VS >= 2010 or later" #endif #endif // minimum required version requires conditional #ifdef _WIN32_WINNT #if _WIN32_WINNT < 0x0600 #undef _WIN32_WINNT #undef WINVER #endif #endif #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0600 #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 // 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 mingw can do native high performance win32 conditionals... #if defined(UCOMMON_WINPTHREAD) && __GNUC_PREREQ__(4, 8) && !defined(UCOMMON_SYSRUNTIME) #define __MINGW_WINPTHREAD__ #include // gnu libstdc++ now requires a win pthread typedef size_t stacksize_t; #else #define _MSTHREADS_ typedef DWORD pthread_t; typedef DWORD pthread_key_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(id, argc, argv) void WINAPI service_##id(DWORD argc, LPSTR *argv) #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 } #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, nullptr);}; 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, nullptr);}; 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 #define __PROGRAM(c,v) extern "C" int main(int c, char **v) #define PROGRAM_MAIN(argc, argv) extern "C" int main(int argc, char **argv) #define PROGRAM_EXIT(code) return code #endif #ifndef __SERVICE #define __SERVICE(id, c, v) void service_##id(int c, char **v) #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 : nullptr);} 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) if(s == nullptr) return nullptr; T ptr = dynamic_cast(s); __THROW_DEREF(ptr); return ptr; #else return static_cast(s); #endif } 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) { __THROW_DEREF(s); return *(static_cast(s)); } template inline T& reference_cast(T *pointer) { __THROW_DEREF(pointer); return *pointer; } template inline const T immutable_cast(T p) { return static_cast(p); } #endif ucommon-7.0.0/inc/ucommon/datetime.h0000644000175000017500000006324312616070251014317 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_TYPEREF_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. */ stringref_t 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. */ const Date operator+(long days) const; /** * Subtract days from a julian date in an expression. * @param days to subtract. * @return new date object with modified days. */ const Date operator-(long days) const; /** * 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. */ const Time operator+(long seconds) const; /** * Subtract seconds to the current time, wrap if 24 hours. * @param seconds to subtract. * @return new time object with modified value. */ const Time operator-(long seconds) const; /** * 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. */ stringref_t 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: virtual void update(void) __OVERRIDE; 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. */ const DateTime operator+(long seconds) const; /** * Subtract seconds from datetime in an expression. Day underflows * update julian date. * @param seconds to subtract from datetime. * @return new modified datetime object. */ const DateTime operator-(long seconds) const; /** * 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. */ stringref_t 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: virtual void update(void) __OVERRIDE; 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: virtual void update(void) __OVERRIDE; 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 __PROTOCOL PrintProtocol, public __PROTOCOL 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) __OVERRIDE; 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 #endif ucommon-7.0.0/inc/ucommon/protocols.h0000644000175000017500000001505112616070251014541 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; 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 __PROTOCOL MemoryProtocol { private: MemoryProtocol *target; public: MemoryRedirect(MemoryProtocol *protocol); virtual void *_alloc(size_t size) __OVERRIDE; }; /** * 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; }; /** * 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(); }; } // namespace ucommon #endif ucommon-7.0.0/inc/ucommon/timers.h0000644000175000017500000002610712606345104014025 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. This also sets * updated false. * @return true if was updated. */ bool update(void); /** * Check if timer active. * @return true if active. */ bool is_active(void) const; public: static const timeout_t inf = ((timeout_t)(-1)); static const time_t reset = ((time_t)(0)); #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 { private: __DELETE_COPY(TimerQueue); 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 DLinkedObject { private: __DELETE_DEFAULTS(event); 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(); } inline timeout_t operator*() 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 #endif ucommon-7.0.0/inc/ucommon/memory.h0000644000175000017500000005716012616070251014034 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 __PROTOCOL MemoryProtocol { private: friend class bufpager; 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); public: /** * Construct a memory pager. * @param page size to use or 0 for OS allocation size. */ memalloc(size_t page = 0); memalloc(const memalloc& copy); /** * 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 size_t size(void) const { return 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) __OVERRIDE; public: /** * Assign foreign pager to us. This relocates the heap references * to our object, clears the other object. */ void assign(memalloc& source); }; /** * 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 __PROTOCOL LockingProtocol { private: mutable pthread_mutex_t mutex; 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) __OVERRIDE; /** * Unlock the memory pager mutex. */ virtual void _unlock(void) __OVERRIDE; public: /** * Construct a memory pager. * @param page size to use or 0 for OS allocation size. */ mempager(size_t page = 0); mempager(const mempager& copy); /** * 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) __OVERRIDE; public: /** * Assign foreign pager to us. This relocates the heap references * to our object, clears the other object. */ void assign(mempager& source); }; 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; __DELETE_COPY(ObjectPager); 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); }; /** * 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; 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() const { return members > 0; } inline bool operator!() const { 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); }; /** * 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: __DELETE_COPY(DirPager); 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) __OVERRIDE; /** * 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); }; /** * 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; __DELETE_COPY(autorelease); 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 { private: __DELETE_COPY(PagerObject); 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); void retain(void) __OVERRIDE; /** * Release a pager object reference. */ void release(void) __OVERRIDE; /** * Return the pager object back to it's originating pool. */ void dealloc(void) __OVERRIDE; }; /** * 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 __PROTOCOL MemoryProtocol { private: LinkedObject *freelist; mutable pthread_mutex_t mutex; __DELETE_COPY(PagerPool); 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); }; /** * 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 { private: __DELETE_COPY(pager); 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 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 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-7.0.0/inc/ucommon/temporary.h0000664000175000017500000002014312611715570014544 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 . /** * Temporary templates for C++. This offers automatic management of * heap temporary objects. * @file ucommon/temporary.h */ #ifndef _UCOMMON_TEMPORARY_H_ #define _UCOMMON_TEMPORARY_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 #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 { /** * 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 { private: __DELETE_COPY(temporary); protected: T *array; size_t used; public: /** * Construct a temporary object, create our stack frame reference. */ inline temporary(size_t size = 1) { array = new T[size]; used = size; } inline temporary(size_t size, const T initial) { array = new T[size]; used = size; for(size_t p = 0; p < size; ++p) array[p] = initial; } inline explicit temporary(const T initial) { array = new T[1]; used = 1; array[0] = initial; } inline ~temporary() { if(array) { delete[] array; array = NULL; } } inline operator T&() const { return array[0]; } /** * Access heap object through our temporary directly. * @return reference to heap resident object. */ inline T& operator*() const { return array[0]; } /** * Access members of our heap object through our temporary. * @return member reference of heap object. */ inline T* operator->() const { return &array[0]; } inline operator bool() const { return array != NULL; } inline bool operator!() const { return array == NULL; } inline temporary& operator=(const T initial) { array[0] = initial; return *this; } inline void release() { if(array) { delete[] array; array = NULL; } } inline T& operator[](size_t index) const { crit(index < used, "array out of bound"); return array[index]; } inline T* operator()(size_t index) const { crit(index < used, "array out of bound"); return &array[index]; } inline void operator()(size_t index, const T value) { crit(index < used, "array out of bound"); array[index] = value; } inline T& value(size_t index) const { crit(index < used, "array out of bound"); return array[index]; } inline void value(size_t index, const T value) { crit(index < used, "array out of bound"); array[index] = value; } inline size_t read(FILE *fp) { return (fp == NULL) || (array == NULL) ? 0 : fread(array, sizeof(T), used, fp); } inline size_t write(FILE *fp) { return (fp == NULL) || (array == NULL) ? 0 : fwrite(array, sizeof(T), used, fp); } inline size_t seek(FILE *fp, long pos) { return (fp == NULL) ? 0 : (fseek(fp, sizeof(T) * pos, SEEK_CUR) / sizeof(T)); } }; template<> class temporary { private: __DELETE_COPY(temporary); protected: char *object; size_t used; public: /** * Construct a temporary object, create our stack frame reference. */ inline temporary(size_t size) { object = (char *)::malloc(size); used = size; } inline operator char *() const { return object; } inline size_t size() const { return used; } /** * Access heap object through our temporary directly. * @return reference to heap resident object. */ inline char *operator*() const { return object; } inline operator bool() const { return object != NULL; } inline bool operator!() const { return object == NULL; } inline void release() { if(object) { ::free(object); object = NULL; } } inline ~temporary() { if(object) { ::free(object); object = NULL; } } inline size_t read(FILE *fp) { return (fp == NULL) || (object == NULL) ? 0 : String::count(fgets(object, (socksize_t)used, fp)); } inline size_t write(FILE *fp) { return (fp == NULL) || (object == NULL) ? 0 : fputs(object, fp); } inline size_t seek(FILE *fp, long pos) { return (fp == NULL) ? 0 : fseek(fp, pos, SEEK_CUR); } }; template<> class temporary { private: inline temporary(const temporary&) {}; protected: uint8_t *object; size_t used; public: /** * Construct a temporary object, create our stack frame reference. */ inline temporary(size_t size) { object = (uint8_t *)::malloc(size); used = size; } inline operator uint8_t *() const { return object; } inline size_t size() const { return used; } /** * Access heap object through our temporary directly. * @return reference to heap resident object. */ inline uint8_t *operator*() const { return object; } inline operator bool() const { return object != NULL; } inline bool operator!() const { return object == NULL; } inline void release() { if(object) { ::free(object); object = NULL; } } inline size_t read(FILE *fp) { return (fp == NULL) || (object == NULL) ? 0 : fread(object, 1, used, fp); } inline size_t write(FILE *fp) { return (fp == NULL) || (object == NULL) ? 0 : fwrite(object, 1, used, fp); } inline size_t seek(FILE *fp, long pos) { return (fp == NULL) ? 0 : fseek(fp, pos, SEEK_CUR); } inline size_t read(fsys& fs) { ssize_t result; if(!object || (result = fs.read(object, used)) < 0) return 0; return (size_t)result; } inline size_t write(fsys& fs) { ssize_t result; if(!object || (result = fs.write(object, used)) < 0) return 0; return (size_t)result; } inline ~temporary() { if(object) { ::free(object); object = NULL; } } }; } // namespace ucommon #endif ucommon-7.0.0/inc/ucommon/reuse.h0000644000175000017500000002370312616070251013643 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 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/reuse.h */ #ifndef _UCOMMON_REUSE_H_ #define _UCOMMON_REUSE_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; __DELETE_DEFAULTS(ArrayReuse); 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 __PROTOCOL MemoryRedirect, protected ReusableAllocator { private: unsigned limit, count; size_t osize; __DELETE_DEFAULTS(PagerReuse); 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); }; /** * 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 { private: __DELETE_DEFAULTS(array_reuse); 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 { private: __DELETE_DEFAULTS(paged_reuse); 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(); } }; } // namespace ucommon #endif ucommon-7.0.0/inc/ucommon/Makefile.in0000644000175000017500000004430412617437745014434 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 reuse.h \ timers.h socket.h access.h export.h thread.h mapped.h \ keydata.h memory.h platform.h fsys.h ucommon.h stream.h \ shell.h protocols.h atomic.h numbers.h condition.h \ datetime.h unicode.h secure.h generics.h stl.h \ typeref.h arrayref.h mapref.h shared.h temporary.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-7.0.0/inc/ucommon/Makefile.am0000664000175000017500000000177612611715570014420 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 reuse.h \ timers.h socket.h access.h export.h thread.h mapped.h \ keydata.h memory.h platform.h fsys.h ucommon.h stream.h \ shell.h protocols.h atomic.h numbers.h condition.h \ datetime.h unicode.h secure.h generics.h stl.h \ typeref.h arrayref.h mapref.h shared.h temporary.h ucommon-7.0.0/inc/ucommon/arrayref.h0000644000175000017500000001563012606345104014334 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 . /** * Arrays of thread-safe strongly typed heap objects. This is used for * arrays of smart pointers to immutable heap instances of object types * that are reference counted and automatically deleted when no longer used. * @file ucommon/arrayref.h */ #ifndef _UCOMMON_ARRAYREF_H_ #define _UCOMMON_ARRAYREF_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 #ifndef _UCOMMON_TYPEREF_H_ #include #endif #ifndef _UCOMMON_THREAD_H_ #include #endif namespace ucommon { class __EXPORT ArrayRef : public TypeRef { protected: typedef enum {ARRAY, STACK, QUEUE, FALLBACK} arraytype_t; class __EXPORT Array : public Counted, public ConditionalAccess { private: __DELETE_DEFAULTS(Array); protected: friend class ArrayRef; size_t head, tail; arraytype_t type; explicit Array(arraytype_t mode, void *addr, size_t size); void assign(size_t index, Counted *object); Counted *remove(size_t index); size_t count(void); virtual void dealloc() __OVERRIDE; inline Counted **get(void) { return reinterpret_cast(((caddr_t)(this)) + sizeof(Array)); } Counted *get(size_t index); }; ArrayRef(arraytype_t mode, size_t size); ArrayRef(arraytype_t mode, size_t size, TypeRef& object); ArrayRef(const ArrayRef& copy); ArrayRef(); void assign(size_t index, TypeRef& t); void reset(TypeRef& object); void reset(Counted *object); Counted *get(size_t index); bool is(size_t index); static Array *create(arraytype_t type, size_t size); protected: void push(const TypeRef& object); void pull(TypeRef& object); bool push(const TypeRef& object, timeout_t timeout); void pull(TypeRef& object, timeout_t timeout); public: size_t count(void); void resize(size_t size); void realloc(size_t size); void clear(void); void pop(void); }; template class stackref : public ArrayRef { public: inline stackref() : ArrayRef() {}; inline stackref(const stackref& copy) : ArrayRef(copy) {}; inline stackref(size_t size) : ArrayRef(STACK, size + 1) {}; inline stackref& operator=(const stackref& copy) { TypeRef::set(copy); return *this; } inline typeref operator[](size_t index) { return typeref(ArrayRef::get(index)); } inline typeref operator()(size_t index) { return typeref(ArrayRef::get(index)); } inline typeref at(size_t index) { return typeref(ArrayRef::get(index)); } inline void release(void) { TypeRef::set(nullptr); } inline typeref pull() { typeref obj; ArrayRef::pull(obj); return obj; } inline typeref pull(timeout_t timeout) { typeref obj; ArrayRef::pull(obj, timeout); return obj; } inline stackref& operator>>(typeref& target) { ArrayRef::pull(target); return *this; } inline void push(const typeref& source) { ArrayRef::push(source); } inline bool push(const typeref& source, timeout_t timeout) { return ArrayRef::push(source, timeout); } inline stackref& operator<<(const typeref& source) { ArrayRef::push(source); return *this; } inline stackref& operator<<(T t) { typeref v(t); ArrayRef::push(v); return *this; } }; template class queueref : public ArrayRef { public: inline queueref() : ArrayRef() {}; inline queueref(const queueref& copy) : ArrayRef(copy) {}; inline queueref(size_t size, bool fallback = false) : ArrayRef(fallback ? FALLBACK : QUEUE, size + 1) {}; inline queueref& operator=(const queueref& copy) { TypeRef::set(copy); return *this; } inline typeref operator[](size_t index) { return typeref(ArrayRef::get(index)); } inline typeref operator()(size_t index) { return typeref(ArrayRef::get(index)); } inline typeref at(size_t index) { return typeref(ArrayRef::get(index)); } inline void release(void) { TypeRef::set(nullptr); } inline typeref pull() { typeref obj; ArrayRef::pull(obj); return obj; } inline typeref pull(timeout_t timeout) { typeref obj; ArrayRef::pull(obj, timeout); return obj; } inline queueref& operator>>(typeref& target) { ArrayRef::pull(target); return *this; } inline void push(const typeref& source) { ArrayRef::push(source); } inline bool push(const typeref& source, timeout_t timeout) { return ArrayRef::push(source, timeout); } inline queueref& operator<<(const typeref& source) { ArrayRef::push(source); return *this; } inline queueref& operator<<(T t) { typeref v(t); ArrayRef::push(v); return *this; } }; template class arrayref : public ArrayRef { public: inline arrayref() : ArrayRef() {}; inline arrayref(const arrayref& copy) : ArrayRef(copy) {}; inline arrayref(size_t size) : ArrayRef(ARRAY, size) {}; inline arrayref(size_t size, typeref& t) : ArrayRef(ARRAY, size, t) {}; inline arrayref(size_t size, T t) : ArrayRef(ARRAY, size) { typeref v(t); reset(v); } inline arrayref& operator=(const arrayref& copy) { TypeRef::set(copy); return *this; } inline arrayref& operator=(typeref& t) { reset(t); return *this; } inline arrayref& operator=(T t) { typeref v(t); reset(v); } inline typeref operator[](size_t index) { return typeref(ArrayRef::get(index)); } inline typeref operator()(size_t index) { return typeref(ArrayRef::get(index)); } inline typeref at(size_t index) { return typeref(ArrayRef::get(index)); } inline typeref value(size_t index) { return typeref(ArrayRef::get(index)); } inline void value(size_t index, typeref& t) { ArrayRef::assign(index, t); } inline void put(typeref& target, size_t index) { TypeRef::put(target, ArrayRef::get(index)); } inline void operator()(size_t index, typeref& t) { ArrayRef::assign(index, t); } inline void operator()(size_t index, T t) { typeref v(t); ArrayRef::assign(index, v); } inline void release(void) { TypeRef::set(nullptr); } }; typedef arrayref bytearray_t; typedef arrayref stringarray_t; } // namespace #endif ucommon-7.0.0/inc/ucommon/shell.h0000664000175000017500000006365312611715570013646 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_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; __DELETE_COPY(shell); 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 { private: __DELETE_COPY(Option); 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); __DELETE_DEFAULTS(flagopt); 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; } inline flagopt& operator=(unsigned value) { counter = value; return *this; } }; /** * 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); __DELETE_DEFAULTS(groupopt); 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; __DELETE_DEFAULTS(stringopt); 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 stringopt& operator=(const char *string) { text = string; return *this; } 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; __DELETE_DEFAULTS(charopt); 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 charopt& operator=(char value) { code = value; return *this; } 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; __DELETE_DEFAULTS(numericopt); 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 numericopt& operator=(long value) { number = value; return *this; } 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; __DELETE_DEFAULTS(counteropt); 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 counteropt& operator=(long value) { number = value; return *this; } 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 *getenv(const char *name, const char *value = NULL); /** * 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 *getsym(const char *name, const char *value = NULL); /** * Set a local symbol. * @param name of symbol to set. * @param value of symbol to set. */ void setsym(const char *name, const char *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 errlog(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); static size_t printf(const char *format, ...) __PRINTF(1, 2); /** * 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 __TEXT #undef _STR #undef __STR #define _STR(x) ((const char *)(x)) #define __STR(x) (static_cast(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);} inline const char *_TEXT(const char *s) {return shell::text(s);} } // namespace ucommon #endif ucommon-7.0.0/inc/ucommon/socket.h0000644000175000017500000021442112617437737014030 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 #ifndef _UCOMMON_TYPEREF_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 typedef struct sockaddr *sockaddr_t; typedef struct sockaddr sockaddr_struct; // older gcc needs...? /** * An object that holds ipv4 or ipv6 binary encoded host addresses. */ struct hostaddr_internet { union { struct in_addr ipv4; #ifdef AF_INET6 struct in6_addr ipv6; #endif }; }; #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. */ struct sockaddr_internet { union { #ifdef AF_INET6 struct sockaddr_in6 ipv6; #endif struct sockaddr_in ipv4; struct sockaddr address; }; }; #else struct sockaddr_internet { union { struct sockaddr_in ipv4; struct sockaddr address; }; }; 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; struct hostaddr_internet Netmask, Network; char Name[16]; unsigned mask(const char *cp) const; struct hostaddr_internet 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 struct hostaddr_internet getNetwork(void) const { return Network; } /** * Get the effective network mask for our cidr block. * @return binary network mask for our cidr. */ inline struct hostaddr_internet getNetmask(void) const { return Netmask; } /** * Get the broadcast host address represented by our cidr. * @return binary broadcast host address. */ inline struct hostaddr_internet 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: // temporary splints... typedef struct hostaddr_internet host_t; typedef cidr cidr_t; /** * 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. */ const struct sockaddr *get(void) const; struct sockaddr *modify(void); inline const struct sockaddr *getAddr(void) const { return get(); } inline const 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 *() { return modify(); } /** * 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. */ const struct sockaddr *get(int family) const; struct sockaddr *modify(int family); inline const struct sockaddr *operator()(int family) const { return get(family); } inline operator struct sockaddr_in *() { return (struct sockaddr_in *)modify(AF_INET); } #ifdef AF_INET6 inline operator struct sockaddr_in6 *() { return (struct sockaddr_in6 *)modify(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 != nullptr; } inline bool is_valid() const { return list != nullptr; } inline bool isValid() const { return list != nullptr; } /** * Test if we have no address list. * @return true if we have no address list. */ inline bool operator!() const { return list == nullptr; } /** * 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 is_any() const { return isAny(get()); } 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 is_loopback() const { return isLoopback(get()); } 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); /** * 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. */ inline static in_port_t getPort(const struct sockaddr *address) { return Socket::port(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) const { 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(uint8_t 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(const 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) const { 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); stringref_t readline(size_t maxsize); /** * 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() const; /** * 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(const 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, uint8_t 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); } /** * 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. */ static unsigned store(struct sockaddr_storage *storage, const struct sockaddr *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 target address. * @param size of interface, 0 used for older code * @return 0 on success, -1 on error. */ static int via(struct sockaddr *address, const struct sockaddr *target, socklen_t size = 0); /** * 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 in_port_t port(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 in_port_t port(const struct sockaddr_internet *address) { return port((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); /** * 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 { private: __DELETE_COPY(ListenSocket); 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 { private: __DELETE_DEFAULTS(TCPServer); 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 class for linked_pointer template. * @author David Sugar */ class __EXPORT linked_sockaddr_operations { protected: inline linked_sockaddr_operations() {} /** * Helper function for linked_pointer. */ const struct addrinfo *_nextaddrinfo(const struct addrinfo *addrinfo) const; /** * Helper function for linked_pointer. */ const struct sockaddr *_getaddrinfo(const struct addrinfo *addrinfo) const; /** * Helper function for linked_pointer. */ socket_t _getaddrsock(const struct addrinfo *addrinfo) const; }; /** * 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 linked_sockaddr_operations { private: const struct addrinfo *ptr; public: inline linked_pointer(const struct addrinfo *list) { ptr = list; } inline linked_pointer(const linked_pointer& copy) { ptr = copy.ptr; } inline linked_pointer() { ptr = nullptr; } 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 const 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 const struct sockaddr *operator*() const { return _getaddrinfo(ptr); } inline operator const struct sockaddr_in *() const { return (struct sockaddr_in *)_getaddrinfo(ptr); } inline const struct sockaddr_in *in(void) const { return (struct sockaddr_in *)_getaddrinfo(ptr); } #ifdef AF_INET6 inline operator const struct sockaddr_in6 *() const { return (struct sockaddr_in6 *)_getaddrinfo(ptr); } inline const 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 != nullptr; } /** * Assign our pointer from an address list. * @param pointer of linked list. */ inline linked_pointer& operator=(const struct addrinfo *list) { ptr = list; return *this; } /** * Assign our pointer from an address list. * @param pointer of linked list. */ inline linked_pointer& operator=(Socket::address& list) { ptr = list.getList(); return *this; } /** * Assign our pointer from an address list. * @param pointer of linked list. */ inline void set(const 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 const 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 == nullptr; } 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 const 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, size_t size); namespace Type { class HostAddress { private: struct hostaddr_internet storage; public: inline HostAddress() { memset(&storage, 0, sizeof(storage)); } inline HostAddress(const HostAddress& copy) { memcpy(&storage, ©.storage, sizeof(storage)); } inline HostAddress(const struct hostaddr_internet *addr) { memcpy(&storage, addr, sizeof(struct hostaddr_internet)); } inline HostAddress(const in_addr *addr) { memset(&storage, 0, sizeof(storage)); memcpy(&storage, addr, sizeof(struct in_addr)); } #ifdef AF_INET6 inline HostAddress(const in6_addr *addr) { memset(&storage, 0, sizeof(storage)); memcpy(&storage, addr, sizeof(struct in6_addr)); } #endif inline operator const struct hostaddr_internet *() const { return &storage; } inline struct hostaddr_internet *operator*() { return &storage; } inline socklen_t size() { return sizeof(storage); } inline HostAddress& operator=(const HostAddress& copy) { memcpy(&storage, ©.storage, sizeof(storage)); return *this; } inline HostAddress& operator=(const struct hostaddr_internet *host) { memcpy(&storage, host, sizeof(struct hostaddr_internet)); return *this; } inline bool operator==(const HostAddress& check) const { return (memcmp(&check.storage, &storage, sizeof(storage)) == 0); } inline bool operator!=(const HostAddress& check) const { return (memcmp(&check.storage, &storage, sizeof(storage)) != 0); } inline bool operator==(const struct hostaddr_internet *host) const { return (memcmp(host, &storage, sizeof(storage)) == 0); } inline bool operator!=(const struct hostaddr_internet *host) const { return (memcmp(host, &storage, sizeof(storage)) != 0); } }; class SockAddress { private: struct sockaddr_storage storage; public: inline SockAddress() { memset(&storage, 0, sizeof(storage)); } inline SockAddress(const SockAddress& copy) { memcpy(&storage, ©.storage, sizeof(storage)); } inline SockAddress(const struct sockaddr *addr) { Socket::store(&storage, addr); } inline SockAddress& operator=(const SockAddress& copy) { memcpy(&storage, ©.storage, sizeof(storage)); return *this; } inline SockAddress& operator=(const struct sockaddr *addr) { Socket::store(&storage, addr); return *this; } inline operator const struct sockaddr *() const { return (const struct sockaddr*)&storage; } inline struct sockaddr *operator*() { return (struct sockaddr *)&storage; } inline const struct sockaddr *get() const { return (const struct sockaddr *)&storage; } inline socklen_t size() { return sizeof(storage); } inline bool operator==(const SockAddress& check) const { return Socket::equal(get(), check.get()); } inline bool operator!=(const SockAddress& check) const { return !Socket::equal(get(), check.get()); } inline bool operator==(const struct sockaddr *check) const { return Socket::equal(get(), check); } inline bool operator!=(const struct sockaddr *check) const { return !Socket::equal(get(), check); } }; class InetAddress { private: struct sockaddr_internet storage; public: inline InetAddress() { memset(&storage, 0, sizeof(storage)); } inline InetAddress(const InetAddress& copy) { memcpy(&storage, ©.storage, sizeof(storage)); } inline InetAddress(const struct sockaddr *addr) { Socket::store(&storage, addr); } inline InetAddress& operator=(const InetAddress& copy) { memcpy(&storage, ©.storage, sizeof(storage)); return *this; } inline InetAddress& operator=(const struct sockaddr *addr) { Socket::store(&storage, addr); return *this; } inline operator const struct sockaddr *() const { return (const struct sockaddr*)&storage; } inline struct sockaddr *operator*() { return (struct sockaddr *)&storage; } inline const struct sockaddr *get() const { return (const struct sockaddr *)&storage; } inline socklen_t size() { return sizeof(storage); } inline bool operator==(const SockAddress& check) const { return Socket::equal(get(), check.get()); } inline bool operator!=(const SockAddress& check) const { return !Socket::equal(get(), check.get()); } inline bool operator==(const struct sockaddr *check) const { return Socket::equal(get(), check); } inline bool operator!=(const struct sockaddr *check) const { return !Socket::equal(get(), check); } }; } typedef TCPServer tcpserv_t; } // namespace ucommon #endif ucommon-7.0.0/inc/ucommon/numbers.h0000644000175000017500000001404312606345104014171 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-7.0.0/inc/ucommon/keydata.h0000644000175000017500000001656212606345104014150 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; const char *name; keyfile *root; keydata(keyfile *file); keydata(keyfile *file, const char *id); __DELETE_COPY(keydata); 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); __DELETE_COPY(keyvalue); 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 pointer; }; /** * 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 pointer; 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-7.0.0/inc/ucommon/generics.h0000644000175000017500000002463012617437737014340 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; } }; /** * Save and restore global objects in function call stack frames. * @author David Sugar */ template class save_restore { private: T *original; T temp; save_restore() __DELETED; 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*() == nullptr); } /** * 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*() == nullptr); } /** * 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. Can be specialized. * @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 copy objects. */ template inline T copy(const T& src) { return T(src); } template inline T& copy(const T& src, T& to) { new((caddr_t)&to) T(src); return to; } /** * Convenience function to move objects. */ template inline T& move(T& src, T& to) { memcpy((void *)&to, (void *)&src, sizeof(T)); new((caddr_t)&src) T(); return to; } template inline T& clear(T& o) { o.~T(); new((caddr_t)&o) T(); return o; } /** * 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) { __THROW_DEREF(pointer); return *pointer; } } // namespace ucommon #endif ucommon-7.0.0/inc/Makefile.in0000644000175000017500000004743312617437745012765 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-7.0.0/inc/Makefile.am0000664000175000017500000000123112570431074012723 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-7.0.0/inc/commoncpp/0000755000175000017500000000000012633254127012745 500000000000000ucommon-7.0.0/inc/commoncpp/exception.h0000664000175000017500000001035512570431074015040 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-7.0.0/inc/commoncpp/persist.h0000644000175000017500000004224612606345104014533 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 #ifndef COMMONCPP_PERSIST_H_ #define COMMONCPP_PERSIST_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif #include #include #include #include #include namespace ost { // 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 { private: __DELETE_DEFAULTS(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: __DELETE_COPY(registration); 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 { private: __DELETE_COPY(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 ucommon-7.0.0/inc/commoncpp/thread.h0000644000175000017500000006417512616070251014315 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 { private: __DELETE_COPY(Mutex); 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 { private: __DELETE_COPY(MutexCounter); 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; __DELETE_COPY(MutexLock); 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::RWLock { private: __DELETE_COPY(ThreadLock); public: inline ThreadLock() : ucommon::RWLock() {} inline void readLock(void) { ucommon::RWLock::access(); } inline void writeLock(void) { ucommon::RWLock::modify(); } inline void tryReadLock(void) { ucommon::RWLock::access(0); } inline void tryWriteLock(void) { ucommon::RWLock::modify(0); } inline void unlock(void) { ucommon::RWLock::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; __DELETE_COPY(ReadLock); 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; __DELETE_COPY(WriteLock); 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 { private: __DELETE_COPY(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 : protected 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 { private: __DELETE_COPY(Event); 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]; __DELETE_COPY(Thread); 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) __OVERRIDE = 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) const { 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 { private: __DELETE_DEFAULTS(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 { private: #ifndef _MSWINDOWS_ struct timeval timer; #else DWORD timer; #endif bool active; __DELETE_COPY(TimerPort); 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) const { 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) const { 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) __OVERRIDE; /** * 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) __OVERRIDE; /** * 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) __OVERRIDE; 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) __OVERRIDE; }; /** * 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) __FINAL; // private run method __DELETE_COPY(ThreadQueue); 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() __OVERRIDE; /** * 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-7.0.0/inc/commoncpp/object.h0000644000175000017500000003741512606345104014312 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 { private: __DELETE_COPY(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; operator bool() 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 { private: __DELETE_COPY(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 { private: __DELETE_COPY(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 { private: __DELETE_COPY(MapTable); 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 { private: __DELETE_COPY(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-7.0.0/inc/commoncpp/commoncpp.h0000644000175000017500000000516712606345104015036 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 #include #ifndef UCOMMON_SYSRUNTIME #include #include #endif #endif ucommon-7.0.0/inc/commoncpp/serial.h0000644000175000017500000006065012606345104014320 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, uint8_t 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) const { 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) const { 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) const { 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&); __DELETE_COPY(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) __OVERRIDE; /** * 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) __OVERRIDE; /** * 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) __OVERRIDE; 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) __OVERRIDE; }; /** * 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 { private: __DELETE_COPY(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 { private: __DELETE_COPY(TTYSession); 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; __DELETE_COPY(SerialPort); 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; __DELETE_COPY(SerialService); /** * 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) __OVERRIDE; 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(uint8_t 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(uint8_t 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) const { return count; } }; #endif #ifdef CCXX_EXCEPTIONS class __EXPORT SerException : public IOException { public: SerException(const String &str) : IOException(str) {} }; #endif } // namespace ost #endif ucommon-7.0.0/inc/commoncpp/slog.h0000644000175000017500000002140512606345104014000 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; __DELETE_COPY(Slog); 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) __OVERRIDE; 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-7.0.0/inc/commoncpp/tcp.h0000644000175000017500000005120012606345104013616 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); __DELETE_COPY(TCPSocket); 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) const { return so; } /** * Get the buffer size for servers. */ inline int getSegmentSize(void) const { 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) { 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); __DELETE_COPY(TCPV6Socket); 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) { 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() __OVERRIDE; /** * 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() __OVERRIDE; /** * 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) __OVERRIDE; /** * 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) __OVERRIDE; /** * 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) __OVERRIDE; 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-7.0.0/inc/commoncpp/string.h0000644000175000017500000000645412606345104014351 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-7.0.0/inc/commoncpp/udp.h0000644000175000017500000004561712606345104013637 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);} __DELETE_COPY(UDPSocket); 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);} __DELETE_COPY(UDPBroadcast); 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); __DELETE_COPY(UDPTransmit); 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(uint8_t 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 { private: __DELETE_COPY(UDPReceive); 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 { private: __DELETE_COPY(UDPDuplex); 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-7.0.0/inc/commoncpp/misc.h0000644000175000017500000001071612616070251013771 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 : protected ucommon::memalloc { private: __DELETE_COPY(MemPager); 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) const { 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 { private: __DELETE_COPY(SharedMemPager); 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]; __DELETE_COPY(Assoc); 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-7.0.0/inc/commoncpp/export.h0000664000175000017500000000552312570431074014364 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-7.0.0/inc/commoncpp/pointer.h0000644000175000017500000000756612606345104014530 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 operator bool() const { return (*ptrCount != 1); } 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-7.0.0/inc/commoncpp/dccp.h0000644000175000017500000001663112606466730013763 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 { private: 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() const; /** * Get RX CCID DCCP. */ int getRxCCID() const; /** * Return number of bytes to be read */ size_t available() const; /** * 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) { return Socket::isPending(Socket::pendingInput, timeout); } /** * Use base socket handler for ending this socket. */ virtual ~DCCPSocket(); }; } // namespace ost #endif ucommon-7.0.0/inc/commoncpp/address.h0000644000175000017500000010001612606345104014455 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 in_port_t 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 { private: __DELETE_COPY(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 { private: __DELETE_COPY(IPV4MulticastValidator); 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 __OVERRIDE; }; /** * 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); } 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); } 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=(in_addr_t addr); inline operator bool() const { return isInetAddress(); } 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 { private: __DELETE_COPY(IPV4Mask); 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=(in_addr_t 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=(in_addr_t 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 { private: __DELETE_COPY(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 { private: __DELETE_COPY(IPV6MulticastValidator); 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 __OVERRIDE; }; /** * 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 operator bool () const { return isInetAddress(); } 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 { private: __DELETE_COPY(IPV6Mask); 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-7.0.0/inc/commoncpp/mime.h0000644000175000017500000001426712606345104013773 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 { private: __DELETE_COPY(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 { private: __DELETE_COPY(MIMEMultipartForm); 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 { private: __DELETE_COPY(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 { private: __DELETE_COPY(MIMEFormData); 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) __OVERRIDE; /** * Stream content (value) of this form data field. * * @param output stream to send body to. */ void body(std::ostream *output) __OVERRIDE; /** * 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-7.0.0/inc/commoncpp/Makefile.in0000644000175000017500000004414312617437745014753 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 persist.h \ xml.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-7.0.0/inc/commoncpp/Makefile.am0000644000175000017500000000162712606345104014723 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 persist.h \ xml.h commoncpp.h ucommon-7.0.0/inc/commoncpp/applog.h0000644000175000017500000003575312606345104014331 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 uint8_t *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-7.0.0/inc/commoncpp/file.h0000644000175000017500000005703612606345104013764 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 __DELETE_COPY(Dir); 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!() const { #ifndef _MSWINDOWS_ return !dir; #else return hDir == INVALID_HANDLE_VALUE; #endif } operator bool() const { #ifndef _MSWINDOWS_ return dir; #else return hDir != INVALID_HANDLE_VALUE; #endif } bool isValid(void) const; }; /** * 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; __DELETE_COPY(DirTree); 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) const { return errid; } /** * Return current error string. * * @return last error string set. */ inline char *getErrorString(void) const { return errstr; } operator bool() const; bool operator!(void) const; }; /** * 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 __DELETE_COPY(MappedFile); 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; __DELETE_COPY(DSO); 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) const { 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-7.0.0/inc/commoncpp/socket.h0000644000175000017500000004550212606345104014330 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) const; /** * 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(uint8_t 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(in_port_t *port = NULL) const; inline IPV4Host getSender(in_port_t *port) const { return getIPV4Sender(port); } #ifdef CCXX_IPV6 virtual IPV6Host getIPV6Sender(in_port_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(in_port_t *port = NULL) const; inline IPV4Host getPeer(in_port_t *port) const { return getIPV4Peer(port); } #ifdef CCXX_IPV6 IPV6Host getIPV6Peer(in_port_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(in_port_t *port = NULL) const; inline IPV4Host getLocal(in_port_t *port) const { return getIPV4Local(port); } #ifdef CCXX_IPV6 IPV6Host getIPV6Local(in_port_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) const { return ia.getAddress(); } #ifdef CCXX_IPV6 inline struct in6_addr getaddress(const IPV6Address &ia) const { 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-7.0.0/inc/commoncpp/tokenizer.h0000664000175000017500000002616012570431074015055 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-7.0.0/inc/commoncpp/process.h0000644000175000017500000002054512606345104014516 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; __DELETE_DEFAULTS(Process); 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 __DELETE_COPY(Lockfile); 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-7.0.0/inc/commoncpp/numbers.h0000644000175000017500000001361112606345104014507 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(const Time& object) : ucommon::Time(object) {} 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-7.0.0/inc/commoncpp/config.h0000644000175000017500000000524512606345104014305 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; #endif ucommon-7.0.0/inc/commoncpp/xml.h0000644000175000017500000001106212616070251013631 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 COMMONCPP_XML_H_ #define COMMONCPP_XML_H_ #ifndef COMMONCPP_CONFIG_H_ #include #endif namespace ost { /** * 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); __DELETE_COPY(XMLParser); 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(const 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(const 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(const caddr_t name, caddr_t *attr) = 0; /** * Notify end of an element in the document. * @param name of element ending. */ virtual void endElement(const 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(const char *cp); /** * 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-7.0.0/biicode.conf0000664000175000017500000000247712570431073012377 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-7.0.0/corelib/0000755000175000017500000000000012633254126011617 500000000000000ucommon-7.0.0/corelib/unicode.cpp0000644000175000017500000003337712616070251013702 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(const char *cp) { uint8_t ch = (uint8_t)(*(cp++)); unsigned count = 0; ucs4_t code; if(!ch) 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 = (uint8_t)*(cp++); if(!ch) 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, const char *str, size_t len) { size_t used = 0; wchar_t *target = (wchar_t *)buffer; while(--len) { ucs4_t code = utf8::get(str); if(!code || code == (ucs4_t)EOF) break; str += chars(code); *(target++) = (wchar_t)code; ++used; } *target = (wchar_t)0; return used; } void utf8::put(ucs4_t code, char *buffer) { if(code == EOF) return; if(code < 0x80) { *buffer = code; return; } unsigned used = 0; if(code < 0x000007ff) { buffer[used++] = (code >> 6) | 0xc0; buffer[used++] = (code & 0x3f) | 0x80; return; } if(code <= 0x0000ffff) { buffer[used++] = (code >> 12) | 0xe0; buffer[used++] = (code >> 6 & 0x3f) | 0x80; buffer[used++] = (code & 0x3f) | 0x80; return; } 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; return; } 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; return; } 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; } ucs4_t *utf8::udup(const char *string) { if(!string) return NULL; size_t len = count(string); size_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; size_t len = count(string); size_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, char *buf, size_t bufsize) { unsigned points = 0; ucs4_t code; const wchar_t *string = (const wchar_t *)str; while(0 != (code = (*(string++)))) { size_t ps = chars(code); if(ps > (bufsize - 1)) break; put(code, buf); buf += ps; } *buf = 0; 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(size_t size) { str = create(size); str->retain(); } UString::UString(const char *text, size_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) { size_t size = utf8::chars(text); str = NULL; str = create(size); str->retain(); utf8::unpack(text, str->text, str->max); str->fix(); } void UString::add(const unicode_t text) { size_t alloc, size; size = alloc = utf8::chars(text); if(str) alloc += str->len; if(!resize(alloc)) return; utf8::unpack(text, str->text + str->len, size); str->fix(); } size_t UString::get(unicode_t output, size_t points) const { const char *buf = ""; if(str) buf = str->text; return utf8::pack(output, buf, points); } void UString::cut(size_t pos, size_t size) { if(!str) return; size_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(size_t pos, const char *text, size_t size) { size_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(size_t pos, size_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, (ssize_t)size); if(!end) return UString(substr); pos = (size_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, size_t pos) const { if(!str) return NULL; return utf8::find(str->text, code, pos); } const char *UString::rfind(ucs4_t code, size_t pos) const { if(!str) return NULL; return utf8::rfind(str->text, code, pos); } unsigned UString::ccount(ucs4_t code) const { if(!str) return 0; return utf8::ccount(str->text, code); } UString UString::operator()(int codepoint, size_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-7.0.0/corelib/reuse.cpp0000644000175000017500000001057612606345104013374 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 { 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); if(!mem) __THROW_ALLOC(); } ArrayReuse::~ArrayReuse() { if(mem) { free(mem); mem = NULL; } } bool ArrayReuse::avail(void) const { bool rtn = false; __AUTOLOCK(this); 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(this); 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(this); if(freelist) { obj = freelist; freelist = next(obj); } else if(used < limit) { obj = (ReusableObject *)(mem + (used * objsize)); ++used; } if(obj) ++count; return obj; } 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(this); if(!limit) return true; if(count < limit) rtn = true; return rtn; } ReusableObject *PagerReuse::request(void) { ReusableObject *obj = NULL; __AUTOLOCK(this); 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(this); 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-7.0.0/corelib/timer.cpp0000644000175000017500000002102312606345104013356 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 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 TimerQueue::event::event(timeout_t timeout) : Timer(), DLinkedObject() { set(timeout); } TimerQueue::event::event(TimerQueue *tq, timeout_t timeout) : Timer(), DLinkedObject() { 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-7.0.0/corelib/numbers.cpp0000664000175000017500000000645112570431074013725 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-7.0.0/corelib/datetime.cpp0000644000175000017500000004525312633253131014043 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); } stringref_t Date::operator()() const { char buf[11]; put(buf); return stringref_t(buf); } 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; } const Date Date::operator+(long val) const { Date result = *this; result += val; return result; } const Date Date::operator-(long val) const { 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); } stringref_t Time::operator()() const { char buf[9]; put(buf); return stringref_t(buf); } 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; } const Time Time::operator+(long val) const { Time result = *this; result += val; return result; } const Time Time::operator-(long val) const { 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()); } stringref_t DateTime::format(const char *text) const { char buffer[64]; size_t last; time_t t; tm_t *tbp; t = get(); tbp = local(&t); last = ::strftime(buffer, 64, text, tbp); release(tbp); buffer[last] = '\0'; return stringref_t(buffer); } long DateTime::operator-(const DateTime &dt) { long secs = (julian - dt.julian) * c_day; secs += (seconds - dt.seconds); return secs; } const DateTime DateTime::operator+(long value) const { DateTime result = *this; result += value; return result; } const DateTime DateTime::operator-(long value) const { 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; } } // namespace ucommon ucommon-7.0.0/corelib/counter.cpp0000664000175000017500000000361512570431074013730 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-7.0.0/corelib/string.cpp0000644000175000017500000011717212622076126013562 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 { String::cstring::cstring(size_t size) : CountedObject() { max = size; len = 0; text[0] = 0; } void String::cstring::fix(void) { text[len] = 0; } void String::cstring::clear(size_t offset) { if(offset >= len) return; text[offset] = 0; len = offset; } void String::cstring::dec(size_t offset) { if(!len) return; if(offset >= len) { text[0] = 0; len = 0; fix(); return; } text[--len] = 0; } void String::cstring::inc(size_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) { size_t size = strlen(str); if(!size) return; 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; if(len == max) return; text[len++] = ch; fix(); } void String::cstring::set(size_t offset, const char *str, size_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; } if(offset > len) { len = offset; text[len] = 0; } } size_t String::size(void) const { if(!str) return 0; return str->max; } size_t String::len(void) const { if(!str) return 0; return str->len; } void String::cstring::set(const char *str) { assert(str != NULL); size_t size = 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) { size_t size = 0; if(!s) s = ""; else if(!end) size = strlen(s); else if(end > s) size = (size_t)(end - s); str = create(size); str->retain(); str->set(s); } String::String(const char *s) { size_t size = count(s); if(!s) s = ""; str = create(size); str->retain(); str->set(s); } String::String(const char *s, size_t size) { if(!s) s = ""; if(!size) size = strlen(s); str = create(size); str->retain(); str->set(s); } String::String(size_t size) { str = create(size); str->retain(); } String::String(size_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(size_t offset, size_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(size_t size) const { void *mem = ::malloc(size + sizeof(cstring)); 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::data(void) { 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, size_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, size_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, size_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) { size_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; size_t cpl = 0; if(cp) cpl = strlen(cp); if(!str || !substring || str->len == 0) return 0; size_t offset = 0; size_t tcl = 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 = (size_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, size_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; 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(); } } size_t String::offset(const char *s) const { if(!str || !s) return npos; if(s < str->text || s > str->text + str->max) return npos; if((size_t)(s - str->text) > str->len) return str->len; return (size_t)(s - str->text); } size_t String::count(void) const { if(!str) return 0; return str->len; } size_t String::ccount(const char *clist) const { if(!str) return 0; return ccount(str->text, clist); } size_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 = strlen(str->text); str->fix(); } va_end(args); return len(); } size_t String::vprintf(const char *format, va_list args) { assert(format != NULL); if(str) { vsnprintf(str->text, str->max + 1, format, args); str->len = 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(size_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(size_t pos) { if(!str || pos >= str->len) return; str->text[pos] = 0; str->fix(); } void String::fill(size_t size, char fill) { if(!str) { str = create(size); str->retain(); } while(str->len < str->max && size--) str->text[str->len++] = fill; str->fix(); } void String::set(size_t offset, const char *s, size_t size) { if(!s || !*s || !str) return; if(!size) size = strlen(s); if(str) str->set(offset, s, size); } void String::set(const char *s, char overflow, size_t offset, size_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, size_t offset, size_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) s += len - size; set(offset, s, size); if(overflow && len > size) str->text[offset] = overflow; } void String::set(const char *s) { size_t len; if(!s) s = ""; if(!str) { len = strlen(s); str = create(len); str->retain(); } str->set(s); } void String::paste(size_t offset, const char *cp, size_t size) { if(!cp) return; if(!size) size = 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(size_t offset, size_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(size_t size) { if(!size) { release(); str = NULL; return true; } if(!str) { str = create(size); str->retain(); } else if(str->is_copied() || str->max < size) { str->release(); str = create(size); str->retain(); } return true; } void String::clear(size_t offset) { if(!str) return; str->clear(offset); } void String::clear(void) { if(str) str->set(""); } void String::cow(size_t size) { if(str) 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(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((size_t)(-offset) >= str->len) return str->text[0]; return str->text[(int)(str->len) + offset]; } String String::operator()(int offset, size_t len) const { const char *cp = operator()(offset); if(!cp) cp = ""; if(!len) len = 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((size_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((size_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+=(size_t offset) { if(str) str->inc(offset); return *this; } String &String::operator-=(size_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) return true; return false; } bool String::operator!() const { bool rtn = false; if(!str) return true; if(!str->len) rtn = true; str->fix(); return rtn; } String::operator bool() const { bool rtn = false; if(!str) return false; 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; } const String String::operator+(const char *s) const { 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, size_t size) { assert(mem != NULL); assert(size > 0); str = new(mem) cstring(size); str->set(""); } memstring::~memstring() { str = NULL; } memstring *memstring::create(size_t size) { assert(size > 0); void *mem = ::malloc(size + sizeof(memstring) + sizeof(cstring)); return new(mem) memstring((caddr_t)mem + sizeof(memstring), size); } memstring *memstring::create(MemoryProtocol *mpager, size_t size) { assert(size > 0); void *mem = mpager->alloc(size + sizeof(memstring) + sizeof(cstring)); return new(mem) memstring((caddr_t)mem + sizeof(memstring), size); } void memstring::release(void) { str = NULL; } bool memstring::resize(size_t size) { return false; } void memstring::cow(size_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); tmp->set(str->text); return tmp; } void String::fix(String &s) { if(s.str) { s.str->len = 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); if(!mem) __THROW_ALLOC(); 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); if(!mem) __THROW_ALLOC(); 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 } 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; } static int hexcode(char ch) { ch = toupper(ch); if(ch >= '0' && ch <= '9') return ch - '0'; else if(ch >= 'A' && ch <= 'F') return ch - 'A' + 10; return -1; // error flag } size_t String::hexcount(const char *str, bool ws) { size_t count = 0; while(str && *str) { if(ws && isspace(*str)) { ++str; continue; } if(hexcode(str[0]) < 0 || hexcode(str[1]) < 0) break; str += 2; ++count; } return count; } size_t String::hexsize(const char *format) { size_t 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 uint8_t *binary, size_t size) { String out(size * 2); char *buf = out.data(); while(size--) { snprintf(buf, 3, "%02x", *(binary++)); buf += 2; } return out; } size_t String::hexdump(const uint8_t *binary, char *string, const char *format) { size_t 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; } size_t String::hex2bin(const char *str, uint8_t *bin, size_t max, bool ws) { size_t count = 0; size_t out = 0; int hi, lo; while(str && *str) { if(ws && isspace(*str)) { ++count; ++str; continue; } hi = hexcode(str[0]); lo = hexcode(str[1]); if(hi < 0 || lo < 0) break; *(bin++) = (hi << 4) | lo; str += 2; count += 2; if(++out > max) break; } return count; } size_t String::hexpack(uint8_t *binary, const char *string, const char *format) { size_t 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; size_t len = 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; } static const uint8_t alphabet[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; String String::b64(const uint8_t *bin, size_t size) { size_t dsize = (size * 4 / 3) + 1; String out(dsize); b64encode(out.data(), 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 = b64size(size); 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::b64size(size_t size) { return (size * 4 / 3) + 4; } size_t String::b64count(const char *src, bool ws) { 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) { if(isspace(*src)) { if(ws) { ++src; continue; } break; } c = (uint8_t)(*(src++)); if (c == '=') break; // end on invalid chars if (decoder[c] == 64) { break; } bits = (bits << 6) + decoder[c]; if (bits & 0x1000000) { bits = 1; count += 3; } } if (bits & 0x40000) count += 2; else if (bits & 0x1000) ++count; return count; } size_t String::b64decode(uint8_t *dest, const char *src, size_t size, bool ws) { 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) { if(isspace(*src)) { if(ws) { ++count; ++src; continue; } break; } c = (uint8_t)(*(src++)); if (c == '=') { ++count; if(*src == '=') ++count; break; } // end on invalid chars if (decoder[c] == 64) { break; } ++count; bits = (bits << 6) + decoder[c]; if (bits & 0x1000000) { if (size < 3) { bits = 1; break; } *(dest++) = (uint8_t)((bits >> 16) & 0xff); *(dest++) = (uint8_t)((bits >> 8) & 0xff); *(dest++) = (uint8_t)((bits & 0xff)); bits = 1; size -= 3; } } if (bits & 0x40000) { if (size >= 2) { *(dest++) = (uint8_t)((bits >> 10) & 0xff); *(dest++) = (uint8_t)((bits >> 2) & 0xff); } } else if ((bits & 0x1000) && size) { *(dest++) = (uint8_t)((bits >> 4) & 0xff); } 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-7.0.0/corelib/socket.cpp0000644000175000017500000023631712633253131013542 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 #ifndef _MSWINDOWS_ #include #include #include #include #else #define HAVE_GETADDRINFO 1 #endif #ifdef HAVE_FCNTL_H #include #endif #include #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 namespace ucommon { typedef uint8_t 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; aip->ai_addrlen = sizeof(struct sockaddr_in6); *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; aip->ai_addrlen = sizeof(struct sockaddr_in); *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; aip->ai_addrlen = sizeof(struct sockaddr_in6); 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; aip->ai_addrlen = sizeof(struct sockaddr_in); } 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; if(WSAStartup(version, &status)) __THROW_RUNTIME("socket init failure"); atexit(_socketcleanup); _started = true; } #else void Socket::init(void) { } #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); struct hostaddr_internet 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; } } struct hostaddr_internet cidr::broadcast(void) const { struct hostaddr_internet 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; uint8_t 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((const struct 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((const struct 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); list = NULL; } } 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::modify(void) { if(!list) return NULL; return list->ai_addr; } const 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::modify(int family) { 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; } const struct sockaddr *Socket::address::get(int family) const { const struct sockaddr *ap; const 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, hints; while(node && node->ai_addr) { if(node->ai_addr && equal(addr, node->ai_addr)) return false; node = node->ai_next; } char buf[256], svc[16]; query(addr, buf, sizeof(buf)); snprintf(svc, sizeof(svc), "%d", port(addr)); memset(&hints, 0, sizeof(hints)); hints.ai_family = addr->sa_family; hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; node = NULL; getaddrinfo(buf, svc, &hints, &node); if (!node) return false; if (node->ai_next) freeaddrinfo(node->ai_next); node->ai_next = list; list = node; return true; } void Socket::address::copy(const struct addrinfo *addr) { clear(); while (addr) { if (addr->ai_addr) insert(addr->ai_addr); addr = addr->ai_next; } } 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::port(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() const { 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::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.data()) return 0; ssize_t result = Socket::readline(so, s.data(), s.size() + 1, iowait); if(result < 0) { ioerr = Socket::error(); s.clear(); return 0; } String::fix(s); return (size_t)result; } stringref_t Socket::readline(size_t size) { charvalues_t buf = stringref::create(size); if(!buf) return stringref_t(); ssize_t result = Socket::readline(so, buf->get(), buf->max() + 1, iowait); if(result < 0) return stringref_t(); stringref_t out; out.assign(buf); return out; } 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, uint8_t 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(const 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(const 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 = port(addr); break; #endif case AF_INET: cp = (caddr_t)(&((const struct sockaddr_in *)(addr))->sin_addr); len = 4; key = port(addr); break; default: return 0; } while(len--) { key = key << 1; key ^= cp[len]; } return key % keysize; } in_port_t Socket::port(const struct sockaddr *addr) { if(!addr) return 0; 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, socklen_t size) { assert(iface != NULL); assert(dest != NULL); int rtn = -1; socket_t so = INVALID_SOCKET; socklen_t slen = len(dest); if(size) memset(iface, 0, size); if(size && size < slen) return ENOMEM; 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); uint8_t *a1, *a2; if(s1->sa_family != s2->sa_family) return false; if(s1->sa_family != AF_INET) return true; a1 = (uint8_t *)&(((const struct sockaddr_in *)(s1))->sin_addr); a2 = (uint8_t *)&(((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_storage *storage, const struct sockaddr *address) { if(storage == NULL || address == NULL) return 0; memset(storage, 0, sizeof(struct sockaddr_storage)); return copy((struct sockaddr *)storage, address); } unsigned Socket::store(struct sockaddr_internet *storage, const struct sockaddr *address) { if(storage == NULL || address == NULL) return 0; memset(storage, 0, sizeof(struct sockaddr_internet)); 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); memset(addr, 0, slen); return ::getsockname(sock, (struct sockaddr *)addr, &slen); } int Socket::remote(socket_t sock, struct sockaddr_storage *addr) { socklen_t slen = sizeof(sockaddr_storage); memset(addr, 0, slen); return ::getpeername(sock, (struct sockaddr *)addr, &slen); } String str(Socket& so, size_t size) { String s(size); so.readline(s.data(), s.size()); String::fix(s); return s; } const struct sockaddr *linked_sockaddr_operations::_getaddrinfo(const struct addrinfo *list) const { return list->ai_addr; } const struct addrinfo *linked_sockaddr_operations::_nextaddrinfo(const struct addrinfo *list) const { if(!list) return NULL; return list->ai_next; } socket_t linked_sockaddr_operations::_getaddrsock(const struct addrinfo *list) const { if(!list) return INVALID_SOCKET; return ::socket(list->ai_family, list->ai_socktype, list->ai_protocol); } } // namespace ucommon ucommon-7.0.0/corelib/object.cpp0000644000175000017500000000576312606345104013521 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(); } AutoObject::AutoObject(ObjectProtocol *o) { if(o) o->retain(); object = o; } AutoObject::AutoObject() { object = 0; } void AutoObject::release(void) { if(object) object->release(); object = 0; } AutoObject::~AutoObject() { release(); } AutoObject::AutoObject(const AutoObject &from) { object = from.object; if(object) object->retain(); } bool AutoObject::operator!() const { return (object == 0); } AutoObject::operator bool() const { return (object != 0); } void AutoObject::set(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-7.0.0/corelib/protocols.cpp0000644000175000017500000001011112616070251014255 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 { 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 __THROW_ALLOC(); 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 __THROW_ALLOC(); return mem; } void *MemoryProtocol::zalloc(size_t size) { void *mem = alloc(size); if(mem) memset(mem, 0, size); else __THROW_ALLOC(); 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); } void LockingProtocol::_lock(void) { } void LockingProtocol::_unlock(void) { } LockingProtocol::~LockingProtocol() { } 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; } 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; } PrintProtocol::~PrintProtocol() { } InputProtocol::~InputProtocol() { } } // namespace ucommon ucommon-7.0.0/corelib/memory.cpp0000644000175000017500000004307012616070251013553 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(_MSC_VER) && _MSC_VER >= 1800 #include #ifndef HAVE_ALIGNED_ALLOC #define HAVE_ALIGNED_ALLOC 1 #endif #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; #if defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_ALIGNED_ALLOC) 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(const memalloc& copy) { count = 0; limit = 0; page = NULL; pagesize = copy.pagesize; align = copy.align; } 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; #if defined(HAVE_ALIGNED_ALLOC) && defined(_MSWINDOWS_) if (align) _aligned_free(page); else free(page); #else free(page); #endif page = next; } count = 0; } memalloc::page_t *memalloc::pager(void) { page_t *npage = NULL; #ifdef HAVE_POSIX_MEMALIGN void *addr; #endif if(limit && count >= limit) { __THROW_RUNTIME("pager exhausted"); return NULL; } #if defined(HAVE_POSIX_MEMALIGN) if(align && !posix_memalign(&addr, align, pagesize)) npage = (page_t *)addr; else npage = (page_t *)malloc(pagesize); #elif defined(HAVE_ALIGNED_ALLOC) if (align) npage = (page_t *)aligned_alloc(align, pagesize); else npage = (page_t *)malloc(pagesize); #else npage = (page_t *)malloc(pagesize); #endif if(!npage) { __THROW_ALLOC(); 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))) { __THROW_SIZE("Larger than pagesize"); 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(const mempager& copy) : memalloc(copy) { 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::get(unsigned ind) const { linked_pointer list = root; if(ind >= members) { __THROW_RANGE("stringpager outside range"); return NULL; } 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) { __THROW_RUNTIME("no members"); return NULL; } 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 == nullptr) { __THROW_RUNTIME("no root"); return NULL; } 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(nullptr), CountedObject() { } void PagerObject::reset(void) { CountedObject::reset(); LinkedObject::Next = NULL; } void PagerObject::dealloc(void) { pager->put(this); } void PagerObject::release(void) { CountedObject::release(); } void PagerObject::retain(void) { CountedObject::retain(); } 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; } } // namespace ucommon ucommon-7.0.0/corelib/cpr.cpp0000644000175000017500000001420012606345104013021 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_ #ifdef HAVE_SYS_TIMEB_H #include #endif 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; } int 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(); } #if !defined(_MSWINDOWS_) && !defined(__QNX__) extern "C" int stricmp(const char *s1, const char *s2) { #ifdef HAVE_STRICMP return stricmp(s1, s2); #else return strcasecmp(s1, s2); #endif } extern "C" int strnicmp(const char *s1, const char *s2, size_t size) { #ifdef HAVE_STRICMP return strnicmp(s1, s2, size); #else return strncasecmp(s1, s2, size); #endif } #endif // 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); assert(mem != NULL); return mem; } extern "C" void *cpr_memassign(size_t size, caddr_t addr, size_t max) { assert(addr); assert(size <= max); 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); } 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); } } #endif ucommon-7.0.0/corelib/shared.cpp0000664000175000017500000000557712570431074013530 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 #include #include namespace ucommon { SharedRef::SharedRef() : TypeRef() { } TypeRef SharedRef::get() { lock.acquire(); TypeRef ptr(ref); lock.release(); return ptr; } void SharedRef::get(TypeRef& ptr) { lock.acquire(); Counted *old = ref; ref = ptr.ref; if(ref) ref->retain(); lock.release(); if(old) old->release(); } void SharedRef::put(TypeRef& ptr) { lock.acquire(); ptr.ref = ref; lock.release(); } MappedPointer::Index::Index(LinkedObject **origin) : LinkedObject(origin) { key = value = NULL; } MappedPointer::MappedPointer(size_t indexes, condlock_t *locking, size_t paging) : pager(paging) { caddr_t p; if(!locking) { p = (caddr_t)pager.alloc(sizeof(condlock_t)); locking = new(p) condlock_t; } lock = locking; list = (LinkedObject **)pager.alloc(sizeof(LinkedObject *) * indexes); free = NULL; paths = 0; while(paths < indexes) list[paths++] = NULL; } MappedPointer::~MappedPointer() { pager.purge(); } LinkedObject *MappedPointer::access(size_t path) { lock->access(); return list[path % paths]; } LinkedObject *MappedPointer::modify(size_t path) { lock->modify(); return list[path % paths]; } void MappedPointer::release(void *object) { if(object != nullptr) lock->release(); } void MappedPointer::replace(Index *ind, void *object) { ind->value = object; lock->commit(); } void MappedPointer::remove(Index *ind, size_t path) { LinkedObject **root = &list[path % paths]; ind->delist(root); ind->enlist(&free); ind->key = ind->value = NULL; lock->commit(); } void MappedPointer::insert(const void *key, void *value, size_t path) { caddr_t p = (caddr_t)(free); if(free) free = free->getNext(); else p = (caddr_t)pager.alloc(sizeof(Index)); Index *ind = new(p) Index(&list[path % paths]); ind->key = key; ind->value = value; lock->commit(); } size_t MappedPointer::keypath(const uint8_t *addr, size_t size) { size_t value = size; while(size--) { value = (value << 3) ^ *(addr++); } return value; } } // namespace ucommon-7.0.0/corelib/mapped.cpp0000644000175000017500000003132012606345104013505 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) __THROW_ALLOC(); 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 __THROW_ALLOC(); } 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) __THROW_ALLOC(); 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) __THROW_ALLOC(); ::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) __THROW_ALLOC(); 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) __THROW_ALLOC(); #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::sbrk(size_t len) { assert(len > 0); void *mp = (void *)(map + used); if(used + len > size) __THROW_RANGE("Outside mapped memory"); used += len; return mp; } bool MappedMemory::copy(size_t offset, void *buffer, size_t bufsize) const { if(!map || (offset + bufsize > size)) { __THROW_RANGE("Outside mapped memory"); 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) __THROW_RANGE("outside mapped memory"); 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(this); if(freelist || used < size) rtn = true; return rtn; } ReusableObject *MappedReuse::request(void) { ReusableObject *obj = NULL; __AUTOLOCK(this); 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(this); 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-7.0.0/corelib/typeref.cpp0000644000175000017500000004044112633253131013717 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 #include namespace ucommon { TypeRef::Counted::Counted(void *addr, size_t objsize, TypeRelease *ar) : ObjectProtocol() { this->offset = (unsigned)((char *)this - (char *)addr); this->size = objsize; this->autorelease = ar; } void TypeRef::Counted::dealloc() { TypeRelease *rel = autorelease; if(rel) { autorelease = nullptr; rel->dealloc(this); return; } void *memory = (void *)((char *)this - offset); delete this; ::free(memory); } void TypeRef::Counted::operator delete(void *addr) { } void TypeRef::Counted::retain(void) { count.fetch_retain(); } void TypeRef::Counted::release(void) { if(count.fetch_release() < 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() { clear(); } void TypeRef::clear(void) { if(ref) ref->release(); ref = NULL; } bool TypeRef::is_released() { if(!ref) return true; if(ref->autorelease) return false; return true; } void TypeRef::set(const TypeRef& ptr) { if(ptr.ref) ptr.ref->retain(); clear(); ref = ptr.ref; } void TypeRef::assign(const typeref_guard& global) { global.sync.acquire(); if(global.ref) global.ref->retain(); clear(); ref = global.ref; global.sync.release(); } void TypeRef::set(TypeRef::Counted *object) { if(object) object->retain(); clear(); ref = object; } caddr_t TypeRef::mem(caddr_t addr) { size_t mask = (Thread::cache() - 1); while(((uintptr_t)addr) & mask) ++addr; return addr; } void typeref_guard::set(const TypeRef& pointer) { sync.lock(); TypeRef::set(pointer); sync.unlock(); } typeref::value::value(caddr_t addr, size_t objsize, const char *str, TypeRelease *ar) : TypeRef::Counted(addr, objsize, ar) { if(str) String::set(mem, objsize + 1, str); else mem[0] = 0; } void typeref::value::destroy(void) { count.clear(); release(); } typeref::typeref() : TypeRef() {} typeref::typeref(const typeref& copy) : TypeRef(copy) {} typeref::typeref(const char *str, TypeRelease *ar) : TypeRef() { size_t size = 0; if(str) size = strlen(str); caddr_t p = ar->allocate(sizeof(value) + size); TypeRef::set(new(mem(p)) value(p, size, str, ar)); } typeref::typeref(size_t size, TypeRelease *ar) : TypeRef() { caddr_t p = ar->allocate(sizeof(value) + size); TypeRef::set(new(mem(p)) value(p, size, "", ar)); } const char *typeref::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 *typeref::operator*() const { value *v = polystatic_cast(ref); if(!v) return NULL; return &v->mem[0]; } size_t typeref::len() const { value *v = polystatic_cast(ref); if(!v) return 0; return v->len(); } const typeref typeref::operator+(const char *str2) const { value *v1 = polystatic_cast(ref); const char *str1 = ""; TypeRelease *ar = nullptr; if(v1) { str1 = &v1->mem[0]; ar = v1->autorelease; } if(!str2) str2 = ""; size_t ss = strlen(str1); ss += strlen(str2); charvalues_t results = create(ss, ar); snprintf(results->get(), results->max() + 1, "%s%s", str1, str2); stringref_t result; result.assign(results); return result; } typeref& typeref::operator=(const typeref& objref) { TypeRef::set(objref); return *this; } typeref& typeref::operator=(const char *str) { set(str); return *this; } void typeref::set(const char *str, TypeRelease *ar) { clear(); size_t size = 0; if(str) size = strlen(str); caddr_t p = ar->allocate(sizeof(value) + size); TypeRef::set(new(mem(p)) value(p, size, str, ar)); } void typeref::b64(const uint8_t *bytes, size_t bsize, TypeRelease *ar) { clear(); size_t len = String::b64size(bsize); caddr_t p = ar->allocate(sizeof(value) + len); value *s = new(mem(p)) value(p, len, "", ar); String::b64encode(&s->mem[0], bytes, bsize); TypeRef::set(s); } void typeref::hex(const uint8_t *bytes, size_t bsize, TypeRelease *ar) { clear(); size_t len = bsize * 2; caddr_t p = ar->allocate(sizeof(value) + len); value *s = new(mem(p)) value(p, len, "", ar); for(size_t index = 0; index < bsize; ++index) { snprintf(&s->mem[index * 2], 3, "%2.2x", bytes[index]); } TypeRef::set(s); } void typeref::assign(value *chars) { clear(); chars->size = strlen(chars->mem); TypeRef::set(chars); } typeref& typeref::operator=(value *chars) { assign(chars); return *this; } typeref::value *typeref::create(size_t size, TypeRelease *ar) { caddr_t p = ar->allocate(sizeof(value) + size); return new(mem(p)) value(p, size, NULL, ar); } void typeref::destroy(typeref::value *chars) { if(chars) chars->destroy(); } void typeref::expand(typeref::value **handle, size_t size) { if(!handle || !*handle) return; typeref::value *change = create(size + (*handle)->max()); if(change) String::set(change->get(), change->max() + 1, (*handle)->get()); destroy(*handle); *handle = change; } bool typeref::operator==(const typeref& ptr) const { value *v1 = polystatic_cast(ref); value *v2 = polystatic_cast(ptr.ref); if(!v1 || !v2) return false; return eq(&(v1->mem[0]), &(v2->mem[0])); } bool typeref::operator==(const char *obj) const { value *v = polystatic_cast(ref); if(!v) return false; return eq(&(v->mem[0]), obj); } bool typeref::operator==(value *chars) const { value *v = polystatic_cast(ref); if(!v || !chars) return false; return eq(&(v->mem[0]), &(chars->mem[0])); } bool typeref::operator<(const typeref& ptr) const { value *v1 = polystatic_cast(ref); value *v2 = polystatic_cast(ptr.ref); if(!v1 && v2) return true; if(!v1 && !v2) return true; if(v1 && !v2) return false; #ifdef HAVE_STRCOLL return strcoll(&(v1->mem[0]), &(v2->mem[0])) < 0; #else return strcmp(&(v1->mem[0]), &(v2->mem[0])) < 0: #endif } typeref::value::value(caddr_t addr, size_t objsize, const uint8_t *str, TypeRelease *ar) : TypeRef::Counted(addr, objsize, ar) { if(objsize && str) memcpy(mem, str, objsize); } typeref::typeref() : TypeRef() {} typeref::typeref(const typeref& copy) : TypeRef(copy) {} typeref::typeref(uint8_t *str, size_t size, TypeRelease *ar) : TypeRef() { caddr_t p = ar->allocate(sizeof(value) + size); TypeRef::set(new(mem(p)) value(p, size, str, ar)); } typeref::typeref(size_t size, TypeRelease *ar) : TypeRef() { caddr_t p = ar->allocate(sizeof(value) + size); TypeRef::set(new(mem(p)) value(p, size, nullptr, ar)); } typeref::typeref(bool mode, size_t bits, TypeRelease *ar) : TypeRef() { size_t size = (bits / 8); if(bits % 8) ++size; caddr_t p = ar->allocate(sizeof(value) + size); TypeRef::set(new(mem(p)) value(p, size, nullptr, ar)); set(mode, 0, bits); } void typeref::value::destroy(void) { count.clear(); release(); } typeref& typeref::operator=(const typeref& objref) { TypeRef::set(objref); return *this; } typeref& typeref::operator=(value *bytes) { assign(bytes); return *this; } void typeref::set(const uint8_t *str, size_t size, TypeRelease *ar) { clear(); caddr_t p = ar->allocate(sizeof(value) + size); TypeRef::set(new(mem(p)) value(p, size, str, ar)); } size_t typeref::hex(const char *str, bool ws, TypeRelease *ar) { clear(); size_t size = String::hexcount(str, ws); if(!size) return 0; caddr_t p = ar->allocate(sizeof(value) + size); TypeRef::set(new(mem(p)) value(p, size, nullptr, ar)); String::hex2bin(str, data(), size, ws); return size; } size_t typeref::b64(const char *str, bool ws, TypeRelease *ar) { clear(); size_t size = String::b64count(str, ws); if(!size) return 0; caddr_t p = ar->allocate(sizeof(value) + size); TypeRef::set(new(mem(p)) value(p, size, nullptr, ar)); String::b64decode(data(), str, size, ws); return size; } const uint8_t *typeref::operator*() const { if(!ref) return NULL; value *v = polystatic_cast(ref); return &v->mem[0]; } uint8_t *typeref::data() { if(!ref) return NULL; value *v = polystatic_cast(ref); return &v->mem[0]; } void typeref::assign(value *bytes) { clear(); TypeRef::set(bytes); } typeref::value *typeref::create(size_t size, TypeRelease *ar) { caddr_t p = ar->allocate(sizeof(value) + size); return new(mem(p)) value(p, size, nullptr, ar); } void typeref::destroy(typeref::value *bytes) { if(bytes) bytes->destroy(); } size_t TypeRef::size(void) const { if(!ref) return 0; return ref->size; } unsigned TypeRef::copies() const { if(!ref) return 0; return ref->copies(); } typeref typeref::hex() { typerefstr; if(ref) { value *v = polystatic_cast(ref); str.hex(&v->mem[0], v->size, ref->getRelease()); } return str; } typeref typeref::b64() { typerefstr; if(ref) { value *v = polystatic_cast(ref); str.b64(&v->mem[0], v->size, ref->getRelease()); } return str; } bool typeref::operator==(const typeref& ptr) const { value *v1 = polystatic_cast(ref); value *v2 = polystatic_cast(ptr.ref); if(!v1 || !v2 || v1->size != v2->size) return false; return !memcmp(&(v1->mem[0]), &(v2->mem[0]), v1->size); } bool typeref::operator==(value *bytes) const { value *v = polystatic_cast(ref); if(!v || !bytes || v->size != bytes->size) return false; return !memcmp(&(v->mem[0]), &(bytes->mem[0]), v->size); } const typeref typeref::operator+(const typeref&add) const { value *v1 = polystatic_cast(ref); value *v2 = polystatic_cast(add.ref); const uint8_t *b1 = NULL, *b2 = NULL; uint8_t *out; size_t s1 = 0, s2 = 0, max; typeref result; TypeRelease *ar = nullptr; if(v1) { s1 = v1->max(); b1 = v1->get(); ar = v1->autorelease; } if(v2) { s2 = v2->max(); b2 = v2->get(); } max = s1 + s2; if(!max) return result; bytevalues_t bytes = create(max, ar); out = const_cast(bytes->get()); if(s1) memcpy(out, b1, s1); if(s2) memcpy(out + s1, b2, s2); result.assign(bytes); return result; } bool typeref::get(size_t offset) { uint8_t mask = 1; value *v = polystatic_cast(ref); if(!v || v->size < offset / 8) return false; mask = mask << offset % 8; return (((v->get())[offset / 8] & mask) != 0); } size_t typeref::count(size_t offset, size_t bits) { uint8_t mask = 1; size_t total = 0; value *v = polystatic_cast(ref); if(!v) return 0; uint8_t *data = v->get(); while(bits--) { size_t pos = offset / 8; if(pos >= v->size) break; uint8_t bitmask = mask << (offset % 8); ++offset; if(data[pos] & bitmask) ++total; } return total; } size_t typeref::set(bool mode, size_t offset, size_t bits) { uint8_t mask = 1; size_t total = 0; value *v = polystatic_cast(ref); if(!v) return 0; uint8_t *data = v->get(); while(bits--) { size_t pos = offset / 8; if(pos >= v->size) break; uint8_t bitmask = mask << (offset % 8); ++offset; bool current = ((data[pos] & bitmask) != 0); if(current != mode) ++total; else continue; if(mode) data[pos] |= bitmask; else data[pos] &= ~bitmask; } return total; } caddr_t TypeRelease::allocate(size_t size) { return (caddr_t)::malloc(size + Thread::cache()); } void TypeRelease::release(TypeRef::Counted *obj) { obj->autorelease = nullptr; obj->dealloc(); } unsigned TypeRelease::purge() { if(delegate) return delegate->purge(); return 0; } void TypeRelease::enlist(TypeRef::Counted **root, TypeRef::Counted *obj) { obj->linkrelease = *root; *root = obj; } TypeRef::Counted *TypeRelease::delist(TypeRef::Counted **root) { TypeRef::Counted *obj = *root; if(obj) { *root = obj->linkrelease; obj->autorelease = nullptr; } else *root = nullptr; return obj; } void TypeRelease::dealloc(TypeRef::Counted *obj) { if(delegate) delegate->release(obj); else release(obj); } class __LOCAL TypeSecure __FINAL : public TypeRelease { private: void release(TypeRef::Counted *obj) __FINAL; public: inline TypeSecure() {} }; class __LOCAL TypeReleaseLater __FINAL : public TypeRelease { private: Mutex lock; TypeRef::Counted *list; void release(TypeRef::Counted *obj) __FINAL; public: TypeReleaseLater() { list = nullptr; } unsigned purge(void) __FINAL; }; void TypeReleaseLater::release(TypeRef::Counted *obj) { lock.acquire(); enlist(&list, obj); lock.release(); } unsigned TypeReleaseLater::purge() { TypeRef::Counted *obj; unsigned count = 0; TypeRef::Counted *pool; lock.acquire(); pool = list; list = nullptr; lock.release(); while((obj = delist(&pool)) != nullptr) { TypeRelease::release(obj); ++count; } return count; } void TypeSecure::release(TypeRef::Counted *obj) { char *addr = (char *)obj + sizeof(TypeRef::Counted); size_t size = TypeRelease::size(obj); memset(addr, 0, size); TypeRelease::release(obj); } static TypeSecure _secure_release; static TypeReleaseLater _release_later; TypeRelease auto_release; TypeRelease secure_release(&_secure_release); TypeRelease release_later(&_release_later); } // namespace ucommon-7.0.0/corelib/regex.cpp0000664000175000017500000001215412570431074013361 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-7.0.0/corelib/condition.cpp0000644000175000017500000003171712617437737014257 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 #include namespace ucommon { #if !defined(_MSTHREADS_) Conditional::attribute Conditional::attr; #endif unsigned ConditionalAccess::max_sharing = 0; void ConditionalAccess::limit_sharing(unsigned max) { max_sharing = max; } void Conditional::set(struct timespec *ts, timeout_t msec) { assert(ts != NULL); #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) clock_gettime(_posix_clocking, ts); #else timeval tv; gettimeofday(&tv, NULL); ts->tv_sec = tv.tv_sec; ts->tv_nsec = tv.tv_usec * 1000l; #endif ts->tv_sec += msec / 1000; ts->tv_nsec += (msec % 1000) * 1000000l; while(ts->tv_nsec >= 1000000000l) { ++ts->tv_sec; ts->tv_nsec -= 1000000000l; } } #ifdef _MSTHREADS_ ConditionMutex::ConditionMutex() { InitializeCriticalSection(&mutex); } ConditionMutex::~ConditionMutex() { DeleteCriticalSection(&mutex); } Conditional::Conditional() { InitializeConditionVariable(&cond); } Conditional::~Conditional() { } void Conditional::wait(void) { SleepConditionVariableCS(&cond, &mutex, INFINITE); } bool Conditional::wait(timeout_t timeout) { if(SleepConditionVariableCS(&cond, &mutex, timeout)) return true; return false; } void Conditional::signal(void) { WakeConditionVariable(&cond); } void Conditional::broadcast(void) { WakeAllConditionVariable(&cond); } bool Conditional::wait(struct timespec *ts) { assert(ts != NULL); return wait((timeout_t)(ts->tv_sec * 1000 + (ts->tv_nsec / 1000000l))); } ConditionVar::ConditionVar(ConditionMutex *m) { shared = m; InitializeConditionVariable(&cond); } ConditionVar::~ConditionVar() { } void ConditionVar::wait(void) { SleepConditionVariableCS(&cond, &shared->mutex, INFINITE); } bool ConditionVar::wait(timeout_t timeout) { if(SleepConditionVariableCS(&cond, &shared->mutex, timeout)) return true; return false; } void ConditionVar::signal(void) { WakeConditionVariable(&cond); } void ConditionVar::broadcast(void) { WakeAllConditionVariable(&cond); } bool ConditionVar::wait(struct timespec *ts) { assert(ts != NULL); return wait((timeout_t)(ts->tv_sec * 1000 + (ts->tv_nsec / 1000000l))); } #else #include Conditional::attribute::attribute() { Thread::init(); pthread_condattr_init(&attr); #if _POSIX_TIMERS > 0 && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(POSIX_TIMERS) #if defined(_POSIX_MONOTONIC_CLOCK) if(!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) _posix_clocking = CLOCK_MONOTONIC; #else pthread_condattr_setclock(&attr, CLOCK_REALTIME); #endif #endif } ConditionMutex::ConditionMutex() { if(pthread_mutex_init(&mutex, NULL)) __THROW_RUNTIME("mutex init failed"); } ConditionMutex::~ConditionMutex() { pthread_mutex_destroy(&mutex); } Conditional::Conditional() { if(pthread_cond_init(&cond, &Conditional::attr.attr)) __THROW_RUNTIME("conditional init failed"); } Conditional::~Conditional() { pthread_cond_destroy(&cond); } bool Conditional::wait(timeout_t timeout) { struct timespec ts; set(&ts, timeout); return wait(&ts); } bool Conditional::wait(struct timespec *ts) { assert(ts != NULL); if(pthread_cond_timedwait(&cond, &mutex, ts) == ETIMEDOUT) return false; return true; } ConditionVar::ConditionVar(ConditionMutex *m) { shared = m; if(pthread_cond_init(&cond, &Conditional::attr.attr)) __THROW_RUNTIME("conditional init failed"); } ConditionVar::~ConditionVar() { pthread_cond_destroy(&cond); } bool ConditionVar::wait(timeout_t timeout) { struct timespec ts; Conditional::set(&ts, timeout); return wait(&ts); } bool ConditionVar::wait(struct timespec *ts) { assert(ts != NULL); if(pthread_cond_timedwait(&cond, &shared->mutex, ts) == ETIMEDOUT) return false; return true; } #endif #if defined(_MSTHREADS_) ConditionalAccess::ConditionalAccess() { waiting = pending = sharing = 0; InitializeConditionVariable(&bcast); } ConditionalAccess::~ConditionalAccess() { } bool ConditionalAccess::waitBroadcast(timeout_t timeout) { if(SleepConditionVariableCS(&bcast, &mutex, timeout)) return true; return false; } void ConditionalAccess::waitBroadcast() { SleepConditionVariableCS(&bcast, &mutex, INFINITE); } void ConditionalAccess::waitSignal() { SleepConditionVariableCS(&cond, &mutex, INFINITE); } bool ConditionalAccess::waitSignal(timeout_t timeout) { if(SleepConditionVariableCS(&cond, &mutex, timeout)) return true; return false; } bool ConditionalAccess::waitBroadcast(struct timespec *ts) { assert(ts != NULL); return waitBroadcast((timeout_t)(ts->tv_sec * 1000 + (ts->tv_nsec / 1000000l))); } bool ConditionalAccess::waitSignal(struct timespec *ts) { assert(ts != NULL); return waitSignal((timeout_t)(ts->tv_sec * 1000 + (ts->tv_nsec / 1000000l))); } #else ConditionalAccess::ConditionalAccess() { waiting = pending = sharing = 0; if(pthread_cond_init(&bcast, &attr.attr)) __THROW_RUNTIME("conditional init failed"); } ConditionalAccess::~ConditionalAccess() { pthread_cond_destroy(&bcast); } bool ConditionalAccess::waitSignal(timeout_t timeout) { struct timespec ts; set(&ts, timeout); return waitSignal(&ts); } bool ConditionalAccess::waitBroadcast(struct timespec *ts) { assert(ts != NULL); if(pthread_cond_timedwait(&bcast, &mutex, ts) == ETIMEDOUT) return false; return true; } bool ConditionalAccess::waitBroadcast(timeout_t timeout) { struct timespec ts; set(&ts, timeout); return waitBroadcast(&ts); } bool ConditionalAccess::waitSignal(struct timespec *ts) { assert(ts != NULL); if(pthread_cond_timedwait(&cond, &mutex, ts) == ETIMEDOUT) return false; return true; } #endif void ConditionalAccess::modify(void) { lock(); while(sharing) { ++pending; waitSignal(); --pending; } } void ConditionalAccess::commit(void) { if(pending) signal(); else if(waiting) broadcast(); unlock(); } void ConditionalAccess::access(void) { lock(); assert(!max_sharing || sharing < max_sharing); while(pending) { ++waiting; waitBroadcast(); --waiting; } ++sharing; unlock(); } void ConditionalAccess::release(void) { lock(); assert(sharing); --sharing; if(pending && !sharing) signal(); else if(waiting && !pending) broadcast(); unlock(); } ConditionalLock::ConditionalLock() : ConditionalAccess() { contexts = NULL; } ConditionalLock::~ConditionalLock() { linked_pointer cp = contexts, next; while(cp) { next = cp->getNext(); delete *cp; cp = next; } } ConditionalLock::Context *ConditionalLock::getContext(void) { Context *slot = NULL; pthread_t tid = Thread::self(); linked_pointer cp = contexts; while(cp) { if(cp->count && Thread::equal(cp->thread, tid)) return *cp; if(!cp->count) slot = *cp; cp.next(); } if(!slot) { slot = new Context(&this->contexts); slot->count = 0; } slot->thread = tid; return slot; } void ConditionalLock::_share(void) { access(); } void ConditionalLock::_unshare(void) { release(); } void ConditionalLock::modify(void) { Context *context; lock(); context = getContext(); assert(context && sharing >= context->count); sharing -= context->count; while(sharing) { ++pending; waitSignal(); --pending; } ++context->count; } void ConditionalLock::commit(void) { Context *context = getContext(); --context->count; if(context->count) { sharing += context->count; unlock(); } else ConditionalAccess::commit(); } void ConditionalLock::release(void) { Context *context; lock(); context = getContext(); assert(sharing && context && context->count > 0); --sharing; --context->count; if(pending && !sharing) signal(); else if(waiting && !pending) broadcast(); unlock(); } void ConditionalLock::access(void) { Context *context; lock(); context = getContext(); assert(context && (!max_sharing || sharing < max_sharing)); // reschedule if pending exclusives to make sure modify threads are not // starved. ++context->count; while(context->count < 2 && pending) { ++waiting; waitBroadcast(); --waiting; } ++sharing; unlock(); } void ConditionalLock::exclusive(void) { Context *context; lock(); context = getContext(); assert(sharing && context && context->count > 0); sharing -= context->count; while(sharing) { ++pending; waitSignal(); --pending; } } void ConditionalLock::share(void) { Context *context = getContext(); assert(!sharing && context && context->count); sharing += context->count; unlock(); } Barrier::Barrier(unsigned limit) : Conditional() { count = limit; waits = 0; } Barrier::~Barrier() { lock(); if(waits) broadcast(); unlock(); } void Barrier::set(unsigned limit) { assert(limit > 0); lock(); count = limit; if(count <= waits) { waits = 0; broadcast(); } unlock(); } void Barrier::dec(void) { lock(); if(count) --count; unlock(); } unsigned Barrier::operator--(void) { unsigned result; lock(); if(count) --count; result = count; unlock(); return result; } void Barrier::inc(void) { lock(); count++; if(count <= waits) { waits = 0; broadcast(); } unlock(); } unsigned Barrier::operator++(void) { unsigned result; lock(); count++; if(count <= waits) { waits = 0; broadcast(); } result = count; unlock(); return result; } bool Barrier::wait(timeout_t timeout) { bool result; Conditional::lock(); if(!count) { Conditional::unlock(); return true; } if(++waits >= count) { waits = 0; Conditional::broadcast(); Conditional::unlock(); return true; } result = Conditional::wait(timeout); Conditional::unlock(); return result; } void Barrier::wait(void) { Conditional::lock(); if(!count) { Conditional::unlock(); return; } if(++waits >= count) { waits = 0; Conditional::broadcast(); Conditional::unlock(); return; } Conditional::wait(); Conditional::unlock(); } Semaphore::Semaphore(unsigned limit) : Conditional() { waits = 0; count = limit; used = 0; } Semaphore::Semaphore(unsigned limit, unsigned avail) : Conditional() { assert(limit > 0); assert(avail <= limit); waits = 0; count = limit; used = limit - avail; } void Semaphore::_share(void) { wait(); } void Semaphore::_unshare(void) { release(); } bool Semaphore::wait(timeout_t timeout) { bool result = true; struct timespec ts; Conditional::set(&ts, timeout); lock(); while(used >= count && result) { ++waits; result = Conditional::wait(&ts); --waits; if(!count) break; } if(result && count) ++used; unlock(); return result; } void Semaphore::wait(void) { lock(); if(used >= count) { ++waits; Conditional::wait(); --waits; } if(count) ++used; unlock(); } void Semaphore::release(void) { lock(); if(used) --used; if(waits) { if(count) signal(); else broadcast(); } unlock(); } void Semaphore::set(unsigned value) { assert(value > 0); unsigned diff; lock(); count = value; if(used >= count || !waits) { unlock(); return; } diff = count - used; if(diff > waits) diff = waits; unlock(); while(diff--) { lock(); signal(); unlock(); } } } // namespace ucommon ucommon-7.0.0/corelib/access.cpp0000644000175000017500000000515612616070251013507 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 { SharedProtocol::~SharedProtocol() { } ExclusiveProtocol::~ExclusiveProtocol() { } void SharedProtocol::exclusive(void) { } void SharedProtocol::share(void) { } SharedProtocol::Locking::Locking(SharedProtocol *obj) { assert(obj != NULL); lock = obj; modify = false; state = 0; lock->_share(); } SharedProtocol::Locking::Locking(const Locking& copy) { assert(copy.modify == false); lock = copy.lock; modify = false; state = 0; if(lock) lock->_share(); } SharedProtocol::Locking& SharedProtocol::Locking::operator=(const Locking& copy) { assert(copy.modify == false); release(); lock = copy.lock; state = 0; if(lock) lock->_share(); return *this; } ExclusiveProtocol::Locking::Locking(ExclusiveProtocol *obj) { assert(obj != NULL); lock = obj; lock->_lock(); } SharedProtocol::Locking::~Locking() { if(lock) { if(modify) lock->share(); lock->_unshare(); lock = NULL; modify = false; } } ExclusiveProtocol::Locking::~Locking() { if(lock) { lock->_unlock(); lock = NULL; } } void SharedProtocol::Locking::release() { if(lock) { if(modify) lock->share(); lock->_unshare(); lock = NULL; modify = false; } } void ExclusiveProtocol::Locking::release() { if(lock) { lock->_unlock(); lock = NULL; } } void SharedProtocol::Locking::exclusive(void) { if(lock && !modify) { lock->exclusive(); modify = true; } } void SharedProtocol::Locking::share(void) { if(lock && modify) { lock->share(); modify = false; } } } // namespace ucommon ucommon-7.0.0/corelib/fsys.cpp0000644000175000017500000010653512633253131013234 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(); } fsys& fsys::operator=(fd_t from) { HANDLE pHandle = GetCurrentProcess(); if(fd != INVALID_HANDLE_VALUE) { if(!CloseHandle(fd)) { error = remapError(); return *this; } } if(DuplicateHandle(pHandle, from, pHandle, &fd, 0, FALSE, DUPLICATE_SAME_ACCESS)) error = 0; else { fd = INVALID_HANDLE_VALUE; error = remapError(); } return *this; } fsys& fsys::operator=(const fsys& from) { HANDLE pHandle = GetCurrentProcess(); if(fd != INVALID_HANDLE_VALUE) { if(!CloseHandle(fd)) { error = remapError(); return *this; } } if(DuplicateHandle(pHandle, from.fd, pHandle, &fd, 0, FALSE, DUPLICATE_SAME_ACCESS)) error = 0; else { fd = INVALID_HANDLE_VALUE; error = remapError(); } return *this; } 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) { int rtn = ::read(fd, buf, len); 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) { int rtn = ::write(fd, buf, len); 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; } fsys& 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(); } return *this; } fsys& 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(); } return *this; } 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(); } fsys& fsys::operator*=(fd_t& from) { if(fd != INVALID_HANDLE_VALUE) close(); fd = from; from = INVALID_HANDLE_VALUE; return *this; } 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_ stringref_t fsys::prefix(void) { char *cp = _getcwd(NULL, 0); stringref_t result(cp); if(cp) ::free(cp); return result; } #else stringref_t fsys::prefix(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 } // namespace ucommon ucommon-7.0.0/corelib/atomic.cpp0000644000175000017500000002442112633253131013515 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 #if __cplusplus >= 201103l #include #endif // blacklist some architectures...like sparc odd 24 bit atomics #define HAVE_ATOMICS 1 #if defined(sparc) #undef HAVE_ATOMICS #endif #ifdef HAVE_STDALIGN_H #include #endif #if defined(_MSC_VER) && _MSC_VER >= 1800 #include #ifndef HAVE_ALIGNED_ALLOC #define HAVE_ALIGNED_ALLOC 1 #endif #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(__has_feature) && defined(__has_extension) #if __has_feature(c_atomic) || __has_extension(c_atomic) #define __CLANG_ATOMICS #endif #endif #if defined(_MSWINDOWS_) bool Atomic::is_lockfree(void) { return true; } 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::fetch_retain() volatile { return InterlockedExchangeAdd(&value, (atomic_t)1); } atomic_t Atomic::counter::fetch_release() volatile { return InterlockedExchangeAdd(&value, (atomic_t)-1); } 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 __cplusplus >= 201103L && defined(HAVE_ATOMICS) typedef std::atomic *atomic_val; bool Atomic::is_lockfree(void) { atomic_val ptr; return std::atomic_is_lock_free(ptr); } atomic_t Atomic::counter::get() volatile { return std::atomic_load_explicit((atomic_val)(&value), std::memory_order_acquire); } void Atomic::counter::clear() volatile { std::atomic_fetch_and_explicit((atomic_val)(&value), (atomic_t)0, std::memory_order_release); } atomic_t Atomic::counter::fetch_retain() volatile { return std::atomic_fetch_add_explicit((atomic_val)(&value), (atomic_t)1, std::memory_order_relaxed); } atomic_t Atomic::counter::fetch_release() volatile { return std::atomic_fetch_sub_explicit((atomic_val)(&value), (atomic_t)1, std::memory_order_release); } atomic_t Atomic::counter::fetch_add(atomic_t change) volatile { return std::atomic_fetch_add_explicit((atomic_val)(&value), (atomic_t)change, std::memory_order_release); } atomic_t Atomic::counter::fetch_sub(atomic_t change) volatile { return std::atomic_fetch_sub_explicit((atomic_val)(&value), (atomic_t)change, std::memory_order_release); } bool Atomic::spinlock::acquire(void) volatile { // if not locked by another already, then we acquired it... return (!std::atomic_exchange_explicit((atomic_val)(&value), (atomic_t)1, std::memory_order_acquire)); } void Atomic::spinlock::wait(void) volatile { while (std::atomic_exchange_explicit((atomic_val)(&value), (atomic_t)1, std::memory_order_acquire)) { while (value) ; } } void Atomic::spinlock::release(void) volatile { std::atomic_store_explicit((atomic_val)(&value), (atomic_t)0, std::memory_order_release); } #elif defined(__CLANG_ATOMICS) && defined(HAVE_ATOMICS) typedef _Atomic(atomic_t) *atomic_val; bool Atomic::is_lockfree(void) { return true; } atomic_t Atomic::counter::get() volatile { return __c11_atomic_load((atomic_val)(&value), __ATOMIC_ACQUIRE); } void Atomic::counter::clear() volatile { __c11_atomic_fetch_and((atomic_val)(&value), (atomic_t)0, __ATOMIC_RELEASE); } atomic_t Atomic::counter::fetch_retain() volatile { return __c11_atomic_fetch_add((atomic_val)(&value), (atomic_t)1, __ATOMIC_RELAXED); } atomic_t Atomic::counter::fetch_release() volatile { return __c11_atomic_fetch_sub((atomic_val)(&value), (atomic_t)1, __ATOMIC_RELEASE); } 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_ACQUIRE)); } void Atomic::spinlock::wait(void) volatile { while (__c11_atomic_exchange((atomic_val)(&value), 1, __ATOMIC_ACQUIRE)) { while (value) ; } } void Atomic::spinlock::release(void) volatile { __c11_atomic_store((atomic_val)(&value), 0, __ATOMIC_RELEASE); } #elif __GNUC_PREREQ__(4, 7) && defined(HAVE_ATOMICS) bool Atomic::is_lockfree(void) { return true; } atomic_t Atomic::counter::fetch_retain() volatile { return __atomic_fetch_add(&value, (atomic_t)1, __ATOMIC_RELAXED); } atomic_t Atomic::counter::fetch_release() volatile { return __atomic_fetch_sub(&value, (atomic_t)1, __ATOMIC_RELEASE); } atomic_t Atomic::counter::fetch_add(atomic_t change) volatile { return __atomic_fetch_add(&value, change, __ATOMIC_RELEASE); } atomic_t Atomic::counter::fetch_sub(atomic_t change) volatile { return __atomic_fetch_sub(&value, change, __ATOMIC_RELEASE); } atomic_t Atomic::counter::get() volatile { return __atomic_fetch_add(&value, 0, __ATOMIC_ACQUIRE); } void Atomic::counter::clear() volatile { __atomic_fetch_and(&value, (atomic_t)0, __ATOMIC_RELEASE); } bool Atomic::spinlock::acquire(void) volatile { // if not locked by another already, then we acquired it... return (!__atomic_test_and_set(&value, __ATOMIC_ACQUIRE)); } void Atomic::spinlock::wait(void) volatile { while (__atomic_test_and_set(&value, __ATOMIC_ACQUIRE)) { while (value) ; } } void Atomic::spinlock::release(void) volatile { __atomic_clear(&value, __ATOMIC_RELEASE); } #elif __GNUC_PREREQ__(4, 1) && defined(HAVE_ATOMICS) bool Atomic::is_lockfree(void) { return true; } atomic_t Atomic::counter::fetch_retain() volatile { return __sync_fetch_and_add(&value, (atomic_t)1); } atomic_t Atomic::counter::fetch_release() volatile { return __sync_fetch_and_sub(&value, (atomic_t)1); } 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 bool Atomic::is_lockfree(void) { return false; } 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; } atomic_t Atomic::counter::fetch_retain() volatile { return fetch_add(1); } atomic_t Atomic::counter::fetch_release() volatile { return fetch_sub(1); } 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 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; } Atomic::Aligned::Aligned(size_t object, size_t align) { if(!align) align = Thread::cache(); offset = 0; caddr_t base = (caddr_t)::malloc(align + object); size_t mask = align - 1; while((intptr_t)base & mask) { ++offset; ++base; } address = (void *)base; } Atomic::Aligned::~Aligned() { caddr_t base = (caddr_t)address; if(base) { while(offset--) { --base; } ::free(base); address = nullptr; } } } // namespace ucommon ucommon-7.0.0/corelib/Makefile.in0000644000175000017500000006034712617437745013632 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 timer.lo memory.lo socket.lo access.lo thread.lo \ fsys.lo cpr.lo reuse.lo stream.lo keydata.lo numbers.lo \ datetime.lo unicode.lo atomic.lo condition.lo regex.lo \ protocols.lo shell.lo typeref.lo arrayref.lo mapref.lo \ shared.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 timer.cpp memory.cpp socket.cpp access.cpp \ thread.cpp fsys.cpp cpr.cpp reuse.cpp stream.cpp \ keydata.cpp numbers.cpp datetime.cpp unicode.cpp atomic.cpp \ condition.cpp regex.cpp protocols.cpp shell.cpp \ typeref.cpp arrayref.cpp mapref.cpp shared.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)/arrayref.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atomic.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/condition.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)/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)/mapref.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)/protocols.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reuse.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shared.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)/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@ .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-7.0.0/corelib/Makefile.am0000664000175000017500000000206412611715570013600 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 timer.cpp memory.cpp socket.cpp access.cpp \ thread.cpp fsys.cpp cpr.cpp reuse.cpp stream.cpp \ keydata.cpp numbers.cpp datetime.cpp unicode.cpp atomic.cpp \ condition.cpp regex.cpp protocols.cpp shell.cpp \ typeref.cpp arrayref.cpp mapref.cpp shared.cpp ucommon-7.0.0/corelib/keydata.cpp0000644000175000017500000002447512606345104013676 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); keydata::pointer 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); keydata::pointer 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::pointer 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); keyfile::pointer 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 > (DWORD)(size() - 64)) vsize = (DWORD)(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 > (DWORD)(size() - 64)) vsize = (DWORD)(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-7.0.0/corelib/shell.cpp0000664000175000017500000015603212611715570013364 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 #ifndef UCOMMON_SYSRUNTIME #include #endif #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