pax_global_header00006660000000000000000000000064141124257310014512gustar00rootroot0000000000000052 comment=e62e01dbec3e6bd7c7098926f1ad065a2d28657d commoncpp-7.0.1/000077500000000000000000000000001411242573100135125ustar00rootroot00000000000000commoncpp-7.0.1/AUTHORS000066400000000000000000000006461411242573100145700ustar00rootroot00000000000000Authors of GNU uCommon. David Sugar designed and implemented commoncpp & ucommon Eric Schendel recent improvements on the serial I/O classes Angelo Naselli as contributor and for bug fixing Leandro Melo de Sales as contributor for DCCP socket support Adrien BĂ©raud is improving the sockets api commoncpp-7.0.1/BUILDS000066400000000000000000000110711411242573100144170ustar00rootroot00000000000000Generic & Embedded Targets: By default, UCommon compiles with full support of C++ and the C++ ansi library. For deeply embedded targets, the stdc++ library (libstdc++ for gcc) can be disabled, along with exception handling and other C++ features that may add to runtime overhead. This is done using the --disable-stdcpp configure option. Any modern C++ compiler and posix platform with basic pthread support should be able to build UCommon successfully. Whether UCommon is compiled with or without c++ ansi library support, it should still be possible to mix and match UCommon code with software that is built with standard C++ runtimes. However, note that when std c++ is disabled, in addition to stripping out some library routines which depend on the C++ ansi library, exception handling and rtti is also disabled for the ucommon library. When using only static linking, the c++ ansi libraries are also disabled by default. This is to prevent bloat from static linkage of the ansi C++ library and static linkage is most common on embedded targets. The --enable-stdcpp option can be used to re-enable the full ansi c++ library. Project Indiana/OpenSolaris specific notes: You need to install SUNWhea or configure will fail on the preprocessor. You can use the Sun Studio 12 compiler as well as gcc. When building without Sun std c++ support (--disable-stdcpp), -lCrun is added alone without -lCstd. To make autogen.sh work (or svn checkout) requires a bunch of packages and setting the AUTOMAKE_SUFFIX="-1.10". You need SUNWgnome-common-devel, SUNWgm4, SUNWgmake, SUNWaconf, SUNWautomake-1.10, and SUNWlibtool. Microsoft Windows & MingW32 specific notes: For Microsoft Windows targets, we primarily focus on using debian hosted mingw32 cross-builds. Since libstdc++ is statically linked, we use the c model and build the ucommon subset by default, as otherwise software that uses plugins would be hugely bloated. Full libstdc++ support can always be re-enabled explicitly using --enable-stdcpp. It should be possible to build ucommon using Microsoft native compilers, and if people wish to submit patches for code changes based on using native Microsoft compilers, they will be accepted so long as they do not break other build environments. Native Microsoft Visual studio files may be generated using cmake. We do not recommend the use of proprietary compilers on proprietary operating systems, and we will continue to work to make the debian hosted mingw build environment as effective for building our packages as we can. Support for older GCC (<3.x): UCommon, like GNU Common C++, is meant to compile anywhere a C++ compiler exists. However, there are specific limitations in gcc < 3, particularly in relation to namespace support. For this reason, we disable libstdc++ support by default, although again it can be enabled using --enable-stdcpp. QNX (Neutrino) Hosts & Targets: QNX distributes and uses both gcc 2.95.3 and 3.3.1, but the latter is only with the latest 6.3.x series release. The userland build tools are old and broken for svn checkout to automake build, including libtool 1.4.x. Nontheless we are able to support direct hosting and builds of ucommon on QNX. Those using tarballs from official distributions should not have these problems. Since gcc 2.95 is the default, the default builds without stdc++. Even worse, if you enable libstdc++ (--enable-stdcpp), the resulting executables will compile and link, but will fail at runtime with symbol link errors. However, executables built and linked with ucommon with stdcpp disabled do link and run fine (and the "make check" tests will pass). Strange. Minix and other non-pthread posix targets: Starting with 1.8.1, uCommon will optionally build with GNU pth. This can be used to establish uCommon C++ threaded design architecture on platforms which do not natively support true threading, such as Minix. On platforms that attempt to simulate threading with user mode non pre-emptive threading, it is recommended to use uCommon with GNU pth even if there is a local library that simulates pthread functionality. The reason is that uCommon also wraps and schedules I/O operations through the pth I/O functions. Recent Platforms and Versions Tested: GNU/Linux gcc 6.0.0 x86, x86_64, arm, mipsel GNU/Linux clang 6.0.0 x86_64 OpenBSD4 6.0.0 i386 NetBSD5 4.0.0 i386 OpenSolaris sunwpro 6.0.0 x86_64 (double) conv of DateTime fails, applog.cpp std::map failure OS/X 6.0.0 ppc, x86 QNX (gcc 2.95) 1.8.1 i386 MingW/cross 6.0.0 i386, x86 ipv6 broken in wine unit tests Cygwin 1.8.0 i386 commoncpp-7.0.1/CMakeLists.txt000066400000000000000000000176761411242573100162730ustar00rootroot00000000000000# Copyright (C) 2009-2014 David Sugar, Tycho Softworks # Copyright (C) 2015-2020 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. # # This is a simplified build system for GNU uCommon. In particular, it # offers limited cmodel linkage support, at least for mingw32 support (and # probably visual c 6 also). If one really needs to do such things outside # these use cases, it is suggested to continue using the existing autotools # configure script driven build environment instead. Mostly the cmake one is # meant for generating project files for those working with IDE's to do # otherwise generic builds of the library and supporting applications. cmake_minimum_required(VERSION 3.12) PROJECT(ucommon) set (VERSION 7.0.1) set (CMAKE_MACOSX_RPATH 1) # when we override default install prefix, assume full path is used... if(WIN32) set(MODULE_FLAGS "-module -shared -no-undefined") else() set(MODULE_FLAGS "-module -shared -avoid-version") endif() # project options option(BUILD_STDLIB "Set to OFF to disable C++ stdlib" ON) if(WIN32) option(BUILD_RUNTIME "Set to OFF to build static runtime" ON) if(BUILD_RUNTIME) set(BUILD_RUNTIME_TYPE SHARED) endif() option(BUILD_STATIC "Set to OFF to build shared libraries" ON) set(POSIX_TIMERS OFF CACHE BOOL "does not use posix timers" FORCE) else() option(BUILD_STATIC "Set to ON to build static libraries" OFF) option(POSIX_TIMERS "Set to ON to enable" OFF) endif() option(BUILD_EXTRAS "Set to OFF to disable" ON) option(BUILD_TESTING "Set to ON to build test programs" OFF) option(CRYPTO_STATIC "Set to ON to build static crypto" OFF) option(CRYPTO_OPENSSL "Set to OFF to disable openssl" ON) MARK_AS_ADVANCED(POSIX_TIMERS BUILD_EXTRAS) MESSAGE( STATUS "Configuring GNU ${PROJECT_NAME} ${VERSION}...") set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") include(GNUInstallDirs) include(CheckFunctionExists) include(CheckLibraryExists) include(CheckIncludeFiles) include(CTest) include(CapeConfig) include(CapeMakeTargets) include(ucommon) include(config) # some platform detection support, especially for bsd's... if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) if(EXISTS "/usr/local/lib/") include_directories("/usr/local/include") link_directories("/usr/local/lib") endif() if(EXISTS "/usr/pkg/lib/") include_directories("/usr/pkg/include") link_directories("/usr/pkg/lib") endif() endif() # we are making this optional in automake, not default... find_package(PkgConfig) if(HAVE_REGEX_H) check_library_exists(regex regfree "" HAVE_REGEX_LIB) if(HAVE_REGEX_LIB OR MINGW OR MSYS) set(UCOMMON_LIBS ${UCOMMON_LIBS} "regex") endif() endif() set(UCOMMON_LIBS ${UCOMMON_LIBS} ${UCOMMON_LINKING}) # for some reason, normal library searches always fail on broken windows if (WIN32 AND NOT UNIX AND NOT MINGW AND NOT MSYS) set(HAVE_GETADDRINFO True) set(HAVE_INET_NTOP True) endif() # alternate we use generic cmake openssl search... if(CRYPTO_OPENSSL AND PKGCONFIG_FOUND) pkg_check_modules(OPENSSL openssl>=1.0.0) endif() if(CRYPTO_OPENSSL AND NOT OPENSSL_FOUND) FIND_PACKAGE(OpenSSL) if(OPENSSL_FOUND) set(OPENSSL_INCLUDE_DIRS "${OPENSSL_INCLUDE_DIR}") set(CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES};${OPENSSL_INCLUDE_DIR}") endif() endif() if(OPENSSL_FOUND) set(HAVE_OPENSSL TRUE) check_include_files(openssl/fips.h HAVE_OPENSSL_FIPS_H) elseif(PKGCONFIG_FOUND) pkg_check_modules(GNUTLS gnutls>=3.0.0) endif() # common build options can be passed to cmake using WITH_CFLAGS, WITH_LIBS, # and WITH_INCLUDES. include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc ${WITH_INCLUDES}) add_definitions(${UCOMMON_FLAGS} ${WITH_CFLAGS}) link_libraries(${WITH_LIBS}) # by default we build static libs for windows, shared libs for unix. # we may also set this from a top level cmake or -DWITH_XX_LIBS if(BUILD_STATIC) set(BUILD_LIBRARY_TYPE STATIC) set(BUILD_CRYPTO_TYPE STATIC) else() set(BUILD_LIBRARY_TYPE SHARED) if(CRYPTO_STATIC) set(BUILD_CRYPTO_TYPE STATIC) else() set(BUILD_CRYPTO_TYPE SHARED) endif() endif() if(NOT BUILD_RUNTIME_TYPE) set(BUILD_RUNTIME_TYPE ${BUILD_LIBRARY_TYPE}) endif() file(GLOB common_src corelib/*.cpp) file(GLOB ucommon_inc inc/ucommon/*.h) file(GLOB commoncpp_src commoncpp/*.cpp) file(GLOB commoncpp_inc inc/commoncpp/*.h) file(GLOB scripts_man *.1) file(GLOB cmakes_inc cmake/Cape*.cmake) list(REMOVE_ITEM ucommon_inc inc/ucommon/secure.h) set(secure_inc inc/ucommon/secure.h) if(OPENSSL_FOUND) include_directories(${OPENSSL_INCLUDE_DIRS}) link_directories(${OPENSSL_LIBRARY_DIRS}) file(GLOB secure_src openssl/*.cpp openssl/*.h) list(APPEND secure_src nossl/common.cpp) if(MINGW) set(SECURE_LIBS ${OPENSSL_LIBRARIES} gdi32 z) elseif(WIN32 AND NOT CYGWIN) set(SECURE_LIBS ${OPENSSL_LIBRARIES} gdi32) else() set(SECURE_LIBS ${OPENSSL_LIBRARIES}) endif() elseif(GNUTLS_FOUND) include_directories(${GNUTLS_INCLUDE_DIRS}) link_directories(${GNUTLS_LIBRARY_DIRS}) file(GLOB secure_src gnutls/*.cpp gnutls/*.h) list(APPEND secure_src nossl/common.cpp) set(SECURE_LIBS ${GNUTLS_LIBRARIES}) else() file(GLOB secure_src nossl/*.cpp nossl/*.h) endif() pc_flags(PKG_UCOMMON_FLAGS ${UCOMMON_FLAGS} ${UCOMMON_VISIBILITY_FLAG}) pc_libs(PKG_UCOMMON_LIBS ${UCOMMON_LIBS}) pc_libs(PKG_SECURE_LIBS ${SECURE_LIBS}) create_specfile() create_headers(ucommon-config.h) create_scripts(scripts_cfg ucommon-config commoncpp-config) create_pcfiles(pc_files ucommon commoncpp) add_library(ucommon ${BUILD_RUNTIME_TYPE} ${common_src} ${ucommon_inc}) set_library_version(ucommon) target_link_libraries(ucommon ${UCOMMON_LIBS} ${WITH_LIBS}) add_library(usecure ${BUILD_CRYPTO_TYPE} ${secure_src} ${secure_inc}) set_library_version(usecure) target_link_libraries(usecure ucommon ${WITH_LIBS} ${SECURE_LIBS} ${UCOMMON_LIBS}) add_dependencies(usecure ucommon) if(BUILD_STDLIB) add_library(commoncpp ${BUILD_LIBRARY_TYPE} ${commoncpp_src} ${commoncpp_inc}) set_library_version(commoncpp) target_link_libraries(commoncpp ucommon ${UCOMMON_LIBS} ${WITH_LIBS} ${SECURE_LIBS}) add_dependencies(commoncpp ucommon) endif() if (BUILD_EXTRAS) add_subdirectory(utils) endif() if (BUILD_TESTING) ENABLE_TESTING() add_subdirectory(test) endif() install(FILES ${pc_files} DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(FILES ${scripts_cfg} DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${scripts_man} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) install(FILES ${cmakes_inc} DESTINATION ${CMAKE_INSTALL_DATADIR}/ucommon/cmake) install(FILES ${ucommon_inc} ${secure_inc} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ucommon) install(FILES ${commoncpp_inc} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/commoncpp) if(BUILD_STDLIB) install(TARGETS commoncpp DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() install(TARGETS ucommon usecure DESTINATION ${CMAKE_INSTALL_LIBDIR}) # Common tarball distribution if(EXISTS ".git/") add_custom_target(dist WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND "${CMAKE_COMMAND}" -E remove -F "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-*.tar.gz" COMMAND git archive -o "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-${VERSION}.tar.gz" --format tar.gz --prefix="${PROJECT_NAME}-${VERSION}/" "v${VERSION}" 2>/dev/null || git archive -o "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-${VERSION}.tar.gz" --format tar.gz --prefix="${PROJECT_NAME}-${VERSION}/" HEAD ) endif() add_cape_make_targets(ucommon ${VERSION}) #add_make_lint_target() add_cape_docs_target(Doxyfile) #add_make_uninstall_target() commoncpp-7.0.1/COPYING000066400000000000000000001043741411242573100145560ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . commoncpp-7.0.1/COPYING.LESSER000066400000000000000000000167271411242573100155560ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. commoncpp-7.0.1/COPYRIGHT000066400000000000000000000011631411242573100150060ustar00rootroot00000000000000This package is collectively known as GNU uCommon C++. This package is collectively licensed using the GNU Lesser General Public License version 3.0 or later. The primary copyright holder was David Sugar and Tycho Softworks, both directly and through copyright assignment. Copyright was assigned to Cherokees of Idaho on March 24, 2015, unless where otherwise explicitly noted. Some specific individual classes in the library may have additional individual copyright holders or copyrighted by the Free Software Foundation. Our preference is that all contributions are copyright assigned to the Free Software Foundation. commoncpp-7.0.1/ChangeLog000066400000000000000000000764501411242573100153000ustar00rootroot00000000000000Changes from 7.0.0 to 7.0.1 - small cmake fixes, improvements for bsd support - stdalign.h not used - supports openssl > 1.0.x - lots of code cleanup for modern distros and compilers - Modernize cmake, add dist target - Spec files cleanup for 7.0.1 - Debian downstream patches added Changes from 6.6.0 to 7.0.0 - clean new library abi 8.0 - atomic typeref system completed, matches tychomt spec - c++11 support completed - deprecated functions and templates removed - deprecated modules (xml, persist) moved to commoncpp Changes from 6.5.7 to 6.6.0 - introduced rsa key support - expanded hmac support - expanded digests for sha256 and 384 - reword of common digest code - improved nullptr clang support - remove clang forced c++11 from build - check for openssl rsa support - port types for 7.0 migration - socket addresses for typeref - further c++11 header fixes - removed old ssl demo app Changes from 6.5.6 to 6.5.7 - improved c++11 support - mapped pointer introduced - fixed is usage - improved mapref remove Changes from 6.5.5 to 6.5.6 - simplified arrayref - added listref - map iterators thru locked instances - type standardization - socket address type Changes from 6.5.4 to 6.5.5 - more portable nullptr support - thread-safe mapref class - some typeref convenience types - bit operations on byterefs Changes from 6.5.3 to 6.5.4 - secure string and key management types - better cleanup of secure objects - file i/o for heap temporary Changes from 6.5.2 to 6.5.3 - arrayref now uses ConditionalAccess, fix for Conditional Changes from 6.5.1 to 6.5.2 - memory management cleanup and mingw32 support for native conditionals - new methodology of having getaddrinfo allocate memory - introduction of queueref and stackref; arrayref becomes useful - typeref concatenation operators Changes from 6.5.0 to 6.5.1 - thread shared references added Changes from 6.4.4 to 6.5.0 - typeref expanded - arrayref introduced - nullptr and other c++ modernizations - clang now defaulted to c++11 - minimum native windows now requires conditionals - mingw has to use win32 pthread support - somewhat more usable heap temporary templates Changes from 6.4.3 to 6.4.4 - additional typeref operators Changes from 6.4.2 to 6.4.3 - fix for broken windows setuid macro Changes from 6.4.1 to 6.4.2 - solaris related cmake fixes - cleanup of test build and osx fixes Changes from 6.4.0 to 6.4.1 - keyfile fixed constructor issue Changes from 6.3.6 to 6.4.0 - new typeref system for immutable atomic reference counted objects - heap management objects support moving heap through assignment - extended unit tests for typeref system - improved openbsd support - atomics enabled by default Changes from 6.3.5 to 6.3.6 - code cleanup - simulate option for scrub - set newline style for cmake genorated files Changes from 6.3.4 to 6.3.5 - general code cleanup - some build fixes Changes from 6.3.3 to 6.3.4 - improved atomics support - configure atomics default matches cmake default - general code cleanup - more casting operations and cast fixups - polymorphic casting support & rtti detection - enclose random value templates in Random - improved rng support Changes from 6.3.2 to 6.3.3 - improved cipher key management - b64 support improved and string hex conversions - simplified digest functions - some solaris fixes Changes from 6.3.1 to 6.3.2 - fixed a broken streambuf for commoncpp - deref cast function added - fixed missing pkg-config Changes from 6.3.0 to 6.3.1 - copyright assignment to Cherokees of Idaho - introduction of ucommon cmake hosted macros - simplified doxygen doc support - convergence of automake and cmake builds - make utils easier for source introspection - converted for cmake builds on debian - count for String::check should be size_t - string bounds checking Changes from 6.2.3 to 6.3.0 - remove legacy cmodel support - modernize library usage - simplify autoconf and cmake - introduce sysruntime... - cleanup memory operators.... Changes from 6.2.2 to 6.2.3 - a few socket fixes, mostly windows related... Changes from 6.2.1 to 6.2.2 - bumped gnutls to 3.0.0 or later... - lots of bug fixes and general cleanup - socket endian issues and other things for ccrtp - templated newp and freep handle management Changes from 6.2.0 to 6.2.1 - datetime: fix const inconsistency - fsys: cached error variable must be mutable - replacment new/delete cannot be declared inline - fix exception specifier clash for c++11 Changes from 6.1.11 to 6.2.0 - standardized cmake paths and stand-alone usages - gnutls support in cmake - unified openssl checks, even works for windows - improved openssl support, new static crypto option - pkgconfig usable in win32, other win32 fixes - fixes for mac build & optional disable of utils - upticked abi version to 7, should have happened with 10/11? Changes from 6.1.10 to 6.1.11 - any addr and overloads in commoncpp - cmake abi fix and other apple specific issues - stream fixes, sflphone recommended changes, and other updates - key protocol added - cleaner build for binding without resolver - cleanup and fixes for commoncpp peering... - UDPSocket: use ucommon::Socket::address - Socket::address: add setAny(sockaddr*), setLoopback(sockaddr*) Changes from 6.1.9 to 6.1.10 - for next release - iso cleaness - Fix memory leak in DateTime ctor - Fix utf8::count() - secure::erase() should be more secure Changes from 6.1.8 to 6.1.9 - ost::Socket: use ucommon::Socket for join(), drop() implementations - back to native threading model for mingw - Socket::store: use existing len method - Socket::address: allow printing to std::ostream - Socket::address: use in_port_t for port numbers - Socket::join, ::drop: allow to set interface index for IPv6 Changes from 6.1.7 to 6.1.8 - mingw libstdc++ c++11 support now requires winpthread - more android related updates Changes from 6.1.6 to 6.1.7 - lots of android related updates Changes from 6.1.5 to 6.1.6 - some windows and mingw fixes - Socket::address::print(): minor fixes - Socket::address: fix constructor documentation - Socket::address: add unit tests for print() - Socket::address: add print() method - Socket::address: add withPort() - Socket::address: add constructors from standard addr types - Socket::address: use existing len() method. Changes from 6.1.4 to 6.1.5 - key merge on load for 6.1.5 Changes from 6.1.3 to 6.1.4 - lots of namespace usage cleanup - Socket::address: add unit tests for new features - Socket::address: add isAny, setAny, isLoopback, setLoopback, any, loopback - Socket::address: convert port to network byte order - ost::Socket: add compatibility with ucommon::Socket::address - we don't want commoncpp configs if no lib made - Socket::address: add equality operator, getPort, setPort, getSize - improved cmake and added srpm, todo make targets Changes from 6.1.2 to 6.1.3 - revised unixaddr buffer overflow issue Changes from 6.1.1 to 6.1.2 - updated contacts, fsf address, and copyright - revised cmake build - added setgroups from ucommon 6.1.0 to 6.1.1 - module flag support for older commoncpp packages - fix for commoncpp pc file - some additional original classes mapped to commoncpp - default Semaphore constructor now valid special case from ucommon 6.0.7 to 6.1.0 - small fixes based on notes from Tristan - exception behavior is changed (fixed) for commoncpp - keywait utility added from ucommon 6.0.6 to 6.0.7 - error state in fsys open fixed - fsys error reset inline added from ucommon 6.0.5 to 6.0.6 - small cleanup of useless validator assignments - fix gnutls casting and warnings - modernized automake support from ucommon 6.0.4 to 6.0.5 - additional constructors to pass pre-allocated memory from ucommon 6.0.3 to 6.0.4 - fix for address list comparison issue from ucommon 6.0.2 to 6.0.3 - fixes for older gnutls releases from ucommon 6.0.1 to 6.0.2 - digest stream operators - auto memory erasing keystring and keyrandom template - common code shared for secure library - some fixes for gnutls support from ucommon 6.0.0 to 6.0.1 - fixes for gnutls support - elimination of gcrypt in gnutls from ucommon 5.5.1 to 6.0.0 - new version 6 api - fixed string + concat operation - made StringPager proper base class by naming conventions - new device access mode and name checking for fsys - fbuf refocused on process pipe and device access - more consistent abi naming conventions - depreciated methods removed - access base classes now consistent with protocols - reorg of datetime classes - allocation and access fault handling from ucommon 5.5.0 to 5.5.1 - regex checks also for lib, mingw support - pedantic cleanup of mingw - anaselli fix for applog and pipes from ucommon 5.4.3 to 5.5.0 - mapof and listof added - semaphore default for commoncpp set to 0 - simplify config, no longer separate stdlib and compat - resolved issues with XOPEN_SOURCE and broken BSD headers - many mingw 32 and 64 bit fixes, build fixes for out of source binary builds from ucommon 5.4.2 to 5.4.3 - fixes for supporting ancient gcc compilers (at least >=2.96!) - bug in Conditional gettimeout, stack and queue suggested by Pollak from ucommon 5.4.1 to 5.4.2 - fixes for older gcc builds and template issues. - bugfix for ConditionalAccess constructor. - bugfix for commoncpp address functions. from ucommon 5.4.0 to 5.4.1 - fixes for windows build. from ucommon 5.3.0 to 5.4.0 - cleanup for ide use. - NamedList sort uses system collation. - some convenience string methods added. - search and replace, regular expression support. - UString extended with copy/cut/paste/left/right operations. - stringpager extended with set/replace method and split. - added fsys::pipe and fsys::noexec. - removed unused pipeio subsystem. from ucommon 5.2.2 to 5.3.0 - sort specific string collation functions added - more stringpager manipulations possible - use of stringlist_t for new fsys exec. - string inpuit and output for bufpager. from ucommon 5.2.1 to 5.2.2 - use strcoll for sorting when possible - common c++ object linking, maps, and ref counted pointers added back - stringpager supports ordered add and sorting - directory pager and list type added - no -L or -I paths in default installs (multi-arch issue) from ucommon 5.2.0 to 5.2.1 - fixed issue with static linking initialization order - shell release method from ucommon 5.1.2 to 5.2.0 - improved shell::detach support and new pdetach utility - fsys generic basic file operations - commoncpp file and dso compatibility support added from ucommon 5.1.1 to 5.1.2 - corrected copyright. since cc libs were moved to bayonne and commoncpp had been added, ALL of ucommon (including commoncpp2) are L-GPL, not just the "core" library. - more standardized manpages from ucommon 5.1.0 to 5.1.1 - better handling of strerror_r support. from ucommon 5.0.7 to 5.1.0 - Pollak's suggestion for peek method for queue added to queue, stack, buffer, and templates. - new stringpager class to hold simple expanding tables of strings. - commoncpp strerror_r fix from list. from ucommon 5.0.6 to 5.0.7 - use debian move xopen forward patch - joinable thread self-join does cleanup of run state from ucommon 5.0.5 to 5.0.6 - generic object save/auto-restore. - separation of shell::error() from shell::errexit(0,...) - separation of runtime and non-runtime libs - disable posix_fadvise if header definitions missing (debian kfreebsd bug) from ucommon 5.0.4 to 5.0.5 - fix for commoncpp emulation when no direct parent commoncpp thread. - rename scrub to scrub files to avoid name conflict. - some enhacement in cmake from ucommon 5.0.3 to 5.0.4 - set without explicit this in templates conflicts with std inherited classes. from ucommon 5.0.2 to 5.0.3 - specialization to use linked_pointer to walk address lists. - fix for cmake build of car. - sockaddr util added to show address resolution lists. from ucommon 5.0.1 to 5.0.2 - fix for termios support. - shell getpass and inkey methods. - extended cipher key management methods. - crytographic archiver (car) added. - openssl fips support added. from ucommon 5.0.0 to 5.0.1 - missing commoncpp/numbers.h header. from ucommon 4.3.3 to 5.0.0 - thread objects fully inheritable. from ucommon 4.3.2 to 4.3.3 - service control path added for dropfile info. - generics dup template added. from ucommon 4.3.1 to 4.3.2 - cmake unit tests added and automated. - extensions to mapping, copy and mapped_view get. - certificate paths now part of usecure. - sorting and named list issues resolved. from ucommon 4.3.0 to 4.3.1 - fix for access to keyfile::create(). - new -xxx and +xxx numeric parser option. from ucommon 4.2.2 to 4.3.0 - shell::path added. - fsys for descriptor. - keyfile extended. - symlink handling in fsys. from ucommon 4.2.1 to 4.2.2 - reorg how we do cmake path configurations. from ucommon 4.2.0 to 4.2.1 - proposed barrier dec from Leon. - added fsys::islink symlink check function. - keyfile::save method added, registry interfaces. from ucommon 4.1.7 to 4.2.0 - some clarification of linked object abi. from ucommon 4.1.6 to 4.1.7 - small fixes in cmake to add includes to projects, etc. from ucommon 4.1.5 to 4.1.6 - fixed permission of shared memory, now world readable if not umasked. from ucommon 4.1.4 to 4.1.5 - posix timers have become experimental since seems broken on some platforms from ucommon 4.1.3 to 4.1.4 - revised cmake for unix builds, fixed cmake bug with non-stdlib from ucommon 4.1.2 to 4.1.3 - new check for posix timing and monotomic clocking - thread unit test expanded to verify timed operations from ucommon 4.1.1 to 4.1.2 - configuration clearification for posix timers - linkage fix for secure and sstream; no copy constructor from ucommon 4.1.0 to 4.1.1 - rexlock try method and better thread inheritence - timer fix for dll linkage, again broken windows - thread specific storage - fixes for cmake builds with openssl and intl support - mingw32, windows header and openssl link issues from ucommon 4.0.5 to 4.1.0 - security system logging. - cleanup of cmake. - clearer idea of what shell::errexit is. - cleanup of pointer templates, Object pointers now object_pointer, temporary is now temporary object, new "generic" smart pointer to be added. - new containers.h to seperate use of contained resources from thread.h and basic threading primitives. - linked_allocator template added for easy access to a free list managed object pool. from ucommon 4.0.4 to 4.0.5 - smarter openssl search. - simplified service handling. - exiting critical handler added. from ucommon 4.0.3 to 4.0.4 - make it easier to subclass cipher key for special purposes. - component naming of binaries for combining ucommon with other subprojects. from ucommon 4.0.2 to 4.0.3 - some changes in file stat macros. from ucommon 4.0.1 to 4.0.2 - introduction of scrub utility for secure file deletion. - introduction of mdsub utility for computing file hashes. - shell::printf always flushes output for console. - Digest::reset now resets even for cleared contexts. from ucommon 4.0.0 to 4.0.1 - fix for misnamed library in ucommon-config. from ucommon 3.4.0 to 4.0.0 - introduction of protocols as abstract bases for mixin classes. - Socket class tracks last error and has iowait/blocking property. - Socket int methods return errno() rather than -1 on error. - buffer protocol created. - string no longer has dependency on socket. - ssl and tcp classes reorganized for consistent naming. - file handling in charfile through character protocol. - unicode conversions use character protocol. - templates updated so []'s always emit value references. from ucommon 3.3.7 to 3.4.0 - simplified to better focus on core runtime mission. - packaging simplified. - ccscript moved to bayonne - ccaudio detached from ucommon 3.3.6 to 3.3.7 - small change in how ucommon components can be pre-set. - missing local header for gnutls. from ucommon 3.3.5 to 3.3.6 - grouping operator for usage help. - script merge operation by images. - doxygen generation now supported from cmake, from Angelo Naselli. from ucommon 3.3.4 to 3.3.5 - make sure gettext is actually buildable before we build with it. from ucommon 3.3.3 to 3.3.4 - broken sym lookup fixed. from ucommon 3.3.2 to 3.3.3 - process detach and restart handling. - more complete string to numeric conversions. - syms were not initialized in all shell constructors. - some inline templates that contain generic values redone as typename. from ucommon 3.3.1 to 3.3.2 - shell debug message logging output. - restart method to hook debuggers. - local thread-safe symbol space. from ucommon 3.3.0 to 3.3.1 - expand args to directory and recursive operations. - fix cstring initialization. - set methods to initialize shell options. - basic logging added. from ucommon 3.2.2 to 3.3.0 - internationalization bindings with gnu gettext support. - use shell parser in audiotool code. - small fixes in shell option parsing. from ucommon 3.2.1 to 3.2.2 - xml parser for buffered i/o objects and files. - bidirectional socket descriptor to FILE. - OrderedIndex reset method. - numeric format conversion and scanning operator "%". from ucommon 3.2.0 to 3.2.1 - splitting shell parser so that it is possible to create tool style parsers. - string hexpack and hexdump functions. - traditional, random, and digest uuid functions. - make sure we always ignore pthread/pth if msw targets (fedora mingw32). - barrier patch from Leon Pollak. from ucommon 3.1.2 to 3.2.0 - added explicit add and remove for NamedObject to make keymap easier to use. - created new keypager type to allocate named objects on demand. - fixed option crash when not defining a long option. - improved shell header documentation. - shell spawn and process management functions. - shell io for buffered pipes and stdio handling. from ucommon 3.1.1 to 3.1.2 - some attention to the question of padding cipher blocks. - gnutls can now also be used in place of openssl. - make sure all keys are destroyed cleanly when secure objects are released. from ucommon 3.1.0 to 3.1.1 - some attention to the shell functions. from ucommon 3.0.6 to 3.1.0 - encapuslate select() bit mask operations into select class. - new read/write based stream methods. - socket cannot be private in TCPSocket. - fixed doxygen generated docs, now much more complete. - introduced new secure library for ssl sockets, digests, ciphers, etc. from ucommon 3.0.5 to 3.0.6 - optional socks proxy support possible with --enable-socks configure flag. - new Socket methods to wrap more socket functionality and new init method. from ucommon 3.0.4 to 3.0.5 - new socket option for nodelay. - copyright notices fixed for consistency. - fix for conflict between stream and macros. from ucommon 3.0.3 to 3.0.4 - buffer purge method added. - new flush io buffer virtual method. - buffering support and tcp socket for non-blocking i/o. from ucommon 3.0.2 to 3.0.3 - new biderectional buffered i/o support added. - new buffered file and buffered tcp socket classes added. - bug in ReusableAllocator freelist assignment. - creation of connected sockets. - standardized host and service name resolution. from ucommon 3.0.1 to 3.0.2 - atomic counter and lock class added. - shell no longer a second class member of ucommon. - unit tests conditional by component selection. - audio::init for static linkage issues. - fsys::trunc method added. - unicode utf8 file character operations. from ucommon 3.0.0 to 3.0.1 - bug fix and unit test for queueof. - initialization template function added. - small cmake fixes. - refinement of stackof and queueof templates. From ucommon 2.1.4 to 3.0.0 - merged ccscript and ccaudio into ucommon core framework. - extended configuration support for includes and plugins. - expanded configure for framework component selection. From ucommon 2.1.3 to 2.1.4 - new utf8_pointer string class and further unicode support. - new component access api for datetime objects. - New object containers for object lists, fifo's, and queues. From ucommon 2.1.2 to 2.1.3 - unicode string support and utf8 string processing. From ucommon 2.1.1 to 2.1.2 - set() methods for date, time, and datetime added. - new defines for buffer sizes added. - new date and time related auto string classes. - fixups for netbsd and openbsd. From ucommon 2.1.0 to 2.1.1 - fix for Time string conversion - size fields for date and time strings. From ucommon 2.0.8 to 2.1.0 - new abi for fsys seek and drop - Added NamedTree/treemap copy constructor and changed id behavior - Improved cmake support using proper build options and adding cpack - Common use of "eq()" inlines for string and other data types - fix for lseek (also patched in 2.0.9) - all int fsys functions now return errno on failure, not -1 - Common C++ number string manip classes - greater use of const in abi - datetime class support added - timer class expanded for operators - fix for generated docs From ucommon 2.0.7 to 2.0.8 - support for optional cmake based build system being added From ucommon 2.0.6 to 2.0.7 - strict aliasing, socket address manipulations, and gcc 4.4 - doc generation cleanup From ucommon 2.0.5 to 2.0.6 - spec file updated per redhat/fedora packaging policies - fixed install scripts handling - added man page for ucommon-config. From ucommon 2.0.4 to 2.0.5 - small code cleanup. - added fsync to fsys as fsys::sync() method. - added missing destructors for queue and stack when no mempager is used. From ucommon 2.0.3 to 2.0.4 - fixed bug in reusable object handoff to free list. - basic dccp socket support added. From ucommon 2.0.2 to 2.0.3 - documented behavior and use case for ...Thread::exit() methods changed. From ucommon 2.0.1 to 2.0.2 - fix for missing functions in mingw32 cross-builds. From ucommon 2.0.0 to 2.0.1 - fix for failed dlopen detection in lc and false libcompat check for netbsd - general code cleanup with pedantic, some subtle header changes - fix for generic interface routing in ipv6 multicast operations - improved sunwpro support for --disable-stdcpp by using no%Cstd and CXX model From ucommon 1.9.9 to 2.0.0 - fsys stream and random access modes with posix_fadvise support. - new fsys drop method to drop used pages in streaming applications. - license changes to lgplv3+ - mempager/memalloc "zalloc" method added. - keyfile based on memalloc, not mempager. From ucommon 1.9.8 to 1.9.9 - critical fix for assignment template for auto pointers. From ucommon 1.9.7 to 1.9.8 - new NamedTree listing methods for moving and re-ordering tree branches. - getIndexed methods for accessing a linked list by index. - some clarification of internet socket address types. - smart pointer can be initially assigned NULL... - new memalloc because I needed a mempager without mutexes... From ucommon 1.9.6 to 1.9.7 - lots of code cleanup for final release candidate for 2.0. From ucommon 1.9.5 to 1.9.6 - better address list management, including unique insert and remove. - copy constructor and address duplication for Socket::address. - fixup of reader/writer pool locking and addition of gaurd objects. - hopefully final core api for real 2.0 release! From ucommon 1.9.4 to 1.9.5 - mutex::gaurd for scope mutex locking arbitrary objects. - read/write locking access control for arbitrary objects. - multi-distro spec file. - simplified abi numbering. From ucommon 1.9.3 to 1.9.4 - string equality tests. - Socket isNull/isNumeric can parse inside a field... - container policies for cidr's - behavior of ID reset for named objects can now be overriden by virtual. - string format conversion base class for use in string classes and operators. From ucommon 1.9.2 to 1.9.3 - fixed join/drop issue in multicast reported by Michael Freedman. - module loader error handling. From ucommon 1.9.1 to 1.9.2 - added Socket::isNull and Socket::isNumeric checks. - added keyhost hash key indexing on host only. - fixed uninitialized getsockname len argument in gethint. - updated spec file. From ucommon 1.9.0 to 1.9.1 - bug in string::token parsing fixed. - unit test to validate string::token fix. - keyfile/keydata classes added for generic config file parsing. - unit test added for keydata processing. From ucommon 1.8.2 to 1.9.0 - pipestream interface normalized for shell execution. - new "shell" class for generic parsing and argument expansion. - v4mapped() added to enable/disable ipv4 to ipv6 mapping support. - fsys::isfile/isdir added. - some rework of timer events to better support updating in arm & disarm. From ucommon 1.8.1 to 1.8.2 - doxygen updates. - fix related to libstdc++/ansi c++ library design defect. From ucommon 1.8.0 to 1.8.1 - use entirely safe string operations everywhere. - keyassoc keydata constructor changed to pass size of string buffer. - basic optional GNU pth support completed. From ucommon 1.7.2 to 1.8.0 - support for forced ipv4/ipv6 in init. ipv6 unit testing. - new family method for query default. - further refinement of socket api. - ipv6 support for opensolaris and -lnsl. From ucommon 1.7.1 to 1.7.2 - small fix in type mismatch in stream allocate methods. - do not remap undefined error codes, as can break switch blocks. - fix for mingw32 address conversion functions. From ucommon 1.7.0 to 1.7.1 - extended errno mapping for sockets. From ucommon 1.6.2 to 1.7.0 - updated abi for fsys, rebuilt to unify file handling and to use a common type and functions for files, directory access, and loader. - simplified TimedEvent completion port handling and new static members. - refactored socket api around supporting use of native socket_t. Minimal api for abstract socket class used for protocol building. - refactored containers to use references in assignment to avoid stack frame constructions. - added stream classes for fsys (threaded i/o) and piping. From ucommon 1.6.1 to 1.6.2 - improved support for using Socket::address as referenced type. New set & add methods. From ucommon 1.6.0 to 1.6.1 - fix for loader. - simplified fsys r/w calls. - fsys.h documented. From ucommon 1.5.0 to 1.6.0 - some small cleanups for opensolaris builds. - additional is() and isnull() template operators, template swap. - automatic rules for default selection with/without ansi C++ library (see BUILDS). - new fsys wrapper class for threaded portable i/o operations. - cmodel.sh support for broken libtool versions. - lots of tcpstream/socket bug fixes and new tcpstream unit test added. - changes in tcpstream abi to use address objects by reference. - dynamic loader support added. From ucommon 1.4.2 to 1.5.0 - added gnu common c++ based tcp streaming class to ucommon. - added gnu common c++ based xml sax parser to ucommon with better support for parsing embedded xml data structures. - Daniel Silverstone's persistence engine from gnu common c++ added. From ucommon 1.4.1 to 1.4.2 - get address entry by family from list. - MultiMap/multimap multiply pathed lists/associated key objects. - remove complex automake rules; use new cmodel.sh to reset libtool when building pure c mode link for c++ objects for deep embedding without libstdc++. - changes to support QNX target builds. From ucommon 1.4.0 to 1.4.1 - internalized getaddrinfo substituted on targets without addrinfo support. - small correction to socket::address::add to pass socket type. - cygwin support - fixups for Solaris support From ucommon 1.3.3 to 1.4.0 - socket::address constructors reorganized - added mapped (shared memory) to ucommon library - improved mingw32 support - support for gcc < 3.0 (gcc 2.96, rhel-2.1 for example) - socket initialization for msw. From ucommon 1.3.2 to 1.3.3 - initialization of socket hinting for BSD stack. - further clarify asserts. - fixes for NetBSD 4; clock_nanosleep and pthread_setconcurrency support. - fixes for gcc < 3.4 (such as openbsd...) - fixes for embedded linux kernel targets From ucommon 1.3.1 to 1.3.2 - clarified assertions for argument preconditions for correctness. From ucommon 1.3.0 to 1.3.1 - many testing asserts added to library for function argument preconditions. From ucommon 1.2.5 to 1.3.0 - dynamic mutex resource locking, with new interface and supporting templates to automate operation. This allows one to create exclusive access regions on demand without having to embed initialized mutexes in each instance of an object that requires serialization protection. From ucommon 1.2.4 to 1.2.5 - restore sharing level at ConditionalLock commit if recursive locked. From ucommon 1.2.3 to 1.2.4 - default initialization of socket address list to NULL required. From ucommon 1.2.2 to 1.2.3 - small change in use of sched.h for portability. - unitialized mempager and reorg treemap purge. From ucommon 1.2.1 to 1.2.2 - typo in exclusive conditional lock. From ucommon 1.2.0 to 1.2.1 - conditional modify access can be asserted during active recursive share. From ucommon 1.1.1 to 1.2.0 - adding conditional policies, ConditionalLock::concurrency() and ConditionalRW::sharing(). - Recursive support in conditional locking. - SharedPointer derived from ConditionalRW and optimized. From ucommon 1.1.1 to 1.1.2 - fix for OS/X. From ucommon 1.1.0 to 1.1.1 - adjusted definition of priority scheduling and added realtime thread policies. From ucommon 1.0.0 to 1.1.0 - fixed spec file to support uses_stdcpp definition. - fixed new operator when using stdcpp. - conditionalrw locking scheme integrated for scheduling optimization. From ucommon 0.9.2 to 1.0.0 - use std::runtime_exception instead of abort when using c++ runtime library - crit macro allows std::runtime_exception processing for c++ runtime library - check for old and new style c++ stream i/o classes, added OLD_STDCPP - replaced NOSTDCPP with reversed & revised NEW_STDCPP flag unless OLD_STDCPP - classes documented and doxygenized. - expanded linked list support with head/tail and insert options. - barrier with timed wait. From ucommon 0.9.1 to 0.9.2 - fix critical bug in Socket::equal tests... From ucommon 0.9.0 to 0.9.1 - removed AutoObject - migrated thread functions to use pure win32 threading for mingw32; no more redhat pthread-win32. This became possible when we dropped cancellable threads. - fixed cc mode library build because libtool still forces libstdc++! From ucommon 0.8.2 to 0.9.0 - slight change to thread init for pthread-win32 static libs. - new steplock formed purely from staircase mutexes. - new event timer for timed completion event signalling. - removed cancellable thread concepts to simplify thread model! From ucommon 0.8.1 to 0.8.2 - conditional lock protect for shared recursive/short lock use. From ucommon 0.8.0 to 0.8.1 - fix for pthread without setschedprio. From ucommon 0.7.0 to 0.8.0 - fix for timerqueue class. - potential writer starvation issues resolved in rwlock/condlock classes. - consolidated and improved Conditional timed waits. - introduction of transformable conditional locking. - access shared locking extended to cover transformable conditional locks. - default compile mode is now stdcpp; first step in gnu common c++ merge. From ucommon 0.6.1 to 0.7.0 - added basic thread priority support - changed base configure options to avoid collisions with other packages - added getservice interface to get socket port # - added charbuf template - cidr policy chains simplified - some rationalization and improvement in socket class with the ability to compare addresses, manipulate address lists, etc. - string finding with deliminators. - first pass at offering real documentation for the library via doxygen. From ucommon 0.6.0 to 0.6.1 - support for static libpthreadGC2 - support for w32 address conversion From ucommon 0.5.0 to 0.6.0 - detached & pooled thread exit support fixed - equal test for socket address - getinterface to find interface to destination address - subnet test for socket address comparison - getaddress replaces hosttostr From ucommon 0.4.0 to 0.5.0 - rwlock now also recursive writers - clarification of conditional locking - generic rexlock type replaces recursive mutex Initial Release 0.4.0 commoncpp-7.0.1/Doxyfile.in000066400000000000000000000037131411242573100156310ustar00rootroot00000000000000# Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015-2020 Cherokees of Idaho. PROJECT_NAME = "UCommon" OUTPUT_DIRECTORY = doc OUTPUT_LANGUAGE = English FULL_PATH_NAMES = YES STRIP_FROM_PATH = inc SHORT_NAMES = YES TAB_SIZE = 4 INPUT = @CMAKE_CURRENT_SOURCE_DIR@/inc/ucommon @CMAKE_CURRENT_SOURCE_DIR@/inc/commoncpp EXAMPLE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/test FILE_PATTERNS = *.h RECURSIVE = NO ALIASES = "license=\par License:\n" JAVADOC_AUTOBRIEF = YES OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO HIDE_UNDOC_CLASSES = YES HIDE_UNDOC_MEMBERS = NO CASE_SENSE_NAMES = NO SHOW_INCLUDE_FILES = YES SORT_BY_SCOPE_NAME = YES SORT_GROUP_NAMES = YES SORT_BRIEF_DOCS = YES SORT_MEMBER_DOCS = YES SEARCH_INCLUDES = YES INCLUDE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/inc /usr/include /usr/local/include GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST = YES MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 GENERATE_HTML = YES GENERATE_HTMLHELP = YES GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 256 GENERATE_LATEX = YES COMPACT_LATEX = YES PDF_HYPERLINKS = YES USE_PDFLATEX = NO LATEX_BATCHMODE = YES LATEX_HIDE_INDICES = NO GENERATE_RTF = NO COMPACT_RTF = NO RTF_HYPERLINKS = NO GENERATE_MAN = NO GENERATE_XML = NO GENERATE_PERLMOD = NO ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES PREDEFINED = AF_INET6 NEW_STDCPP CLASS_DIAGRAMS = YES COLLABORATION_GRAPH = YES HIDE_UNDOC_RELATIONS = NO HAVE_DOT = YES CLASS_GRAPH = YES INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = YES SOURCE_BROWSER = YES GRAPHICAL_HIERARCHY = YES DOT_IMAGE_FORMAT = svg DOT_TRANSPARENT = YES # MAX_DOT_GRAPH_WIDTH = 1024 # MAX_DOT_GRAPH_HEIGHT = 1024 TEMPLATE_RELATIONS = NO GENERATE_LEGEND = YES SEARCHENGINE = NO WARN_IF_UNDOCUMENTED = NO commoncpp-7.0.1/Makefile.am000066400000000000000000000037701411242573100155550ustar00rootroot00000000000000# Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015-2020 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. ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = autogen.sh README* *.pc.in *.spec.in *.spec *-config.in \ *-config.1 Doxyfile.in BUILDS SUPPORT COPYING* COPYRIGHT CMakeLists.txt \ cmake-abi.sh ucommon-config.h.cmake directive.in cmake/*.cmake DIST_SUBDIRS = corelib commoncpp openssl gnutls nossl utils inc test SUBDIRS = corelib @SECURE@ @COMPAT@ inc test if BUILD_UTILS SUBDIRS += utils endif EXTRA_SCRIPTS = commoncpp-config pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = ucommon.pc @COMPAT_PC@ scriptdir = $(bindir) script_SCRIPTS = ucommon-config @COMPAT_CONFIG@ cmakedir = $(datadir)/ucommon/cmake cmake_DATA = cmake/CapeConfig.cmake cmake/CapeMakeTargets.cmake man_MANS = ucommon-config.1 commoncpp-config.1 .phony: doxy todo lint todo: @grep --color=tty --exclude="Makefile*" --exclude-dir=.git -nrEI "/[*] TODO|/[*] FIXME|// TODO|// FIXME" . doxy: -rm -rf doc $(DOXYGEN) Doxyfile srpm: dist rm -f *.rpm rpmbuild -bs --nodeps --define "_sourcedir ." --define "_srcrpmdir ." --sign ucommon.spec deb: dist rm -f *.deb *.debian.tar.gz *.dsc *.changes cape-source --sign ucommon-${VERSION}.tar.gz . lint: cppcheck --force -q . clean-local: -rm -rf doc dist-hook: cleandist cleandist: @rm -f ${PACKAGE}-[0-9]*.tar.gz @rm -f ${PACKAGE}-[0-9]*.tar.xz @rm -f ${PACKAGE}-[0-9]*.tar.bz2 @rm -f ${PACKAGE}-[0-9]*.shar.gz @rm -f ${PACKAGE}-[0-9]*.zip @rm -f *${PACKAGE}*.rpm @rm -f *${PACKAGE}*.deb @rm -f ${PACKAGE}_*.xz @rm -f ${PACKAGE}_*.gz @rm -f ${PACKAGE}_*.dsc @rm -f *.changes commoncpp-7.0.1/NEWS000066400000000000000000000033421411242573100142130ustar00rootroot00000000000000uCommon Library NEWS -- history of visible user changes. Updated 2008-04-15. uCommon C++ 0.4 codebase completed and ready for release with the introduction of the GNU GPL V3. This is a complete rewrite of UCommon as a C++ library for threading and design patterns suitable for deeply embedded targets. uCommon C++ 0.7 codebase now has core documentation and basic library theory in header files. This documentation can be generated with doxygen or by using "make doxy". uCommon C++ 1.0 release has been simplified, fully documented, and modified in specific ways to simplify the migration and merge with GNU Common C++ to form GNU Common C++ 2.0. uCommon C++ 1.5 release begins the process of migrating GNU Common C++ into the core GNU uCommon C++ codebase. Some GNU Common C++ classes, including tcp streaming, xml parser, and persist, have been revised and integrated for the 1.5.0 release itself. Other GNU Common C++ classes will be integrated as requested and needed. The 1.5/1.x series will actually be the last UCommon release sets, as GNU uCommon C++ 2.0 will instead be released as GNU Common C++ 2 2.0. uCommon C++ 2.0 released under the GNU Lesser General Public License, Version 3 or later. uCommon C++ 2.1 is considered a refactored abi release offering greater clarity, consistency of use, and additional features that were migrated from Common C++. The 2.1 release series may continue to introduce additional classes. ucommon 3.0 merges other ucommon related libraries to create a single ucommon framework for application development. ucommon 3.1 introduced the ucommon secure framework with support for ssl sockets, random number generation, ciphering, and digest computation. Further cryptographic features will be added over time. commoncpp-7.0.1/README000066400000000000000000000120321411242573100143700ustar00rootroot00000000000000GNU uCommon C++ is meant as a very light-weight C++ 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. GNU uCommon C++ 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. GNU uCommon C++ 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. GNU uCommon C++ 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. While GNU uCommon C++ has been influenced by GNU Common C++, it introduces some new concepts for handling of thread locking and synchronization. GNU uCommon C++ also 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. GNU uCommon C++ 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. GNU uCommon C++ may also be built with GCC cross compiling for mingw32 to build Microsoft Windows targets natively. The cmake build system can also be used, to create project files for various platforms including xcode for OS/X and various Microsoft Visual Studio project file formats. The minimum platform support for uCommon is a modern and working posix pthread threading library. I 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. I also eliminate the practice and dependency on pthread automatic cancellation behavior, which otherwise introduces much greater complexity to user applications and can often lead to defective coding practices. The first three releases of uCommon were introduced in 1999-2000 as a pure "C" library for embedded targets, and had not seen an update in 7 years. Hence I have had the package name in use for a very long time. Work on what became uCommon C++ 0.4 was originally intended as a refactoring effort for GNU Common C++ to better support IPV6, and became something different as entirely new code was written in 2006. I originally hoped to release GNU uCommon C++ in March of 2007 as a new package under the GNU GPL V3, but the license was unavoidably delayed. GNU uCommon C++ will merge code from and replace GNU Common C++ in future releases. GNU uCommon C++ is a linkable library distributed under the GNU General Public License, Version 3 or later. As of version 2.0, we are now using the GNU Lesser General Public License, Version 3 or later, to remain consistent and compatible with past GNU Common C++ licensing. A new release series of GNU uCommon C++ is 2.1 involved refactoring the abi release from prior 2.0.x releases, offering greater clarity, consistency of use, and some new features that were migrated from Common C++. To better focus on standardizing secure and runtime services, uCommon was somewhat simplified in release 3.4. Current work has been focused on better integration with C++11 standards. commoncpp-7.0.1/README.secure000066400000000000000000000024461411242573100156650ustar00rootroot00000000000000The GNU uCommon C++ secure library component (and the core GNU uCommon C++ library) is licensed under the GNU Lesser General Public License 3.0 or later. It is generally believed that openssl can be linked with GNU L-GPL licensed software, and with GNU GPL licensed software as well, when appearing as a "default system library" on a target platform. However, we generally recommend using the GNU tls (gnutls) library build of the GNU uCommon C++ secure library component rather than openssl unless gnutls is not available for your target platform of choice. We strive to maintain feature parity between the gnutls and openssl crypto implementations. We may also add nss as a secure backend in the future. Programming to the GNU uCommon C++ secure api is intended to avoid the need entirely of using openssl, gnutls, or other library specific functions. This means the total size of the secure library will grow as we add additional common features, such as pki support. In the past as there has been no generally agreed upon crypto library, so developers building new apps would use a library they already know, or that is best optimized for the platform they are using. Our goal is to remove this complexity of supporting different crypto libraries by offering a single API for secure application development. commoncpp-7.0.1/SUPPORT000066400000000000000000000006631411242573100146160ustar00rootroot00000000000000uCommon 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://savannah.gnu.org/projects/gnucomm https://www.gitlab.com/dyfet/ucommon Mailing lists and email contacts: tychosoft@gmail.com http://lists.gnu.org/mailman/listinfo/bug-commoncpp Other contacts jabber:dyfet@jabber.org irc:tychosoft@freenode.net commoncpp-7.0.1/TODO000066400000000000000000000045351411242573100142110ustar00rootroot00000000000000Proposed changes for 6.1.0: srvaddress type portable shell::pass to get pins with *'s siot merged into ucommon for serial device support. fsys.cpp & file.cpp split into part that truly requires _XOPEN_SOURCE >= 600 and rest FetchProtocol for string >> operator? Use NSPR as an alternate thread runtime base like we do with GNU pth... Especially convenient with common use of NSS for future tls. Do we still keep GNU pth option if we do this? Use NSPR code base for simulating msw conditional variables for direct native msw threading if better than code we have in ucommon, or maybe use NSPR in place of native msw threading entirely? Add NSS backend for secure alongside openssl & gnutls. SSLBuffer does not do validation and peer methods missing. We should load all ca certificates rather than depend on using a directory path for using multiple CA's because the latter depends on hash mapped directories for openssl and may not exist as a feature in gnutls. Should we have a new generic ca archive format and ca management tool? Certificate paths should be exposed and changable. Base-name of certificate service should be changable. PKI related functions in secure library. shell parser support for +options, auto collating of short options to remove duplicates. unicode shell options? Rejected changes: DetachedThread delete this into dealloc() virtual... - use Thread::exit() virtual for this purpose instead in script engine make expression operands virtuals or expression operation itself virtual. - ccscript moved into bayonne, no longer needed if there, either. changed new operators confined to namespace for include file issues with std lib - build and compile issues if not global ssl socket low level methods and bio rather than just upper level stream. Add serialio and logging class? - rejected; in siot Redu and split ucommon.pc and usecure.pc. This is to get cleaner linkages in derived projects. Also or alternately change ucommon-config to have a with & without secure mode. - for now added minimal linking move spawn/proc stuff from shell into new proc::, move fsys:: inherited redirect methods and pipe into proc. This is to clean up static linking uses and interdependence of some things. Maybe also proc::release and detach from shell... ?? separate enhanced string format and numbers library commoncpp-7.0.1/autogen.sh000077500000000000000000000051341411242573100155160ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015-2020 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. WANT_AUTOCONF_2_5=1 export WANT_AUTOCONF_2_5 rm -rf autoconf auto*.cache libtool if test ! -d autoconf ; then mkdir autoconf ; fi libtoolize="libtoolize" for lt in glibtoolize libtoolize15 libtoolize14 libtoolize13 ; do if test -x /usr/bin/$lt ; then libtoolize=$lt ; break fi if test -x /usr/local/bin/$lt ; then libtoolize=$lt ; break fi if test -x /opt/local/bin/$lt ; then libtoolize=$lt ; break fi done $libtoolize --copy --force AUTOMAKE_FLAGS="" case $libtoolize in *glibtoolize) AUTOMAKE_FLAGS="-i" ;; esac ACLOCALDIRS="" if test -d m4 ; then ACLOCALDIRS="-I m4" ; fi if test ! -z "$ACLOCAL" ; then ACLOCALDIRS="$ACLOCALDIRS "${ACLOCAL} elif test ! -z "$ACLOCAL_FLAGS" ; then ACLOCALDIRS="$ACLOCALDIRS $ACLOCAL_FLAGS" ; fi reconf="" if test -f ~/.configure ; then reconf=`grep ^reconfig: ~/.configure | sed -e s/^reconfig://` elif test -f /etc/configure.conf ; then reconf=`grep ^reconfig: /etc/configure.conf | sed -e s/^reconfig://` ; fi if test ! -z "$reconf" ; then ACLOCALDIRS="$ACLOCALDIRS $reconf" ; fi if [ -d ~/share/aclocal ] ; then ACLOCALDIRS="$ACLOCALDIRS -I ~/share/aclocal" elif [ -d /usr/local/share/aclocal ] ; then ACLOCALDIRS="$ACLOCALDIRS -I /usr/local/share/aclocal" fi if test ! -z "$1" -o ! -z "${AUTOCONF_SUFFIX}" ; then ver="$1" else for v in 2.53 2.57 ; do if test -f /usr/bin/autoconf-$v ; then ver=$v fi done fi if test "$ver" = "2.53" -a -z "$AUTOMAKE_SUFFIX" ; then if test -f /usr/bin/automake-1.5 ; then AUTOMAKE_SUFFIX="-1.5" fi fi aclocal${AUTOMAKE_SUFFIX} $ACLOCALDIRS if test -f /usr/bin/autoheader-$ver ; then /usr/bin/autoheader-$ver else autoheader${AUTOCONF_SUFFIX} fi automake${AUTOMAKE_SUFFIX} --add-missing --copy ${AUTOMAKE_FLAGS} if test -f /usr/bin/autoconf-$ver ; then /usr/bin/autoconf-$ver else autoconf${AUTOCONF_SUFFIX} fi rm -f config.cache # fix for some broken... if test -f /usr/bin/automake-1.4 ; then if test -f ltmain.sh ; then cp ltmain.sh autoconf/ltmain.sh fi fi commoncpp-7.0.1/cmake-abi.sh000077500000000000000000000015751411242573100156720ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2013-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015-2020 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 commoncpp-7.0.1/cmake/000077500000000000000000000000001411242573100145725ustar00rootroot00000000000000commoncpp-7.0.1/cmake/CapeConfig.cmake000066400000000000000000000175011411242573100175760ustar00rootroot00000000000000#.rst: # CapeConfig # --------------- #============================================================================= # Copyright (C) 2015-2020 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. #============================================================================= include(GNUInstallDirs) include(CheckFunctionExists) include(CheckIncludeFiles) macro(check_functions) foreach(arg ${ARGN}) string(TOUPPER "${arg}" _fn) set(_fn "HAVE_${_fn}") check_function_exists(${arg} ${_fn}) endforeach() endmacro() macro(check_headers) foreach(arg ${ARGN}) string(TOUPPER "${arg}" _hdr) string(REGEX REPLACE "/" "_" _hdr ${_hdr}) string(REGEX REPLACE "[.]" "_" _hdr ${_hdr}) set(_hdr "HAVE_${_hdr}") check_include_files(${arg} ${_hdr}) endforeach() endmacro() macro(target_setuid_properties) if(UNIX) if(CMAKE_COMPILER_IS_GNUCXX AND NOT CMAKE_COMPILE_SETUID_FLAGS) set(CMAKE_COMPILE_SETUID_FLAGS "-O2 -fPIE -fstack-protector -D_FORTIFY_SOURCE=2 --param ssp-buffer-size=4 -pie") if(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") set(CMAKE_LINK_SETUID_FLAGS "-pie") else() set(CMAKE_LINK_SETUID_FLAGS "-pie -z relro -z now") endif() endif() foreach(arg ${ARGN}) set_target_properties(${arg} PROPERTIES COMPILE_FLAGS "${CMAKE_COMPILE_SETUID_FLAGS}" LINK_FLAGS "${CMAKE_LINK_SETUID_FLAGS}" POSITION_INDEPENDENT_CODE TRUE ) endforeach() endif() endmacro() function(set_library_version _LIBRARY) set(_VERSION "${ARGN}") set(_SOVERSION "-") if(UNIX AND "${_VERSION}" STREQUAL "" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake-abi.sh") execute_process(WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND "./cmake-abi.sh" OUTPUT_VARIABLE _VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) endif() if(NOT UNIX OR "${_VERSION}" STREQUAL "") set(_VERSION "${VERSION}") endif() STRING(REGEX REPLACE "[.].*$" "" _SOVERSION ${_VERSION}) if(ABI_MAJORONLY) set(_VERSION ${_SOVERSION}) endif() set_target_properties(${_LIBRARY} PROPERTIES VERSION ${_VERSION} SOVERSION ${_SOVERSION}) endfunction() function(set_source_dependencies _TARGET) if(NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}") add_dependencies(${_TARGET} ${ARGN}) endif() endfunction() function(create_specfile) if(ARGN) foreach(arg ${ARGN}) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${arg}.spec.cmake) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${arg}.spec.cmake ${CMAKE_CURRENT_SOURCE_DIR}/${arg}.spec @ONLY NEWLINE_STYLE UNIX) else() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${arg}.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/${arg}.spec @ONLY NEWLINE_STYLE UNIX) endif() endforeach() else() if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.spec.in) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.spec @ONLY NEWLINE_STYLE UNIX) else() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.spec.cmake ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.spec @ONLY NEWLINE_STYLE UNIX) endif() endif() endfunction() function(create_rcfiles _OUTPUT) set(RC_VERSION ${VERSION}) string(REGEX REPLACE "[.]" "," RC_VERSION ${VERSION}) set(RC_VERSION "${RC_VERSION},0") set(RC_FILES) if(ARGN) foreach(arg ${ARGN}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${arg}.rc.cmake ${CMAKE_CURRENT_SOURCE_DIR}/${arg}.rc NEWLINE_STYLE WIN32) set(RC_FILES ${RC_FILES} ${arg}.rc) endforeach() else() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.rc.cmake ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.rc NEWLINE_STYLE WIN32) set(RC_FILES ${PROJECT_NAME}.rc) endif() if(WIN32) set(${_OUTPUT} ${RC_FILES} PARENT_SCOPE) else() set(${_OUTPUT} PARENT_SCOPE) endif() endfunction() function(create_scripts _OUTPUT) set(SCR_FILES) foreach(arg ${ARGN}) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${arg}.cmake) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${arg}.cmake ${CMAKE_CURRENT_BINARY_DIR}/${arg} NEWLINE_STYLE UNIX) else() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${arg}.in ${CMAKE_CURRENT_BINARY_DIR}/${arg} @ONLY NEWLINE_STYLE UNIX) endif() set(SCR_FILES ${SCR_FILES} ${CMAKE_CURRENT_BINARY_DIR}/${arg}) endforeach() set(${_OUTPUT} ${SCR_FILES} PARENT_SCOPE) endfunction() function(create_pcfiles _OUTPUT) set(PC_FILES) if(ARGN) foreach(arg ${ARGN}) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${arg}.pc.cmake) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${arg}.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/${arg}.pc NEWLINE_STYLE UNIX) else() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${arg}.pc.in ${CMAKE_CURRENT_BINARY_DIR}/${arg}.pc @ONLY NEWLINE_STYLE UNIX) endif() set(PC_FILES ${PC_FILES} ${CMAKE_CURRENT_BINARY_DIR}/${arg}.pc) endforeach() else() if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc.cmake) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc NEWLINE_STYLE UNIX) else() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc @ONLY NEWLINE_STYLE UNIX) endif() set(PC_FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc) endif() set(${_OUTPUT} ${PC_FILES} PARENT_SCOPE) endfunction() function(create_headers) if(ARGN) foreach(arg ${ARGN}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${arg}.cmake ${CMAKE_CURRENT_BINARY_DIR}/${arg} NEWLINE_STYLE UNIX) endforeach() else() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}-config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.h NEWLINE_STYLE UNIX) endif() include_directories(${CMAKE_CURRENT_BINARY_DIR}) endfunction() function(pc_libs _OUTPUT) set(libs) foreach(lib ${ARGN}) STRING(REGEX REPLACE "^[-]l" "" slib ${lib}) set(libs "${libs} -l${slib}") endforeach() set(${_OUTPUT} ${libs} PARENT_SCOPE) endfunction() function(pc_flags _OUTPUT) set(flags) foreach(flag ${ARGN}) set(flags "${flags} ${flag}") endforeach() set(${_OUTPUT} ${flags} PARENT_SCOPE) endfunction() macro (enable_arg _enable_name _enable_default) if (${ARGC} GREATER 2) set(_auto_arg_help ${_AUTO_ARG_HELP} "-Denable-${_enable_name}=[true|false] -- ${ARGV2} (default: ${_enable_default})" ) endif() if(NOT DEFINED enable-${_enable_name} AND NOT DEFINED disable-${_enable_name}) set(enable_${_enable_name} ${_enable_default}) elseif(DEFINED enable-${_enable_name}) if(enable-${_enable_name}) set(enable_${_enable_name} true) else() set(enable_${_enable_name} false) endif() unset(enable-${_enable_name}) unset(enable-${_enable_name} CACHE) elseif(DEFINED disable-${_enable_name}) if(disable-${_enable_name}) set(enable_${_enable_name} false) else() set(enable_${_enable_name} true) endif() unset(disable-${_enable_name}) unset(disable-${_enable_name} CACHE) endif() endmacro() commoncpp-7.0.1/cmake/CapeMakeTargets.cmake000066400000000000000000000115221411242573100205750ustar00rootroot00000000000000#.rst: # CapeMakeTargets # --------------- #============================================================================= # Copyright (C) 2015-2020 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. #============================================================================= macro(add_make_dist_target _TARGET _VERSION) option(BUILD_DISTFILE "Set to ON to create tarball distfile" OFF) if(BUILD_DISTFILE OR CMAKE_GENERATOR MATCHES "Unix Makefiles") add_custom_target(cleandist WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMAND rm -f "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET}[-_]*.gz" COMMAND rm -f "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET}_*.dsc" COMMAND rm -f "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET}-*.zip" COMMAND rm -f "${CMAKE_CURRENT_BINARY_DIR}/*.rpm" COMMAND rm -f "${CMAKE_CURRENT_BINARY_DIR}/*.deb" COMMAND rm -f "${CMAKE_CURRENT_BINARY_DIR}/*.changes" ) add_custom_target(dist DEPENDS cleandist WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND git archive --format tar.gz --output="${CMAKE_CURRENT_BINARY_DIR}/${_TARGET}-${_VERSION}.tar.gz" --prefix="${_TARGET}-${_VERSION}/" HEAD COMMAND git archive --format zip --output="${CMAKE_CURRENT_BINARY_DIR}/${_TARGET}-${_VERSION}.zip" --prefix="${_TARGET}-${_VERSION}/" HEAD ) endif() endmacro(add_make_dist_target) macro(add_make_srpm_target _TARGET) if(UNIX AND CMAKE_GENERATOR MATCHES "Unix Makefiles") add_custom_target(srpm DEPENDS dist WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND rm -f *.rpm COMMAND rpmbuild -bs --nodeps --define "_sourcedir ." --define "_srcrpmdir ." --sign ${_TARGET}.spec ) endif() endmacro() macro(add_make_uninstall_target) if(CMAKE_GENERATOR MATCHES "Unix Makefiles") add_custom_target(uninstall WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMAND xargs 4.1 only so far...) if(UCOMMON_VISIBILITY_FLAG) check_c_compiler_flag(${UCOMMON_VISIBILITY_FLAG} CHECK_VISIBILITY) endif() find_package(Threads) if (CMAKE_HAVE_PTHREAD_H) set(HAVE_PTHREAD_H TRUE) endif() set (UCOMMON_LIBS ${UCOMMON_LIBS} ${CMAKE_THREAD_LIBS_INIT} ${WITH_LDFLAGS}) if (MINGW OR MSYS) set (UCOMMON_LIBS ${UCOMMON_LIBS} mingwex mingw32) else() if (WIN32 AND CMAKE_COMPILER_IS_GNUCXX) set (UCOMMON_LIBS ${UCOMMON_LIBS} mingwex mingw32) endif() endif() if (WIN32 OR MINGW OR MSYS OR CMAKE_SYSTEM MATCHES "Windows") set (UCOMMON_LIBS ${UCOMMON_LIBS} crypt32 advapi32 user32 ws2_32 wsock32 kernel32) endif() if(UNIX AND NOT BUILD_STDLIB) set(UCOMMON_LIBS ${UCOMMON_LIBS} c) endif() if(MSYS OR MINGW) set(UCOMMON_LIBS ${UCOMMON_LIBS} msvcrt) endif() if(CMAKE_COMPILER_IS_GNUCXX AND NOT BUILD_STDLIB) check_library_exists(gcc __modsi3 "" HAVE_GCC_LIB) if(HAVE_GCC_LIB) set(UCOMMON_LIBS ${UCOMMON_LIBS} gcc) endif() endif() if(UNIX OR MSYS OR MINGW OR CYGWIN) check_library_exists(dl dlopen "" HAVE_DL_LIB) if (HAVE_DL_LIB) set (UCOMMON_LIBS ${UCOMMON_LIBS} dl) else() check_library_exists(compat dlopen "" HAVE_COMPAT_LIB) if(HAVE_COMPAT_LIB) set (UCOMMON_LIBS ${UCOMMON_LIBS} compat) endif() endif() check_library_exists(dld shl_load "" HAVE DLD_LIB) if (HAVE_DLD_LIB) set (UCOMMON_LIBS ${UCOMMON_LIBS} dld) endif() check_library_exists(socket socket "" HAVE_SOCKET_LIB) if (HAVE_SOCKET_LIB) set (UCOMMON_LIBS ${UCOMMON_LIBS} socket) endif() check_library_exists(posix4 sem_wait "" HAVE_POSIX4_LIB) if (HAVE_POSIX4_LIB) set(UCOMMON_LIBS ${UCOMMON_LIBS} posix4) endif() check_library_exists(rt clock_gettime "" HAVE_RT_LIB) if (HAVE_RT_LIB) set(UCOMMON_LIBS ${UCOMMON_LIBS} rt) endif() endif() endif() commoncpp-7.0.1/commoncpp-config.1000066400000000000000000000055741411242573100170450ustar00rootroot00000000000000.\" ucommon-config - script to get information about common c++ library .\" Copyright (C) 2009-2020 David Sugar .\" .\" This manual page 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 General Public License .\" along with this program; if not, write to the Free Software .\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 .\" USA. .\" .\" This manual page is written especially for Debian GNU/Linux. .\" .TH commoncpp-config "1" "July 2009" "GNU Common C++ Configuration" "GNU Telephony" .SH NAME commoncpp-config \- script to get information about common c++ library .SH SYNOPSIS .B commoncpp-config .BI [--prefix[= DIR ]] .BI [--exec-prefix[= DIR ]] .B [--version] .B [--cflags] .B [--libs] .B [--includes] .SH DESCRIPTION .B commoncpp-config is a tool that is used to configure to determine the compiler and linker flags that should be used to compile and link programs that use the .BR common c++ library. .IR Note : .B commoncpp-config is provided for compatibility with legacy software only. Current projects should use .B pkg-config instead! .SH OPTIONS .TP .B --version Print the currently installed version of .B common c++ on the standard output. .TP .B --includes Print the include directory for .BR common c++ headers .TP .B --libs Print the linker flags that are necessary to link a program with .BR common c++ .TP .B --cflags Print the compiler flags that are necessary to compile a program with .BR common c++ .TP .BI --prefix= PREFIX If specified, use .I PREFIX instead of the installation prefix that .B common c++ was built with when computing the output for the .B --cflags and .B --libs options. This option is also used for the exec prefix if .B --exec-prefix was not specified. This option must be specified before any .B --libs or .B --cflags options. .TP .BI --exec-prefix= PREFIX If specified, use .I PREFIX instead of the installation exec prefix that .B common c++ was built with when computing the output for the .B --cflags and .B --libs options. This option must be specified before any .B --libs or .B --cflags options. .SH "SEE ALSO" .IR pkg-config (1). .SH AUTHOR .B commoncpp-config was written by David Sugar . .SH COPYRIGHT Copyright \(co 2009 David Sugar, Tycho Softworks. .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. commoncpp-7.0.1/commoncpp-config.in000077500000000000000000000041231411242573100173030ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015-2020 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. prefix="@CMAKE_INSTALL_PREFIX@" includedir="@CMAKE_INSTALL_FULL_INCLUDEDIR@" libdir="@CMAKE_INSTALL_FULL_LIBDIR@" modflags="@MODULE_FLAGS@" usage() { cat < #ifdef HAVE_ENDIAN_H #include #endif #include #include #include #include #include #ifndef _MSWINDOWS_ #include #include #include #endif #if defined(_MSWINDOWS_) && !defined(__BIG_ENDIAN) #define __LITTLE_ENDIAN 1234 #define __BIG_ENDIAN 4321 #define __PDP_ENDIAN 3412 #define __BYTE_ORDER __LITTLE_ENDIAN #endif namespace ost { using std::ostream; #if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN enum { MCAST_VALID_MASK = 0xF0000000, MCAST_VALID_VALUE = 0xE0000000 }; #else enum { MCAST_VALID_MASK = 0x000000F0, MCAST_VALID_VALUE = 0x000000E0 }; #endif #ifndef _MSWINDOWS_ Mutex IPV4Address::mutex; #endif IPV4Host IPV4Host::_host_; const IPV4MulticastValidator IPV4Multicast::validator; void IPV4MulticastValidator::operator()(const in_addr address) const { #ifdef CCXX_EXCEPTIONS // "0.0.0.0" is always accepted, as it is an "empty" address. if ( (address.s_addr != INADDR_ANY) && (address.s_addr & MCAST_VALID_MASK) != MCAST_VALID_VALUE ) { throw "Multicast address not in the valid range: from 224.0.0.1 through 239.255.255.255"; } #endif } IPV4Address::IPV4Address(const IPV4Validator *_validator) : validator(_validator), ipaddr(NULL), addr_count(0), hostname(NULL) { *this = (in_addr_t)INADDR_ANY; } IPV4Address::IPV4Address(const char *address, const IPV4Validator *_validator) : validator(_validator), ipaddr(NULL), addr_count(0), hostname(NULL) { if(address == 0 || !strcmp(address, "*")) setAddress(NULL); else setAddress(address); } IPV4Address::IPV4Address(struct in_addr addr, const IPV4Validator *_validator) : validator(_validator), ipaddr(NULL), hostname(NULL) { if ( this->validator ) { (*validator)(addr); } addr_count = 1; ipaddr = new struct in_addr[1]; ipaddr[0] = addr; } IPV4Address::IPV4Address(const IPV4Address &rhs) : validator(rhs.validator), addr_count(rhs.addr_count), hostname(NULL) { ipaddr = new struct in_addr[addr_count]; memcpy(ipaddr, rhs.ipaddr, sizeof(struct in_addr) * addr_count); } IPV4Address::~IPV4Address() { if(ipaddr) { delete[] ipaddr; ipaddr = NULL; } if(hostname) { delString(hostname); hostname = NULL; } } struct in_addr IPV4Address::getAddress(void) const { return ipaddr[0]; } struct in_addr IPV4Address::getAddress(size_t i) const { return (i < addr_count ? ipaddr[i] : ipaddr[0]); } bool IPV4Address::isInetAddress(void) const { struct in_addr addr; memset(&addr, 0, sizeof(addr)); if(memcmp(&addr, &ipaddr[0], sizeof(addr))) return true; return false; } IPV4Address &IPV4Address::operator=(const char *str) { if(str == 0 || !strcmp(str, "*")) str = "0.0.0.0"; setAddress(str); return *this; } IPV4Address &IPV4Address::operator=(struct in_addr addr) { if(ipaddr) delete[] ipaddr; if ( validator ) (*validator)(addr); addr_count = 1; ipaddr = new struct in_addr[1]; ipaddr[0] = addr; if(hostname) delString(hostname); hostname = NULL; return *this; } IPV4Address &IPV4Address::operator=(in_addr_t addr) { union { in_addr_t addr; struct in_addr in4; } aptr; aptr.addr = addr; if ( validator ) (*validator)(aptr.in4); if(ipaddr) delete[] ipaddr; addr_count = 1; ipaddr = new struct in_addr[1]; memcpy(ipaddr, &aptr.in4, sizeof(struct in_addr)); if(hostname) delString(hostname); hostname = NULL; return *this; } IPV4Address &IPV4Address::operator=(const IPV4Address &rhs) { if(this == &rhs) return *this; addr_count = rhs.addr_count; if(ipaddr) delete[] ipaddr; ipaddr = new struct in_addr[addr_count]; memcpy(ipaddr, rhs.ipaddr, sizeof(struct in_addr) * addr_count); validator = rhs.validator; if(hostname) delString(hostname); hostname = NULL; return *this; } bool IPV4Address::operator==(const IPV4Address &a) const { const IPV4Address *smaller, *larger; size_t s, l; if(addr_count > a.addr_count) { smaller = &a; larger = this; } else { smaller = this; larger = &a; } // Loop through all addr's in the smaller and make sure // that they are all in the larger for(s = 0; s < smaller->addr_count; s++) { // bool found = false; for(l = 0; l < larger->addr_count && memcmp((char *)&smaller->ipaddr[s], (char *)&larger->ipaddr[l], sizeof(struct in_addr)); l++); if(l == larger->addr_count) return false; } return true; } bool IPV4Address::operator!=(const IPV4Address &a) const { // Impliment in terms of operator== return (*this == a ? false : true); } IPV4Host &IPV4Host::operator&=(const IPV4Mask &ma) { for(size_t i = 0; i < addr_count; i++) { struct in_addr mask = ma.getAddress(); uint8_t *a = (uint8_t *)&ipaddr[i]; uint8_t *m = (uint8_t *)&mask; for(size_t j = 0; j < sizeof(struct in_addr); ++j) *(a++) &= *(m++); } if(hostname) delString(hostname); hostname = NULL; return *this; } IPV4Host::IPV4Host(struct in_addr addr) : IPV4Address(addr) {} IPV4Host::IPV4Host(const char *host) : IPV4Address(host) { char namebuf[256]; if(!host) { if(this == &_host_) { gethostname(namebuf, 256); setAddress(namebuf); } else *this = _host_; } } bool IPV4Address::setIPAddress(const char *host) { if(!host) return false; #if defined(_MSWINDOWS_) struct sockaddr_in addr; addr.sin_addr.s_addr = inet_addr(host); if ( validator ) (*validator)(addr.sin_addr); if(addr.sin_addr.s_addr == INADDR_NONE) return false; *this = addr.sin_addr.s_addr; #else struct in_addr l_addr; int ok = inet_aton(host, &l_addr); if ( validator ) (*validator)(l_addr); if ( !ok ) return false; *this = l_addr; #endif return true; } void IPV4Address::setAddress(const char *host) { if(hostname) delString(hostname); hostname = NULL; if(!host) // The way this is currently used, this can never happen { *this = (in_addr_t)htonl(INADDR_ANY); return; } #ifdef _MSWINDOWS_ if(!stricmp(host, "localhost")) { *this = (long unsigned int)inet_addr("127.0.0.1"); return; } #endif if(!setIPAddress(host)) { struct hostent *hp; struct in_addr **bptr; #if defined(__GLIBC__) char hbuf[8192]; struct hostent hb; int rtn; if(gethostbyname_r(host, &hb, hbuf, sizeof(hbuf), &hp, &rtn)) hp = NULL; #elif defined(sun) char hbuf[8192]; struct hostent hb; int rtn; hp = gethostbyname_r(host, &hb, hbuf, sizeof(hbuf), &rtn); #elif (defined(__osf__) || defined(_MSWINDOWS_)) hp = gethostbyname(host); #else mutex.enterMutex(); hp = gethostbyname(host); mutex.leaveMutex(); #endif if(!hp) { if(ipaddr) delete[] ipaddr; ipaddr = new struct in_addr[1]; memset(ipaddr, 0, sizeof(struct in_addr)); return; } // Count the number of IP addresses returned addr_count = 0; for(bptr = (struct in_addr **)hp->h_addr_list; *bptr != NULL; bptr++) { addr_count++; } // Allocate enough memory if(ipaddr) delete[] ipaddr; // Cause this was allocated in base ipaddr = new struct in_addr[addr_count]; // Now go through the list again assigning to // the member ipaddr; bptr = (struct in_addr **)hp->h_addr_list; for(unsigned int i = 0; i < addr_count; i++) { if ( validator ) (*validator)(*bptr[i]); ipaddr[i] = *bptr[i]; } } } IPV4Broadcast::IPV4Broadcast(const char *net) : IPV4Address(net) { } IPV4Mask::IPV4Mask(const char *mask) { unsigned long x = 0xffffffff; int l = 32 - atoi(mask); if(setIPAddress(mask)) return; if(l < 1 || l > 32) { #ifdef CCXX_EXCEPTIONS if(Thread::getException() == Thread::throwObject) throw((IPV4Address *)this); #endif return; } *this = htonl(x << l); } const char *IPV4Address::getHostname(void) const { struct hostent *hp = NULL; struct in_addr addr0; memset(&addr0, 0, sizeof(addr0)); if(!memcmp(&addr0, &ipaddr[0], sizeof(addr0))) return NULL; #ifdef _MSWINDOWS_ memset(&addr0, 0xff, sizeof(addr0)); if(!memcmp(&addr0, &ipaddr[0], sizeof(addr0))) return "255.255.255.255"; long a = inet_addr("127.0.0.1"); if(!memcmp(&a, &ipaddr[0], sizeof(a))) return "localhost"; #endif #if defined(__GLIBC__) char hbuf[8192]; struct hostent hb; int rtn; if(gethostbyaddr_r((char *)&ipaddr[0], sizeof(addr0), AF_INET, &hb, hbuf, sizeof(hbuf), &hp, &rtn)) hp = NULL; #elif defined(sun) char hbuf[8192]; struct hostent hb; int rtn; hp = gethostbyaddr_r((char *)&ipaddr[0], (int)sizeof(addr0), (int)AF_INET, &hb, hbuf, (int)sizeof(hbuf), &rtn); #elif defined(__osf__) || defined(_MSWINDOWS_) hp = gethostbyaddr((char *)&ipaddr[0], sizeof(addr0), AF_INET); #else mutex.enterMutex(); hp = gethostbyaddr((char *)&ipaddr[0], sizeof(addr0), AF_INET); mutex.leaveMutex(); #endif if(hp) { if(hostname) delString(hostname); hostname = newString(hp->h_name); return hostname; } else { return inet_ntoa(ipaddr[0]); } } IPV4Host operator&(const IPV4Host &addr, const IPV4Mask &mask) { IPV4Host temp = addr; temp &= mask; return temp; } IPV4Multicast::IPV4Multicast() : IPV4Address(&validator) {} IPV4Multicast::IPV4Multicast(const struct in_addr address) : IPV4Address(address, &validator) {} IPV4Multicast::IPV4Multicast(const char *address) : IPV4Address(address, &validator) {} #ifdef CCXX_IPV6 #ifndef _MSWINDOWS_ Mutex IPV6Address::mutex; #endif const IPV6MulticastValidator IPV6Multicast::validator; void IPV6MulticastValidator::operator()(const in6_addr address) const { #ifdef CCXX_EXCEPTIONS // "0000:" is always accepted, as it is an "empty" address. if ( (address.s6_addr[0] != 0 || address.s6_addr[1] != 0) && (address.s6_addr[0] != 0xff || address.s6_addr[1] < 0x1f)) { throw "Multicast address not in the valid prefix ff00-ff1f:"; } #endif } IPV6Address::IPV6Address(const IPV6Validator *_validator) : validator(_validator), hostname(NULL) { addr_count = 1; ipaddr = new struct in6_addr[1]; memcpy(ipaddr, &in6addr_any, sizeof(struct in6_addr)); } IPV6Address::IPV6Address(const char *address, const IPV6Validator *_validator) : validator(_validator), ipaddr(NULL), addr_count(0), hostname(NULL) { if(address == 0 || !strcmp(address, "*")) setAddress(NULL); else setAddress(address); } IPV6Address::IPV6Address(struct in6_addr addr, const IPV6Validator *_validator) : validator(_validator), ipaddr(NULL), hostname(NULL) { if ( this->validator ) { (*validator)(addr); } addr_count = 1; ipaddr = new struct in6_addr[1]; memcpy(ipaddr, &addr, sizeof(struct in6_addr)); } IPV6Address::IPV6Address(const IPV6Address &rhs) : validator(rhs.validator), addr_count(rhs.addr_count), hostname(NULL) { ipaddr = new struct in6_addr[addr_count]; memcpy(ipaddr, rhs.ipaddr, sizeof(struct in6_addr) * addr_count); } IPV6Address::~IPV6Address() { if(ipaddr) { delete[] ipaddr; ipaddr = NULL; } if(hostname) { delString(hostname); hostname = NULL; } } struct in6_addr IPV6Address::getAddress(void) const { return ipaddr[0]; } struct in6_addr IPV6Address::getAddress(size_t i) const { return (i < addr_count ? ipaddr[i] : ipaddr[0]); } bool IPV6Address::isInetAddress(void) const { struct in6_addr addr; memset(&addr, 0, sizeof(addr)); if(!ipaddr) return false; if(memcmp(&addr, &ipaddr[0], sizeof(addr))) return true; return false; } IPV6Address &IPV6Address::operator=(const char *str) { if(str == 0 || !strcmp(str, "*")) str = "::"; setAddress(str); return *this; } IPV6Address &IPV6Address::operator=(struct in6_addr addr) { if(ipaddr) delete[] ipaddr; if ( validator ) (*validator)(addr); addr_count = 1; ipaddr = new struct in6_addr[1]; ipaddr[0] = addr; if(hostname) delString(hostname); hostname = NULL; return *this; } IPV6Address &IPV6Address::operator=(const IPV6Address &rhs) { if(this == &rhs) return *this; addr_count = rhs.addr_count; if(ipaddr) delete[] ipaddr; ipaddr = new struct in6_addr[addr_count]; memcpy(ipaddr, rhs.ipaddr, sizeof(struct in6_addr) * addr_count); validator = rhs.validator; if(hostname) delString(hostname); hostname = NULL; return *this; } bool IPV6Address::operator==(const IPV6Address &a) const { const IPV6Address *smaller, *larger; size_t s, l; if(addr_count > a.addr_count) { smaller = &a; larger = this; } else { smaller = this; larger = &a; } // Loop through all addr's in the smaller and make sure // that they are all in the larger for(s = 0; s < smaller->addr_count; s++) { // bool found = false; for(l = 0; l < larger->addr_count && memcmp((char *)&smaller->ipaddr[s], (char *)&larger->ipaddr[l], sizeof(struct in6_addr)); l++); if(l == larger->addr_count) return false; } return true; } bool IPV6Address::operator!=(const IPV6Address &a) const { // Impliment in terms of operator== return (*this == a ? false : true); } IPV6Host &IPV6Host::operator&=(const IPV6Mask &ma) { for(size_t i = 0; i < addr_count; i++) { struct in6_addr mask = ma.getAddress(); uint8_t *a = (uint8_t *)&ipaddr[i]; uint8_t *m = (uint8_t *)&mask; for(size_t j = 0; j < sizeof(struct in6_addr); ++j) *(a++) &= *(m++); } if(hostname) delString(hostname); hostname = NULL; return *this; } IPV6Host::IPV6Host(struct in6_addr addr) : IPV6Address(addr) {} IPV6Host::IPV6Host(const char *host) : IPV6Address(host) { char namebuf[256]; if(!host) { gethostname(namebuf, 256); setAddress(namebuf); } } bool IPV6Address::setIPAddress(const char *host) { if(!host) return false; struct in6_addr l_addr; #ifdef _MSWINDOWS_ struct sockaddr saddr; int slen = sizeof(saddr); struct sockaddr_in6 *paddr = (struct sockaddr_in6 *)&saddr; int ok = WSAStringToAddress((LPSTR)host, AF_INET6, NULL, &saddr, &slen); l_addr = paddr->sin6_addr; #else int ok = inet_pton(AF_INET6, host, &l_addr); #endif if ( validator ) (*validator)(l_addr); if ( !ok ) return false; *this = l_addr; return true; } #if defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME2) void IPV6Address::setAddress(const char *host) { if(hostname) delString(hostname); hostname = NULL; if(!host) // The way this is currently used, this can never happen host = "::"; #ifdef _MSWINDOWS_ if(!stricmp(host, "localhost")) host = "::1"; #endif if(!setIPAddress(host)) { struct addrinfo hint, *list = NULL, *first; memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_INET6; struct in6_addr *addr; struct sockaddr_in6 *ip6addr; if(getaddrinfo(host, NULL, &hint, &list) || !list) { if(ipaddr) delete[] ipaddr; ipaddr = new struct in6_addr[1]; memset((void *)&ipaddr[0], 0, sizeof(struct in6_addr)); return; } // Count the number of IP addresses returned addr_count = 0; first = list; while(list) { ++addr_count; list = list->ai_next; } // Allocate enough memory if(ipaddr) delete[] ipaddr; // Cause this was allocated in base ipaddr = new struct in6_addr[addr_count]; // Now go through the list again assigning to // the member ipaddr; list = first; int i = 0; while(list) { ip6addr = (struct sockaddr_in6 *)list->ai_addr; addr = &ip6addr->sin6_addr; if(validator) (*validator)(*addr); ipaddr[i++] = *addr; list = list->ai_next; } freeaddrinfo(first); } } #else void IPV6Address::setAddress(const char *host) { if(hostname) delString(hostname); hostname = NULL; if(!host) // The way this is currently used, this can never happen host = "::"; #ifdef _MSWINDOWS_ if(!stricmp(host, "localhost")) host = "::1"; #endif if(!setIPAddress(host)) { struct hostent *hp; struct in6_addr **bptr; #if defined(__GLIBC__) char hbuf[8192]; struct hostent hb; int rtn; if(gethostbyname2_r(host, AF_INET6, &hb, hbuf, sizeof(hbuf), &hp, &rtn)) hp = NULL; #elif defined(sun) char hbuf[8192]; struct hostent hb; int rtn; hp = gethostbyname2_r(host, AF_INET6, &hb, hbuf, sizeof(hbuf), &rtn); #elif (defined(__osf__) || defined(_OSF_SOURCE) || defined(__hpux)) hp = gethostbyname(host); #elif defined(_MSWINDOWS_) && (!defined(_MSC_VER) || _MSC_VER < 1300) hp = gethostbyname(host); #elif defined(_MSWINDOWS_) hp = gethostbyname2(host, AF_INET6); #else mutex.enterMutex(); hp = gethostbyname2(host, AF_INET6); mutex.leaveMutex(); #endif if(!hp) { if(ipaddr) delete[] ipaddr; ipaddr = new struct in6_addr[1]; memset((void *)&ipaddr[0], 0, sizeof(struct in6_addr)); return; } // Count the number of IP addresses returned addr_count = 0; for(bptr = (struct in6_addr **)hp->h_addr_list; *bptr != NULL; bptr++) { addr_count++; } // Allocate enough memory if(ipaddr) delete[] ipaddr; // Cause this was allocated in base ipaddr = new struct in6_addr[addr_count]; // Now go through the list again assigning to // the member ipaddr; bptr = (struct in6_addr **)hp->h_addr_list; for(unsigned int i = 0; i < addr_count; i++) { if ( validator ) (*validator)(*bptr[i]); ipaddr[i] = *bptr[i]; } } } #endif IPV6Broadcast::IPV6Broadcast(const char *net) : IPV6Address(net) { } IPV6Mask::IPV6Mask(const char *mask) : IPV6Address(mask) { } const char *IPV6Address::getHostname(void) const { struct hostent *hp = NULL; struct in6_addr addr0; static char strbuf[64]; memset(&addr0, 0, sizeof(addr0)); if(!memcmp(&addr0, &ipaddr[0], sizeof(addr0))) return NULL; if(!memcmp(&in6addr_loopback, &ipaddr[0], sizeof(addr0))) return "localhost"; #if defined(__GLIBC__) char hbuf[8192]; struct hostent hb; int rtn; if(gethostbyaddr_r((char *)&ipaddr[0], sizeof(addr0), AF_INET6, &hb, hbuf, sizeof(hbuf), &hp, &rtn)) hp = NULL; #elif defined(sun) char hbuf[8192]; struct hostent hb; int rtn; hp = gethostbyaddr_r((char *)&ipaddr[0], sizeof(addr0), AF_INET6, &hb, hbuf, (int)sizeof(hbuf), &rtn); #elif defined(__osf__) || defined(_MSWINDOWS_) hp = gethostbyaddr((char *)&ipaddr[0], sizeof(addr0), AF_INET6); #else mutex.enterMutex(); hp = gethostbyaddr((char *)&ipaddr[0], sizeof(addr0), AF_INET6); mutex.leaveMutex(); #endif if(hp) { if(hostname) delString(hostname); hostname = newString(hp->h_name); return hostname; } else { #ifdef _MSWINDOWS_ struct sockaddr saddr; struct sockaddr_in6 *paddr = (struct sockaddr_in6 *)&saddr; DWORD slen = sizeof(strbuf); memset(&saddr, 0, sizeof(saddr)); paddr->sin6_family = AF_INET6; paddr->sin6_addr = ipaddr[0]; WSAAddressToString(&saddr, sizeof(saddr), NULL, strbuf, &slen); return strbuf; #else return inet_ntop(AF_INET6, &ipaddr[0], strbuf, sizeof(strbuf)); #endif } } IPV6Host operator&(const IPV6Host &addr, const IPV6Mask &mask) { IPV6Host temp = addr; temp &= mask; return temp; } IPV6Multicast::IPV6Multicast() : IPV6Address(&validator) {} IPV6Multicast::IPV6Multicast(const char *address) : IPV6Address(address,&validator) {} #endif ostream& operator<<(ostream &os, const IPV4Address &ia) { os << inet_ntoa(getaddress(ia)); return os; } typedef uint8_t bit_t; static void bitmask(bit_t *bits, bit_t *mask, unsigned len) { while(len--) *(bits++) &= *(mask++); } static void bitimask(bit_t *bits, bit_t *mask, unsigned len) { while(len--) *(bits++) |= ~(*(mask++)); } static void bitset(bit_t *bits, unsigned blen) { 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) { 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; } IPV4Cidr::IPV4Cidr() { memset(&network, 0, sizeof(network)); memset(&netmask, 0, sizeof(netmask)); } IPV4Cidr::IPV4Cidr(const char *cp) { set(cp); } IPV4Cidr::IPV4Cidr(IPV4Cidr &cidr) { memcpy(&network, &cidr.network, sizeof(network)); memcpy(&netmask, &cidr.netmask, sizeof(netmask)); } bool IPV4Cidr::isMember(const struct in_addr &addr) const { struct in_addr host = addr; bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host)); if(!memcmp(&host, &network, sizeof(host))) return true; return false; } bool IPV4Cidr::isMember(const struct sockaddr *saddr) const { struct sockaddr_in *addr = (struct sockaddr_in *)saddr; struct in_addr host; if(saddr->sa_family != AF_INET) return false; memcpy(&host, &addr->sin_addr.s_addr, sizeof(host)); bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host)); if(!memcmp(&host, &network, sizeof(host))) return true; return false; } struct in_addr IPV4Cidr::getBroadcast(void) const { struct in_addr bcast; memcpy(&bcast, &network, sizeof(network)); bitimask((bit_t *)&bcast, (bit_t *)&netmask, sizeof(bcast)); return bcast; } unsigned IPV4Cidr::getMask(const char *cp) const { unsigned dcount = 0; const char *gp = cp; const char *mp = strchr(cp, '/'); uint8_t dots[4]; #ifdef _MSWINDOWS_ DWORD mask; #else uint32_t mask; #endif if(mp) { if(!strchr(++mp, '.')) return atoi(mp); mask = inet_addr(mp); 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; } void IPV4Cidr::set(const char *cp) { char cbuf[INET_IPV4_ADDRESS_SIZE]; char *ep; unsigned dots = 0; #ifdef _MSWINDOWS_ DWORD addr; #endif memset(&netmask, 0, sizeof(netmask)); bitset((bit_t *)&netmask, getMask(cp)); setString(cbuf, sizeof(cbuf), cp); ep = (char *)strchr(cp, '/'); if(ep) *ep = 0; cp = cbuf; while(NULL != (cp = strchr(cp, '.'))) { ++dots; ++cp; } while(dots++ < 3) addString(cbuf, sizeof(cbuf), ".0"); #ifdef _MSWINDOWS_ addr = inet_addr(cbuf); memcpy(&network, &addr, sizeof(network)); #else inet_aton(cbuf, &network); #endif bitmask((bit_t *)&network, (bit_t *)&netmask, sizeof(network)); } #ifdef CCXX_IPV6 IPV6Cidr::IPV6Cidr() { memset(&network, 0, sizeof(network)); memset(&netmask, 0, sizeof(netmask)); } IPV6Cidr::IPV6Cidr(const char *cp) { set(cp); } IPV6Cidr::IPV6Cidr(IPV6Cidr &cidr) { memcpy(&network, &cidr.network, sizeof(network)); memcpy(&netmask, &cidr.netmask, sizeof(netmask)); } bool IPV6Cidr::isMember(const struct in6_addr &addr) const { struct in6_addr host = addr; bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host)); if(!memcmp(&host, &network, sizeof(host))) return true; return false; } bool IPV6Cidr::isMember(const struct sockaddr *saddr) const { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)saddr; struct in6_addr host; if(saddr->sa_family != AF_INET6) return false; memcpy(&host, &addr->sin6_addr, sizeof(host)); bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host)); if(!memcmp(&host, &network, sizeof(host))) return true; return false; } struct in6_addr IPV6Cidr::getBroadcast(void) const { struct in6_addr bcast; memcpy(&bcast, &network, sizeof(network)); bitimask((bit_t *)&bcast, (bit_t *)&netmask, sizeof(bcast)); return bcast; } unsigned IPV6Cidr::getMask(const char *cp) const { unsigned count = 0, rcount = 0; const char *sp = strchr(cp, '/'); int flag = 0; if(sp) return atoi(++sp); if(!strncmp(cp, "ff00:", 5)) return 8; if(!strncmp(cp, "fe80:", 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 = 1; } else flag = 0; } } return rcount; } void IPV6Cidr::set(const char *cp) { char cbuf[INET_IPV6_ADDRESS_SIZE]; char *ep; memset(&netmask, 0, sizeof(netmask)); bitset((bit_t *)&netmask, getMask(cp)); setString(cbuf, sizeof(cbuf), cp); ep = (char *)strchr(cp, '/'); if(ep) *ep = 0; #ifdef _MSWINDOWS_ int slen = sizeof(network); WSAStringToAddressA(cbuf, AF_INET6, NULL, (struct sockaddr*)&network, &slen); #else inet_pton(AF_INET6, cbuf, &network); #endif bitmask((bit_t *)&network, (bit_t *)&netmask, sizeof(network)); } #endif } // namespace ost commoncpp-7.0.1/commoncpp/applog.cpp000066400000000000000000000672541411242573100175110ustar00rootroot00000000000000// Copyright (C) 2005-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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 UCOMMON_SYSRUNTIME #include #include #include #include #ifndef _MSWINDOWS_ #include #include #endif #include #include #include #include #include #include #include #include // TODO sc: test if has to move up now that it is into commoncpp // NOTE: the order of inclusion is important do not move following include line // redefinition of __EXPORT needed if we're compiling our dll #include // local includes #include namespace ost { class logStruct { public: string _ident; int _priority; Slog::Level _level; bool _enable; bool _clogEnable; bool _slogEnable; size_t _msgpos; enum logEnum { BUFF_SIZE = 512, LAST_CHAR = BUFF_SIZE - 1 }; char _msgbuf[BUFF_SIZE]; logStruct() : _ident("") , _priority(Slog::levelDebug), _level(Slog::levelDebug), _enable(false), _clogEnable(false), _slogEnable(false), _msgpos(0) { memset(_msgbuf, 0, BUFF_SIZE); }; ~logStruct() {}; }; struct levelNamePair { const char *name; Slog::Level level; }; //#ifdef _MSWINDOWS_ //template class std::map; //#endif class LevelName : public std::map { public: LevelName(const levelNamePair initval[], int num) { for (int i = 0; i < num; i++) insert(make_pair(string(initval[i].name), initval[i].level)); }; }; class logger : public ost::ThreadQueue { private: string _nomeFile; std::fstream _logfs; bool _usePipe; bool _closedByApplog; protected: // to dequeue log messages and write them to file if not log_directly virtual void runQueue(void *data); virtual void startQueue(void); virtual void stopQueue(void); virtual void onTimer(void); virtual void final(void); void _openFile(); public: logger(const char* logFileName = NULL, bool usePipe = false); virtual ~logger(); // To change log file name void logFileName(const char* FileName, bool usePipe = false); void openFile(); void closeFile(); }; // mapping thread ID <-> logStruct (buffer) typedef std::map LogPrivateData; // map ident <-> levels typedef std::map IdentLevel; class __LOCAL AppLogPrivate { public: // subscription and unsubsciption must be protected as well ost::Mutex _subMutex; // mapping thread ID <-> logStruct (buffer) LogPrivateData _logs; // map ident <-> levels IdentLevel _identLevel; // log directly into file bool _logDirectly; bool _logPipe; // log spooler logger *_pLogger; string _nomeFile; Mutex _lock; std::fstream _logfs; static const levelNamePair _values[]; static LevelName _assoc; AppLogPrivate() : _pLogger(NULL) {} ~AppLogPrivate() { if (_pLogger) delete _pLogger; } }; const levelNamePair AppLogPrivate::_values[] = { { "emerg", Slog::levelEmergency }, { "alert", Slog::levelAlert }, { "critical", Slog::levelCritical }, { "error", Slog::levelError }, { "warn", Slog::levelWarning }, { "notice", Slog::levelNotice }, { "info", Slog::levelInfo }, { "debug", Slog::levelDebug } }; AppLog alog; LevelName AppLogPrivate::_assoc(_values, sizeof AppLogPrivate::_values / sizeof *AppLogPrivate::_values); std::map *AppLog::assoc = &AppLogPrivate::_assoc; #if defined(CCXX_EXCEPTIONS) HEXdump::HEXdump(const unsigned char *buffer, int len, int max_len) : _str() { std::stringstream sstr; if (buffer == NULL || len <= 0) return ; long buf_len = (max_len > 0 && len > max_len) ? max_len : len; long int addr = 0; int cnt2 = 0; int n; int i; sstr.str(""); // get exception from ifstream failures sstr.exceptions(ifstream::failbit | ifstream::badbit); try { sstr << std::endl; sstr << "dump " << len << " byte." << std::endl; for (n = 0; n < buf_len; n++) { if (cnt2 == 0) { // Print address. sstr << std::setw(7) << std::setfill('0') << int (addr) << " - "; addr = addr + 16; } cnt2 = (cnt2 + 1) % 18; if (cnt2 <= 16) { // print hex value sstr << std::hex << std::setw(2) << std::setfill('0') << int (buffer[n]) << " "; } else { sstr << " "; sstr << std::setfill(' '); for (i = n - cnt2 + 1; i < n; i++) { // print ascii value if (buffer[i] < 32 || 126 < buffer[i]) { sstr << '.'; } else { sstr << buffer[i]; } } sstr << std::endl; sstr << std::dec; cnt2 = 0; n--; } } sstr << std::setfill(' '); for (i = cnt2 + 1; i <= 16 ; i++) { sstr << std::setw(2) << "--" << " "; } sstr << " "; for (i = n - cnt2; cnt2 <= 16 && i < n; i++) { if (buffer[i] < 32 || 126 < buffer[i]) { sstr << '.'; } else { sstr << buffer[i]; } } sstr << std::dec; if (max_len > 0 && len > max_len) sstr << std::endl << "dump troncato a " << max_len << " byte." << std::endl; } catch (...) { sstr.str("HEXdump failed!"); } _str = sstr.str(); } #endif // class logger logger::logger(const char* logFileName, bool usePipe) : ThreadQueue(NULL, 0, 0), _usePipe(usePipe), _closedByApplog(false) { _nomeFile = ""; if (logFileName) _nomeFile = logFileName; openFile(); } logger::~logger() { Semaphore::post(); Thread::terminate(); _logfs.flush(); _logfs.close(); } // New log file name void logger::logFileName(const char* FileName, bool usePipe) { if (!FileName) return; _usePipe = usePipe; _nomeFile = FileName; if (_logfs.is_open()) _logfs.close(); openFile(); } /// open also logger if applog->open() is invoked void logger::openFile() { _closedByApplog=false; } ///internal logger openFile needed to use pipe and avoid stream buffering in the case /// the consumer is not connected to pipe void logger::_openFile() { if (!_closedByApplog && !_logfs.is_open()) { if (!_nomeFile.empty()) { _logfs.clear(); if (!_usePipe) { _logfs.open(_nomeFile.c_str(), std::ofstream::out | std::ofstream::app | std::ofstream::ate); } #ifndef _MSWINDOWS_ else { // create pipe int err = mkfifo(_nomeFile.c_str(), S_IRUSR | S_IWUSR); if (err == 0 || errno == EEXIST) { // and open it _logfs.open(_nomeFile.c_str(), std::fstream::in | std::fstream::out); } else THROW(AppLogException("Can't create pipe")); } #endif if (_logfs.fail()) THROW(AppLogException("Can't open log file name")); } } } /// close also logger if applog->close() is invoked void logger::closeFile() { _closedByApplog = true; } // writes into filename enqueued messages void logger::runQueue(void * data) { char *str = (char *) data; // if for some internal reasons file has been closed // reopen it try { _openFile(); } catch (AppLogException e) { std::cerr << e.what() << std::endl; slog.emerg("%s\n", e.what()); std::cerr.flush(); } if (_logfs.is_open()) { _logfs << str; _logfs.flush(); } //if we use a pipe to avoid increasing of stream buffer // without a consumer, we open, use and close it if ((_usePipe || _closedByApplog) && _logfs.is_open()) { _logfs.flush(); _logfs.close(); } } void logger::startQueue() { } void logger::stopQueue() { } void logger::onTimer() { } void logger::final() { if (started) { data_t *pFirst = first; while (pFirst) { runQueue(pFirst->data); pFirst = pFirst->next; } } } #ifndef _MSWINDOWS_ AppLog::AppLog(const char* logFileName, bool logDirectly, bool usePipe) : streambuf(), ostream((streambuf*) this) #else AppLog::AppLog(const char* logFileName, bool logDirectly) : streambuf(), ostream((streambuf*) this) #endif { d= NULL; // pedantic fussy about initing members before base classes... d = new AppLogPrivate(); if (!d) THROW(AppLogException("Memory allocation problem")); d->_nomeFile = ""; d->_logDirectly = logDirectly; #ifndef _MSWINDOWS_ d->_logPipe = usePipe; #else d->_logPipe = false; #endif // level string to level value // assoc["emerg"] = levelEmergency; // assoc["alert"] = levelAlert; // assoc["critical"] = levelCritical; // assoc["error"] = levelError; // assoc["warn"] = levelWarning; // assoc["notice"] = levelNotice; // assoc["info"] = levelInfo; // assoc["debug"] = levelDebug; if (logFileName) d->_nomeFile = logFileName; if (!d->_logDirectly && logFileName) d->_pLogger = new logger(logFileName, d->_logPipe); else d->_pLogger = NULL; // writes to file directly if (!d->_nomeFile.empty() && d->_logDirectly) { if (!d->_logPipe) { d->_logfs.open(d->_nomeFile.c_str(), std::fstream::in | std::fstream::out); if (!d->_logfs.is_open()) { d->_logfs.open(d->_nomeFile.c_str(), std::fstream::out | std::fstream::app); } else d->_logfs.seekg(0, std::fstream::end); } // on Windows pipe are not used as they are not supported on WinNT #ifndef _MSWINDOWS_ else { // create pipe int err = mkfifo(d->_nomeFile.c_str(), S_IRUSR | S_IWUSR); if (err == 0 || errno == EEXIST) { // and open it d->_logfs.open(d->_nomeFile.c_str(), std::fstream::in | std::fstream::out); } else THROW(AppLogException("Can't create pipe")); } #endif if (d->_logfs.fail()) THROW(AppLogException("Can't open log file name")); } //from Error level on write to syslog also slog.level(Slog::levelError); slog.clogEnable(false); } AppLog::~AppLog() { // if _logDirectly close(); if (d) delete d; } void AppLog::subscribe() { ost::MutexLock mtx(d->_subMutex); Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) { // subscribes new thread d->_logs[tid]; } } } void AppLog::unsubscribe() { ost::MutexLock mtx(d->_subMutex); Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt != d->_logs.end()) { // unsubscribes thread d->_logs.erase(logIt); } } } #ifndef _MSWINDOWS_ void AppLog::logFileName(const char* FileName, bool logDirectly, bool usePipe) #else void AppLog::logFileName(const char* FileName, bool logDirectly) #endif { if (!FileName) { slog.error("Null file name!"); return; } d->_lock.enterMutex(); d->_nomeFile = FileName; close(); d->_logDirectly = logDirectly; #ifndef _MSWINDOWS_ d->_logPipe = usePipe; #else d->_logPipe = false; #endif if (!d->_logDirectly) { if (d->_pLogger) d->_pLogger->logFileName(FileName, d->_logPipe); else d->_pLogger = new logger(FileName, d->_logPipe); d->_lock.leaveMutex(); return; } // log directly if (!d->_nomeFile.empty()) { if (!d->_logPipe) { d->_logfs.open(d->_nomeFile.c_str(), std::fstream::out | std::fstream::app); } #ifndef _MSWINDOWS_ else { // create pipe int err = mkfifo(d->_nomeFile.c_str(), S_IRUSR | S_IWUSR); if (err == 0 || errno == EEXIST) { // and open it d->_logfs.open(d->_nomeFile.c_str(), std::fstream::in | std::fstream::out); } else THROW(AppLogException("Can't create pipe")); } #endif if (d->_logfs.fail()) THROW(AppLogException("Can't open log file name")); } d->_lock.leaveMutex(); } // writes to log void AppLog::writeLog(bool endOfLine) { Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return; if ((d->_logDirectly && !d->_logfs.is_open() && !logIt->second._clogEnable) || (!d->_logDirectly && !d->_pLogger && !logIt->second._clogEnable)) { logIt->second._msgpos = 0; logIt->second._msgbuf[0] = '\0'; return; } if (logIt->second._enable) { time_t now; struct tm *dt; time(&now); struct timeval detail_time; gettimeofday(&detail_time, NULL); dt = localtime(&now); char buf[50]; const char *p = "unknown"; switch (logIt->second._priority) { case Slog::levelEmergency: p = "emerg"; break; case Slog::levelInfo: p = "info"; break; case Slog::levelError: p = "error"; break; case Slog::levelAlert: p = "alert"; break; case Slog::levelDebug: p = "debug"; break; case Slog::levelNotice: p = "notice"; break; case Slog::levelWarning: p = "warn"; break; case Slog::levelCritical: p = "crit"; break; } snprintf(buf, sizeof(buf) - 1, "%04d-%02d-%02d %02d:%02d:%02d.%03d ", dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday, dt->tm_hour, dt->tm_min, dt->tm_sec, (int)(detail_time.tv_usec / 1000)); buf[sizeof(buf)-1] = 0; // per sicurezza if (d->_logDirectly) { d->_lock.enterMutex(); if (d->_logfs.is_open()) { d->_logfs << buf; if (!logIt->second._ident.empty()) d->_logfs << logIt->second._ident.c_str() << ": "; d->_logfs << "[" << p << "] "; d->_logfs << logIt->second._msgbuf; if (endOfLine) d->_logfs << endl; d->_logfs.flush(); } } else if (d->_pLogger) { // ThreadQueue std::stringstream sstr; sstr.str(""); // reset contents sstr << buf; if (!logIt->second._ident.empty()) sstr << logIt->second._ident.c_str() << ": "; sstr << "[" << p << "] "; sstr << logIt->second._msgbuf; if (endOfLine) sstr << endl; sstr.flush(); if (sstr.fail()) cerr << "stringstream failed!!!! " << endl; // enqueues log message d->_pLogger->post((void *) sstr.str().c_str(), (unsigned)(sstr.str().length() + 1)); d->_lock.enterMutex(); } // slog it if error level is right if (logIt->second._slogEnable && logIt->second._priority <= Slog::levelError) { slog((Slog::Level) logIt->second._priority) << logIt->second._msgbuf; if (endOfLine) slog << endl; } if (logIt->second._clogEnable #ifndef _MSWINDOWS_ && (getppid() > 1) #endif ) { clog << logIt->second._msgbuf; if (endOfLine) clog << endl; } d->_lock.leaveMutex(); } logIt->second._msgpos = 0; logIt->second._msgbuf[0] = '\0'; } } void AppLog::close(void) { if (d->_logDirectly) { d->_lock.enterMutex(); if (d->_logfs.is_open()) { d->_logfs.flush(); d->_logfs.close(); } d->_lock.leaveMutex(); } else { if (d->_pLogger) d->_pLogger->closeFile(); } } void AppLog::open(const char *ident) { Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return; if (d->_nomeFile.empty()) { std::cerr << "Empty file name" << std::endl; slog.emerg("Empty file nane!\n"); } if (d->_logDirectly) { d->_lock.enterMutex(); if (!d->_logfs.is_open()) { d->_logfs.open(d->_nomeFile.c_str(), std::fstream::out | std::fstream::app); } if (!d->_logfs.is_open()) { std::cerr << "Can't open file name!" << std::endl; slog.emerg("Can't open file name!\n"); } d->_lock.leaveMutex(); } else { if (d->_pLogger) d->_pLogger->openFile(); } if (ident != NULL) logIt->second._ident = ident; } } void AppLog::identLevel(const char *ident, Slog::Level level) { if (!ident) return; string id = ident; IdentLevel::iterator idLevIt = d->_identLevel.find(id); if (idLevIt == d->_identLevel.end()) { d->_identLevel[id] = level; } else idLevIt->second = level; } void AppLog::level(Slog::Level enable) { Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return; logIt->second._level = enable; } } void AppLog::clogEnable(bool f) { Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return; logIt->second._clogEnable = f; } } void AppLog::slogEnable(bool en) { Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return; logIt->second._slogEnable = en; } } int AppLog::sync() { int retVal = (pbase() != pptr()); if (fail()) { slog(Slog::levelNotice) << "fail() is true, calling clear()" << endl; clear(); } Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt != d->_logs.end()) { retVal = (logIt->second._msgpos > 0); if (retVal) { slog(Slog::levelNotice) << "sync called and msgpos > 0" << endl; } } } overflow(EOF); return retVal; } int AppLog::overflow(int c) { Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return c; if (!logIt->second._enable) return c; if (c == '\n' || !c || c == EOF) { if (!logIt->second._msgpos) { if (c == '\n') writeLog(true); return c; } if (logIt->second._msgpos < (int)(sizeof(logIt->second._msgbuf) - 1)) logIt->second._msgbuf[logIt->second._msgpos] = 0; else logIt->second._msgbuf[logIt->second._msgpos-1] = 0; writeLog(c == '\n'); //reset buffer logIt->second._msgpos = 0; return c; } if (logIt->second._msgpos < (int)(sizeof(logIt->second._msgbuf) - 1)) logIt->second._msgbuf[logIt->second._msgpos++] = c; } return c; } void AppLog::error(const char *format, ...) { va_list args; Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return; error(); if (!logIt->second._enable) return; overflow(EOF); va_start(args, format); logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0'; logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args); if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1; overflow(EOF); if (logIt->second._slogEnable) slog.error(logIt->second._msgbuf); va_end(args); } } void AppLog::warn(const char *format, ...) { va_list args; Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return; warn(); if (!logIt->second._enable) return; overflow(EOF); va_start(args, format); logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0'; logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args); if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1; overflow(EOF); if (logIt->second._slogEnable) slog.warn(logIt->second._msgbuf); va_end(args); } } void AppLog::debug(const char *format, ...) { va_list args; Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return; debug(); if (!logIt->second._enable) return; overflow(EOF); va_start(args, format); logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0'; logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args); if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1; overflow(EOF); va_end(args); } } void AppLog::emerg(const char *format, ...) { va_list args; Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return; emerg(); if (!logIt->second._enable) return; overflow(EOF); va_start(args, format); logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0'; logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args); if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1; overflow(EOF); if (logIt->second._slogEnable) slog.emerg(logIt->second._msgbuf); va_end(args); } } void AppLog::alert(const char *format, ...) { va_list args; Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return; alert(); if (!logIt->second._enable) return; overflow(EOF); va_start(args, format); logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0'; logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args); if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1; overflow(EOF); if (logIt->second._slogEnable) slog.alert(logIt->second._msgbuf); va_end(args); } } void AppLog::critical(const char *format, ...) { va_list args; Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return; critical(); if (!logIt->second._enable) return; overflow(EOF); va_start(args, format); logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0'; logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args); if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1; overflow(EOF); if (logIt->second._slogEnable) slog.critical(logIt->second._msgbuf); va_end(args); } } void AppLog::notice(const char *format, ...) { va_list args; Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return; notice(); if (!logIt->second._enable) return; overflow(EOF); va_start(args, format); logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0'; logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args); if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1; overflow(EOF); if (logIt->second._slogEnable) slog.notice(logIt->second._msgbuf); va_end(args); } } void AppLog::info(const char *format, ...) { va_list args; Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return; info(); if (!logIt->second._enable) return; overflow(EOF); va_start(args, format); logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0'; logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args); if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1; overflow(EOF); va_end(args); } } AppLog &AppLog::operator()(Slog::Level lev) { Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return *this; // needed? overflow(EOF); // enables log Slog::Level th_lev = logIt->second._level; logIt->second._enable = (th_lev >= lev); // is there a log level per module? if (!logIt->second._ident.empty()) { std::string st = logIt->second._ident; IdentLevel::iterator idLevIt = d->_identLevel.find(st); if (idLevIt != d->_identLevel.end()) { th_lev = idLevIt->second; logIt->second._enable = (th_lev >= lev); } } logIt->second._priority = lev; } return *this; } AppLog &AppLog::operator()(const char *ident, Slog::Level lev) { Thread *pThr = getThread(); if (pThr) { cctid_t tid = pThr->getId(); LogPrivateData::iterator logIt = d->_logs.find(tid); if (logIt == d->_logs.end()) return this->operator()(lev); logIt->second._enable = true; open(ident); } return this->operator()(lev); } AppLog& AppLog::operator<< (AppLog& (*pfManipulator)(AppLog&)) { return (*pfManipulator)(*this); } AppLog& AppLog::operator<< (ostream& (*pfManipulator)(ostream&)) { (*pfManipulator)(polyreference_cast(this)); return reference_cast(this) ; } } #endif commoncpp-7.0.1/commoncpp/dccp.cpp000066400000000000000000000422431411242573100171270ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include #include #include #ifdef _MSWINDOWS_ #include #define _IOLEN64 (unsigned) #define _IORET64 (int) typedef int socklen_t; #define socket_errno WSAGetLastError() #else #include #include #ifdef HAVE_NET_IP6_H #include #endif #define socket_errno errno # ifndef O_NONBLOCK # define O_NONBLOCK O_NDELAY # endif # ifdef IPPROTO_IP # ifndef SOL_IP # define SOL_IP IPPROTO_IP # endif // !SOL_IP # endif // IPPROTO_IP #endif // !WIN32 #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK (unsigned long)0x7f000001 #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_FILIO_H #include #endif #if defined(__hpux) #define _XOPEN_SOURCE_EXTENDED #endif #ifdef HAVE_NET_IF_H #include #endif #ifndef _IOLEN64 #define _IOLEN64 #endif #ifndef _IORET64 #define _IORET64 #endif namespace ost { DCCPSocket::DCCPSocket(Family fam) : Socket(fam, SOCK_DCCP, IPPROTO_DCCP) { family = fam; } DCCPSocket::DCCPSocket(DCCPSocket& server, timeout_t timeout) : Socket(accept(server.so, NULL, NULL)) { family = server.family; Socket::state = CONNECTED; socklen_t alen = sizeof(peer); getpeername(so, (struct sockaddr *)&peer, &alen); switch(family) { #ifdef CCXX_IPV6 case IPV6: if(!server.onAccept(IPV6Host(peer.ipv6.sin6_addr), peer.ipv6.sin6_port)) endSocket(); break; #endif case IPV4: if(!server.onAccept(IPV4Host(peer.ipv4.sin_addr), peer.ipv4.sin_port)) endSocket(); break; } } #ifdef HAVE_GETADDRINFO DCCPSocket::DCCPSocket(const char *name, Family fam, unsigned backlog) : Socket(fam, SOCK_DCCP, IPPROTO_DCCP) { char namebuf[128], *cp; struct addrinfo hint, *list = NULL, *first; snprintf(namebuf, sizeof(namebuf), "%s", name); cp = strrchr(namebuf, '/'); if(!cp) cp = strrchr(namebuf, ':'); if(!cp) { cp = namebuf; name = NULL; } else { name = namebuf; *(cp++) = 0; if(!strcmp(name, "*")) name = NULL; } family = fam; memset(&hint, 0, sizeof(hint)); hint.ai_family = family; hint.ai_socktype = SOCK_DCCP; hint.ai_protocol = IPPROTO_DCCP; hint.ai_flags = AI_PASSIVE; if(getaddrinfo(name, cp, &hint, &list) || !list) { endSocket(); error(errBindingFailed, (char *)"Could not find service", errno); return; } #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif first = list; while(list) { if(!bind(so, list->ai_addr, (socklen_t)list->ai_addrlen)) { state = BOUND; break; } list = list->ai_next; } freeaddrinfo(first); if(state != BOUND) { endSocket(); error(errBindingFailed,(char *)"Could not bind socket",socket_errno); return; } if(listen(so, backlog)) { endSocket(); error(errBindingFailed,(char *)"Could not listen on socket",socket_errno); return; } } #else DCCPSocket::DCCPSocket(const char *name, Family fam, unsigned backlog) : Socket(fam, SOCK_DCCP, IPPROTO_DCCP) { char namebuf[128], *cp; struct sockaddr_in addr; #ifdef CCXX_IPV6 struct sockaddr_in6 addr6; #endif struct sockaddr *ap = NULL; socklen_t alen = 0; struct servent *svc; family = fam; memset(&addr, 0, sizeof(addr)); snprintf(namebuf, sizeof(namebuf), "%s", name); cp = strrchr(namebuf, '/'); if(!cp) cp = strrchr(namebuf, ':'); if(!cp) { cp = namebuf; name = "*"; } else { name = namebuf; *(cp++) = 0; } addr.sin_family = family; if(isdigit(*cp)) addr.sin_port = htons(atoi(cp)); else { svc = getservbyname(cp, "dccp"); if(svc) addr.sin_port = svc->s_port; if(!svc) { endSocket(); error(errBindingFailed, "Could not find service", errno); return; } } #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif switch(family) { #ifdef CCXX_IPV6 case IPV6: { IPV6Address ia6(name); addr6.sin6_port = addr.sin_port; addr6.sin6_family = family; addr6.sin6_addr = getaddress(ia6); ap = (struct sockaddr *)&addr6; alen = sizeof(addr6); break; } #endif case IPV4: IPV4Address ia(name); addr.sin_addr = getaddress(ia); ap = (struct sockaddr *)&addr; alen = sizeof(addr); break; } if(!ap || bind(so, (struct sockaddr *)ap, alen)) { endSocket(); error(errBindingFailed,(char *)"Could not bind socket",socket_errno); return; } if(listen(so, backlog)) { endSocket(); error(errBindingFailed,(char *)"Could not listen on socket", socket_errno); return; } state = BOUND; } #endif DCCPSocket::DCCPSocket(const IPV4Address &ia, in_port_t port, unsigned backlog) : Socket(AF_INET, SOCK_DCCP, IPPROTO_DCCP) { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr = getaddress(ia); addr.sin_port = htons(port); family = IPV4; memset(&peer, 0, sizeof(peer)); peer.ipv4 = addr; #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif if(bind(so, (struct sockaddr *)&addr, sizeof(addr))) { endSocket(); error(errBindingFailed,(char *)"Could not bind socket",socket_errno); return; } if(listen(so, backlog)) { endSocket(); error(errBindingFailed,(char *)"Could not listen on socket",socket_errno); return; } state = BOUND; } #ifdef CCXX_IPV6 DCCPSocket::DCCPSocket(const IPV6Address &ia, in_port_t port, unsigned backlog) : Socket(AF_INET6, SOCK_DCCP, IPPROTO_DCCP) { struct sockaddr_in6 addr; memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_addr = getaddress(ia); addr.sin6_port = htons(port); family = IPV6; memset(&peer, 0, sizeof(peer)); peer.ipv6 = addr; #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif if(bind(so, (struct sockaddr *)&addr, sizeof(addr))) { endSocket(); error(errBindingFailed,(char *)"Could not bind socket",socket_errno); return; } if(listen(so, backlog)) { endSocket(); error(errBindingFailed,(char *)"Could not listen on socket",socket_errno); return; } state = BOUND; } bool DCCPSocket::onAccept(const IPV6Host &ia, in_port_t port) { return true; } #endif bool DCCPSocket::onAccept(const IPV4Host &ia, in_port_t port) { return true; } IPV4Host DCCPSocket::getIPV4Sender(in_port_t *port) const { if(port) *port = ntohs(peer.ipv4.sin_port); return IPV4Host(peer.ipv4.sin_addr); } #ifdef CCXX_IPV6 IPV6Host DCCPSocket::getIPV6Sender(in_port_t *port) const { return IPV6Host(peer.ipv6.sin6_addr); } #endif DCCPSocket::~DCCPSocket() { endSocket(); } void DCCPSocket::disconnect(void) { if(Socket::state != CONNECTED) return; endSocket(); so = socket(family, SOCK_DCCP, IPPROTO_DCCP); if(so != INVALID_SOCKET) Socket::state = AVAILABLE; } #ifdef HAVE_GETADDRINFO void DCCPSocket::connect(const char *target) { char namebuf[128]; char *cp; struct addrinfo hint, *list = NULL, *next, *first; bool connected = false; snprintf(namebuf, sizeof(namebuf), "%s", target); cp = strrchr(namebuf, '/'); if(!cp) cp = strrchr(namebuf, ':'); if(!cp) { connectError(); return; } *(cp++) = 0; memset(&hint, 0, sizeof(hint)); hint.ai_family = family; hint.ai_socktype = SOCK_DCCP; hint.ai_protocol = IPPROTO_DCCP; if(getaddrinfo(namebuf, cp, &hint, &list) || !list) { connectError(); return; } first = list; while(list) { if(!::connect(so, list->ai_addr, (socklen_t)list->ai_addrlen)) { connected = true; break; } next = list->ai_next; list = next; } freeaddrinfo(first); if(!connected) { connectError(); return; } Socket::state = CONNECTED; } #else void DCCPSocket::connect(const char *target) { char namebuf[128]; char *cp; struct servent *svc; in_port_t port; snprintf(namebuf, sizeof(namebuf), "%s", target); cp = strrchr(namebuf, '/'); if(!cp) cp = strrchr(namebuf, ':'); if(!cp) { connectError(); return; } *(cp++) = 0; if(isdigit(*cp)) port = atoi(cp); else { svc = getservbyname(cp, "dccp"); if(svc) port = ntohs(svc->s_port); if(!svc) { connectError(); return; } } switch(family) { case IPV4: connect(IPV4Host(namebuf), port); break; #ifdef CCXX_IPV6 case IPV6: connect(IPV6Host(namebuf), port); break; #endif default: connectError(); } } #endif void DCCPSocket::connect(const IPV4Host &host, in_port_t port, timeout_t timeout) { size_t i; fd_set fds; struct timeval to; bool connected = false; int rtn; int sockopt; socklen_t len = sizeof(sockopt); for(i = 0 ; i < host.getAddressCount(); i++) { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr = host.getAddress(i); addr.sin_port = htons(port); if(timeout) setCompletion(false); // Win32 will crash if you try to connect to INADDR_ANY. if ( INADDR_ANY == addr.sin_addr.s_addr ) addr.sin_addr.s_addr = INADDR_LOOPBACK; rtn = ::connect(so, (struct sockaddr *)&addr, (socklen_t)sizeof(addr)); if(!rtn) { connected = true; break; } #ifndef _MSWINDOWS_ if(errno == EINPROGRESS) #else if(WSAGetLastError() == WSAEINPROGRESS) #endif { FD_ZERO(&fds); FD_SET(so, &fds); to.tv_sec = timeout / 1000; to.tv_usec = timeout % 1000 * 1000; // timeout check for connect completion if(::select((int)so + 1, NULL, &fds, NULL, &to) < 1) continue; getsockopt(so, SOL_SOCKET, SO_ERROR, (char *)&sockopt, &len); if(!sockopt) { connected = true; break; } endSocket(); so = socket(AF_INET, SOCK_DCCP, IPPROTO_DCCP); if(so == INVALID_SOCKET) break; } } setCompletion(true); if(!connected) { rtn = errno; errno = rtn; connectError(); return; } Socket::state = CONNECTED; } #ifdef CCXX_IPV6 void DCCPSocket::connect(const IPV6Host &host, in_port_t port, timeout_t timeout) { size_t i; fd_set fds; struct timeval to; bool connected = false; int rtn; int sockopt; socklen_t len = sizeof(sockopt); for(i = 0 ; i < host.getAddressCount(); i++) { struct sockaddr_in6 addr; memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_addr = host.getAddress(i); addr.sin6_port = htons(port); if(timeout) setCompletion(false); // Win32 will crash if you try to connect to INADDR_ANY. if ( !memcmp(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any))) memcpy(&addr.sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback)); rtn = ::connect(so, (struct sockaddr *)&addr, (socklen_t)sizeof(addr)); if(!rtn) { connected = true; break; } #ifndef _MSWINDOWS_ if(errno == EINPROGRESS) #else if(WSAGetLastError() == WSAEINPROGRESS) #endif { FD_ZERO(&fds); FD_SET(so, &fds); to.tv_sec = timeout / 1000; to.tv_usec = timeout % 1000 * 1000; // timeout check for connect completion if(::select((int)so + 1, NULL, &fds, NULL, &to) < 1) continue; getsockopt(so, SOL_SOCKET, SO_ERROR, (char *)&sockopt, &len); if(!sockopt) { connected = true; break; } endSocket(); so = socket(AF_INET6, SOCK_DCCP, IPPROTO_DCCP); if(so == INVALID_SOCKET) break; } } setCompletion(true); if(!connected) { rtn = errno; errno = rtn; connectError(); return; } Socket::state = CONNECTED; } #endif bool DCCPSocket::setCCID(uint8_t ccid) { uint8_t ccids[16]; /* for getting the available CCIDs, should be large enough */ socklen_t len = sizeof(ccids); int ret; bool ccid_supported = false; /* * Determine which CCIDs are available on the host */ ret = getsockopt(so, SOL_DCCP, DCCP_SOCKOPT_AVAILABLE_CCIDS, (char *)&ccids, &len); if (ret < 0) { error(errInput,(char *)"Can not determine available CCIDs",socket_errno); return false; } for (unsigned i = 0; i < sizeof(ccids); i++) { if (ccid == ccids[i]) { ccid_supported = true; break; } } if (!ccid_supported) { error(errInput,(char *)"CCID specified is not supported",socket_errno); return false; } if (setsockopt(so, SOL_DCCP, DCCP_SOCKOPT_CCID, (char *)&ccid, sizeof (ccid)) < 0) { error(errInput,(char *)"Can not set CCID",socket_errno); return false; } return true; } int DCCPSocket::getTxCCID() const { int ccid, ret; socklen_t ccidlen; ccidlen = sizeof(ccid); ret = getsockopt(so, SOL_DCCP, DCCP_SOCKOPT_TX_CCID, (char *)&ccid, &ccidlen); if (ret < 0) { error(errInput,(char *)"Can not determine get current TX CCID value",socket_errno); return -1; } return ccid; } int DCCPSocket::getRxCCID() const { int ccid, ret; socklen_t ccidlen; ccidlen = sizeof(ccid); ret = getsockopt(so, SOL_DCCP, DCCP_SOCKOPT_RX_CCID, (char *)&ccid, &ccidlen); if (ret < 0) { error(errInput,(char *)"Can not determine get current DX CCID value",socket_errno); return -1; } return ccid; } size_t DCCPSocket::available() const { size_t readsize = 0; #ifndef _MSWINDOWS_ if (ioctl (so, FIONREAD, &readsize) < 0) { error(errInput,(char *)"Error on retrieve the FIONREAD option.",socket_errno); } #else if (ioctlsocket(so, FIONREAD, (u_long *)&readsize)){ error(errInput,(char *)"Error on retrieve the FIONREAD option.",socket_errno); } #endif return readsize; } } // namespace ost commoncpp-7.0.1/commoncpp/dir.cpp000066400000000000000000000202601411242573100167670ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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 _MSC_VER #include #endif // needed for GNU/LINUX glibc otherwise pread/pwrite wont work #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 600 #endif /* * on old glibc's, this has to be * defined explicitly */ #ifndef _XOPEN_SOURCE_EXTENDED #define _XOPEN_SOURCE_EXTENDED #endif #include #include #include #include #include #include #include #ifdef _MSWINDOWS_ #include #include #endif namespace ost { using namespace std; Dir::Dir(const char *fname) : #ifdef _MSWINDOWS_ hDir(INVALID_HANDLE_VALUE), name(NULL) #else dir(NULL) #endif { #ifdef HAVE_READDIR_R save = reinterpret_cast(save_space); #endif if(fname) open(fname); } bool Dir::create(const char *path, Attr attr) { bool rtn = true; #ifdef _MSWINDOWS_ // fixme: make it form a security attributes structure if(!CreateDirectory(path, NULL)) rtn = false; #else long xmask = 0; switch(attr) { case attrPublic: xmask |= S_IXOTH; case attrGroup: xmask |= S_IXGRP; case attrPrivate: xmask |= S_IXUSR; break; default: return false; } if(mkdir(path, (long)attr | xmask)) rtn = false; #endif return rtn; } bool Dir::remove(const char *path) { bool rtn = true; #ifdef _MSWINDOWS_ if(!RemoveDirectory(path)) rtn = false; #else if(rmdir(path)) rtn = false; #endif return rtn; } bool Dir::setPrefix(const char *prefix) { bool rtn = true; #ifdef _MSWINDOWS_ if(!SetCurrentDirectory(prefix)) rtn = false; #else if(chdir(prefix)) rtn = false; #endif return rtn; } bool Dir::getPrefix(char *prefix, size_t size) { bool rtn = true; #ifdef _MSWINDOWS_ if(!GetCurrentDirectory((DWORD)size, prefix)) rtn = false; #else if(getcwd(prefix, size) == NULL) rtn = false; #endif return rtn; } void Dir::open(const char *fname) { #ifdef _MSWINDOWS_ size_t len = strlen(fname) + 4; char *path; #endif close(); #ifdef _MSWINDOWS_ DWORD attr = GetFileAttributes(fname); if( (attr == (DWORD)~0l) || !(attr & FILE_ATTRIBUTE_DIRECTORY) ) { #ifdef CCXX_EXCEPTIONS if(Thread::getException() == Thread::throwObject) throw(this); #ifdef COMMON_STD_EXCEPTION else if(Thread::getException() == Thread::throwException) throw(DirException(String(fname) + ": failed")); #endif #endif } path = (char *)_malloca(len + 1); if(path) snprintf(path, len + 1, "%s", fname); #ifdef CCXX_EXCEPTIONS if (!path && Thread::getException() == Thread::throwObject) throw(this); #ifdef COMMON_STD_EXCEPTION else if(!path && Thread::getException() == Thread::throwException) throw(DirException(String(fname) + ": failed")); #endif #endif if (!path || !path[0]) return; addString(path, len, "\\*"); hDir = FindFirstFile(path, &fdata); if(hDir != INVALID_HANDLE_VALUE) name = fdata.cFileName; memcpy(&data, &fdata, sizeof(fdata)); #else // WIN32 entry = NULL; dir = opendir(fname); #ifdef CCXX_EXCEPTIONS if(!dir && Thread::getException() == Thread::throwObject) throw(this); #ifdef COMMON_STD_EXCEPTION else if(!dir && Thread::getException() == Thread::throwException) throw(DirException(String(fname) + ": failed")); #endif #endif #endif // WIN32 } Dir::~Dir() { close(); } void Dir::close(void) { #ifdef _MSWINDOWS_ if(hDir != INVALID_HANDLE_VALUE) FindClose(hDir); hDir = INVALID_HANDLE_VALUE; #else if(dir) closedir(dir); dir = NULL; entry = NULL; #endif } bool Dir::rewind(void) { bool rtn = true; #ifdef _MSWINDOWS_ memcpy(&data, &fdata, sizeof(data)); name = fdata.cFileName; #else if(!dir) rtn = false; else rewinddir(dir); #endif return rtn; } bool Dir::isValid(void) const { #ifdef _MSWINDOWS_ if(hDir == INVALID_HANDLE_VALUE) #else if(!dir) #endif return false; return true; } const char *Dir::operator*() { #ifdef _MSWINDOWS_ return name; #else if(!dir) return NULL; if(!entry) return getName(); return entry->d_name; #endif } const char *Dir::getName(void) { #ifdef _MSWINDOWS_ char *retname = name; if(hDir == INVALID_HANDLE_VALUE) return NULL; if(retname) { name = NULL; if(FindNextFile(hDir, &data)) name = data.cFileName; } return retname; #else if(!dir) return NULL; #ifdef HAVE_READDIR_R readdir_r(dir, save, &entry); #else entry = readdir(dir); #endif if(!entry) return NULL; return entry->d_name; #endif // WIN32 } DirTree::DirTree(const char *prefix, unsigned depth) { max = ++depth; dir = new Dir[depth]; current = 0; open(prefix); } DirTree::DirTree(unsigned depth) { max = ++depth; dir = new Dir[depth]; current = 0; } void DirTree::open(const char *prefix) { char *cp; close(); if(!isDir(prefix)) return; snprintf(path, sizeof(path), "%s/", prefix); prefixpos = (unsigned)strlen(path) - 1; while(NULL != (cp = strchr(path, '\\'))) *cp = '/'; while(prefixpos && path[prefixpos - 1] == '/') path[prefixpos--] = 0; dir[current++].open(prefix); } DirTree::~DirTree() { close(); if(dir) delete[] dir; dir = NULL; } unsigned DirTree::perform(const char *prefix) { unsigned count = 0; open(prefix); while(NULL != (getPath())) ++count; close(); return count; } void DirTree::close(void) { while(current--) dir[current].close(); current = 0; } bool DirTree::filter(const char *fpath, struct stat *ino) { fpath = strrchr(path, '/'); if(fpath) ++fpath; else return false; if(!strcmp(fpath, ".")) return false; if(!strcmp(fpath, "..")) return false; if(!ino) return false; return true; } char *DirTree::getPath(void) { char *cp; const char *name; struct stat ino; bool flag; while(current) { cp = strrchr(path, '/'); name = dir[current - 1].getName(); if(!name) { *cp = 0; dir[--current].close(); continue; } snprintf(cp + 1, sizeof(path) - strlen(path) - 2, "%s", name); if(::stat(path, &ino)) { ino.st_mode = 0; flag = filter(path, NULL); } else flag = filter(path, &ino); if(!flag) continue; if((ino.st_mode & S_IFMT) == S_IFDIR) { if(!canAccess(path)) break; if(current < max) dir[current++].open(path); snprintf(path + strlen(path), sizeof(path) - strlen(path), "/"); } break; } if(!current) return NULL; return path; } } // end namespace commoncpp-7.0.1/commoncpp/dso.cpp000066400000000000000000000200211411242573100167710ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include #include #include #include #if defined(HAVE_DLFCN_H) extern "C" { #include } #ifndef RTLD_GLOBAL #define RTLD_GLOBAL 0 #endif #endif // HAVE_DLFN_H #ifdef HAVE_SHL_LOAD #include #endif #ifdef HAVE_MACH_O_DYLD_H #include #define oModule ((oModule)(image)) #endif #ifdef _MSWINDOWS_ #define hImage ((HMODULE)(image)) #endif namespace ost { DSO *DSO::first = NULL; DSO *DSO::last = NULL; Mutex DSO::mutex; void DSO::dynunload(void) { while (last) { DSO *prev = last->prev; delete last; last = prev; } last = first = NULL; } DSO::~DSO() { #if defined(HAVE_MACH_DYLD) NSSymbol sym; void (*fini)(void); #endif MutexLock lock(mutex); #if defined(_MSWINDOWS_) if(image) FreeLibrary(hImage); #elif defined(HAVE_MACH_DYLD) if(image == NULL) return; sym = NSLookupSymbolInModule(oModule, "__fini"); if(sym != NULL) { fini = (void (*)(void))NSAddressOfSymbol(sym); fini(); } NSUnLinkModule(oModule, NSUNLINKMODULE_OPTION_NONE); #elif defined(HAVE_SHL_LOAD) if(image) shl_unload(image); #elif defined(HAVE_DLFCN_H) if(image) dlclose(image); #endif if(first == this && last == this) first = last = NULL; if(!next && !prev) return; if(prev) prev->next = next; if(next) next->prev = prev; if(first == this) first = next; if(last == this) last = prev; } void DSO::loader(const char *filename, bool flag) { #if defined(HAVE_MACH_DYLD) NSObjectFileImage oImage; NSSymbol sym = NULL; void (*init)(void); #endif id = strrchr(filename, '/'); if(id) ++id; else id = filename; next = prev = NULL; #if defined(_MSWINDOWS_) image = LoadLibrary(filename); err = "none"; #elif defined(HAVE_MACH_DYLD) err = "none"; image = NULL; switch(NSCreateObjectFileImageFromFile(filename, &oImage)) { case NSObjectFileImageSuccess: break; default: err = "unknown error"; return; } if(flag) image = NSLinkModule(oImage, filename, NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_RETURN_ON_ERROR); else image = NSLinkModule(oImage, filename, NSLINKMODULE_OPTION_RETURN_ON_ERROR); NSDestroyObjectFileImage(oImage); if(oModule != NULL) sym = NSLookupSymbolInModule(oModule, "__init"); if(sym) { init = (void (*)(void))NSAddressOfSymbol(sym); init(); } #elif defined(HAVE_SHL_LOAD) err = "none"; if(flag) image = shl_load(filename, BIND_IMMEDIATE, 0L); else image = shl_load(filename, BIND_DEFERRED, 0L); #elif defined(HAVE_DLFCN_H) if(flag) image = dlopen(filename, RTLD_NOW | RTLD_GLOBAL); else image = dlopen(filename, RTLD_LAZY | RTLD_GLOBAL); #endif #if defined(_MSWINDOWS_) if(!image) { err = "load failed"; #elif defined(HAVE_MACH_DYLD) if(image == NULL) { err = "load failed"; #elif defined(HAVE_SHL_LOAD) if(!image) { err = "load failed"; #elif defined(HAVE_DLFCN_H) if(!image) { err = dlerror(); #else if(1) { err = "load unsupported"; #endif // since generally failure to map or load a plugin is fatel in most // cases, we should generally log the error to syslog as well as notify // the upper level system of the failure through exception. slog.error() << "dso: " << id << ": " << err << std::endl; #ifdef CCXX_EXCEPTIONS if(Thread::getException() == Thread::throwObject) throw(this); #ifdef COMMON_STD_EXCEPTION else if(Thread::getException() == Thread::throwException) throw(DSOException(String(id) + err)); #endif #endif return; } if(!last) { last = first = this; return; } mutex.enterMutex(); last->next = this; prev = last; last = this; mutex.leaveMutex(); } DSO *DSO::getObject(const char *id) { const char *chk = strrchr(id, '/'); DSO *dso; if(chk) ++chk; else chk = id; mutex.enterMutex(); dso = first; while(dso) { if(!stricmp(dso->id, chk)) break; dso = dso->next; } mutex.leaveMutex(); return dso; } bool DSO::isValid(void) { #if defined(_MSWINDOWS_) if(!image) #elif defined(HAVE_MACH_DYLD) if(image == NULL) #else if(!image) #endif return false; return true; } DSO::addr_t DSO::operator[](const char *sym) { #if defined(HAVE_SHL_LOAD) int value; shl_t handle = (shl_t)image; if(shl_findsym(&handle, sym, 0, &value) == 0) return (DSO::addr_t)value; else return NULL; #elif defined(HAVE_MACH_DYLD) NSSymbol oSymbol = NSLookupSymbolInModule(oModule, sym); if(oSymbol) return (DSO::addr_t)NSAddressOfSymbol(oSymbol); else return (DSO::addr_t)NULL; #elif defined(_MSWINDOWS_) DSO::addr_t addr = (DSO::addr_t)GetProcAddress(hImage, sym); if(!addr) err = "symbol missing"; return addr; #elif defined(HAVE_DLFCN_H) return (DSO::addr_t)dlsym(image, (char *)sym); #else return (DSO::addr_t)NULL; #endif } #ifdef HAVE_MACH_DYLD static void MyLinkError(NSLinkEditErrors c, int errorNumber, const char *filename, const char *errstr) { slog.error() << "dyld: " << filename << ": " << errstr << std::endl; } static void MyUndefined(const char *symname) { slog.error() << "dyld: undefined: " << symname << std::endl; } static NSModule MyMultiple(NSSymbol s, NSModule oMod, NSModule nMod) { slog.error() << "dyld: multiply defined symbols" << std::endl; } void DSO::setDebug(void) { static NSLinkEditErrorHandlers handlers = { &MyUndefined, &MyMultiple, &MyLinkError}; NSInstallLinkEditErrorHandlers(&handlers); } #else void DSO::setDebug(void) { } #endif } // namespace ost commoncpp-7.0.1/commoncpp/exception.cpp000066400000000000000000000073641411242573100202210ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 600 #endif #include #include #include #include #include #if defined(CCXX_EXCEPTIONS) namespace ost { Exception::Exception(const String& what_arg) throw(): _what(what_arg) {} Exception::~Exception() throw() {} const char *Exception::what() const throw() { return _what.c_str(); } const char *Exception::getString() const { return _what.c_str(); } IOException::IOException(const String &what_arg, long systemError) throw() : Exception(what_arg), _systemError(systemError), _systemErrorString(NULL) { } IOException::~IOException() throw() { delete [] _systemErrorString; } long IOException::getSystemError() const throw() { return _systemError; } const char* IOException::getSystemErrorString() const throw() { const uint32_t errStrSize = 2048; if ( !_systemErrorString ) _systemErrorString = new char[errStrSize]; #ifndef _MSWINDOWS_ #ifdef HAVE_STRERROR_R #if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined(_GNU_SOURCE) || !defined(APPLE)) assert(strerror_r(_systemError, _systemErrorString, errStrSize) == 0); #else _systemErrorString = strerror_r(_systemError, _systemErrorString, errStrSize); #endif #else static Mutex mlock; mlock.enter(); String::set(_systemErrorString, errStrSize, strerror(_systemError)); mlock.leave(); #endif return _systemErrorString; #else FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, _systemError, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), _systemErrorString, errStrSize, NULL); return _systemErrorString; #endif } } // namespace ost #endif commoncpp-7.0.1/commoncpp/file.cpp000066400000000000000000001022711411242573100171330ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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 _MSC_VER #include #endif // needed for GNU/LINUX glibc otherwise pread/pwrite wont work #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 600 #endif /* * on old glibc's, this has to be * defined explicitly */ #ifndef _XOPEN_SOURCE_EXTENDED #define _XOPEN_SOURCE_EXTENDED #endif #include // broken BSD; XOPEN should not imply _POSIX_C_SOURCE, // _POSIX_C_SOURCE should not stop __BSD_VISIBLE #include #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_FILE_H #include #endif #ifdef HAVE_SYS_LOCKF_H #include #endif #include #include #include #include #include #include #ifdef __BORLANDC__ #include #include #else #include #include #endif #include #include #ifndef _MSWINDOWS_ #ifdef COMMON_AIX_FIXES #undef LOCK_EX #undef LOCK_SH #endif #if defined(MACOSX) || defined(__ANDROID__) #define MISSING_LOCKF #endif #ifndef F_LOCK #define MISSING_LOCKF enum { F_ULOCK = 1, F_LOCK, F_TLOCK, F_TEST }; #endif #if defined(MISSING_LOCKF) #define lockf(a, b, c) flock(a, b) #endif #endif // ndef WIN32 #if defined(_OSF_SOURCE) && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE > 1 #undef LOCK_EX #undef LOCK_SH #endif #if 0 /* * not used anymore ? (hen) */ static const char *clearfile(const char *pathname) { remove(pathname); return pathname; } static const char *clearfifo(const char *pathname, int mode) { remove(pathname); mkfifo(pathname, mode); return pathname; } #endif namespace ost { RandomFile::RandomFile(const char *name) : Mutex() { #ifdef _MSWINDOWS_ fd = INVALID_HANDLE_VALUE; // immediate is not defined on Win32 #else fd = -1; flags.immediate = false; #endif flags.thrown = flags.initial = flags.temp = false; flags.count = 0; pathname = NULL; } RandomFile::RandomFile(const RandomFile &rf) : Mutex() { // first, `dup'-licate the file descriptor/handle #ifdef _MSWINDOWS_ HANDLE pidHandle = GetCurrentProcess(); HANDLE dupHandle; if(rf.fd != INVALID_HANDLE_VALUE) { if(!DuplicateHandle(pidHandle, rf.fd, pidHandle, &dupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) fd = INVALID_HANDLE_VALUE; else fd = dupHandle; } else fd = INVALID_HANDLE_VALUE; #else if(rf.fd > -1) fd = dup(rf.fd); else fd = -1; #endif flags = rf.flags; flags.count = 0; if(rf.pathname) pathname = newString(rf.pathname); else pathname = NULL; } RandomFile::~RandomFile() { final(); } File::Error RandomFile::restart(void) { return errOpenFailed; } File::Attr RandomFile::initialize(void) { return attrPublic; } void RandomFile::final(void) { #ifdef _MSWINDOWS_ if(fd != INVALID_HANDLE_VALUE) { CloseHandle(fd); if(flags.temp && pathname) DeleteFile(pathname); } #else if(fd > -1) { close(fd); if(flags.temp && pathname) remove(pathname); } #endif if(pathname) { delString(pathname); pathname = NULL; } #ifdef _MSWINDOWS_ fd = INVALID_HANDLE_VALUE; #else fd = -1; #endif flags.count = 0; flags.initial = false; } RandomFile::Error RandomFile::error(Error id, char *str) { errstr = str; errid = id; if(!flags.thrown) { flags.thrown = true; #ifdef CCXX_EXCEPTIONS if(Thread::getException() == Thread::throwObject) throw(this); #ifdef COMMON_STD_EXCEPTION else if(Thread::getException() == Thread::throwException) { if(!str) str = (char *)""; throw FileException(str); } #endif #endif } return id; } bool RandomFile::initial(void) { bool init; #ifdef _MSWINDOWS_ if(fd == INVALID_HANDLE_VALUE) #else if(fd < 0) #endif return false; enterMutex(); init = flags.initial; flags.initial = false; if(!init) { leaveMutex(); return false; } #ifdef _MSWINDOWS_ Attr access = initialize(); if(access == attrInvalid) { CloseHandle(fd); if(pathname) DeleteFile(pathname); fd = INVALID_HANDLE_VALUE; leaveMutex(); error(errInitFailed); return false; } #else int mode = (int)initialize(); if(!mode) { close(fd); fd = -1; if(pathname) remove(pathname); leaveMutex(); error(errInitFailed); return false; } fchmod(fd, mode); #endif leaveMutex(); return init; } #ifndef _MSWINDOWS_ RandomFile::Error RandomFile::setCompletion(Complete mode) { long flag = fcntl(fd, F_GETFL); if(fd < 0) return errNotOpened; flags.immediate = false; #ifdef O_SYNC flag &= ~(O_SYNC | O_NONBLOCK); #else flag &= ~O_NONBLOCK; #endif switch(mode) { case completionImmediate: #ifdef O_SYNC flag |= O_SYNC; #endif flags.immediate = true; break; case completionDelayed: flag |= O_NONBLOCK; //completionDeferred: ? (hen) case completionDeferred: break; } fcntl(fd, F_SETFL, flag); return errSuccess; } #endif off_t RandomFile::getCapacity(void) { off_t eof, pos = 0; #ifdef _MSWINDOWS_ if(!fd) #else if(fd < 0) #endif return 0; enterMutex(); #ifdef _MSWINDOWS_ pos = SetFilePointer(fd, 0l, NULL, FILE_CURRENT); eof = SetFilePointer(fd, 0l, NULL, FILE_END); SetFilePointer(fd, pos, NULL, FILE_BEGIN); #else pos = lseek(fd, 0l, SEEK_CUR); eof = lseek(fd, 0l, SEEK_END); lseek(fd, pos, SEEK_SET); #endif leaveMutex(); return eof; } RandomFile::operator bool(void) const { #ifdef _MSWINDOWS_ return fd != INVALID_HANDLE_VALUE; #else if(fd < 0) return false; return true; #endif } bool RandomFile::operator!(void) const { #ifdef _MSWINDOWS_ return fd == INVALID_HANDLE_VALUE; #else if(fd < 0) return true; return false; #endif } SharedFile::SharedFile(const char *path) : RandomFile(path) { fcb.address = NULL; fcb.len = 0; fcb.pos = 0; open(path); } SharedFile::SharedFile(const SharedFile &sh) : RandomFile(sh) { } SharedFile::~SharedFile() { final(); } SharedFile::Error SharedFile::open(const char *path) { #ifdef _MSWINDOWS_ if(fd != INVALID_HANDLE_VALUE) #else if(fd > -1) #endif final(); if(path != pathname) { if(pathname) delString(pathname); pathname = newString(path); } flags.initial = false; #ifdef _MSWINDOWS_ fd = CreateFile(pathname, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); if(fd == INVALID_HANDLE_VALUE) { flags.initial = true; fd = CreateFile(pathname, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); } if(fd == INVALID_HANDLE_VALUE) return errOpenFailed; return errSuccess; #else fd = ::open(pathname, O_RDWR); if(fd < 0) { flags.initial = true; fd = ::open(pathname, O_CREAT | O_RDWR | O_TRUNC, (int)attrPrivate); } if(fd < 0) return error(errOpenFailed); #ifdef LOCK_SH if(::flock(fd, LOCK_SH | LOCK_NB)) { close(fd); fd = -1; return error(errOpenInUse); } #endif return errSuccess; #endif // WIN32 } SharedFile::Error SharedFile::fetch(caddr_t address, ccxx_size_t len, off_t pos) { #ifdef _MSWINDOWS_ if(fd == INVALID_HANDLE_VALUE) #else if(fd < 0) #endif return errNotOpened; enterMutex(); if(address) fcb.address = address; if(len) fcb.len = len; if(pos != -1) fcb.pos = pos; #ifdef _MSWINDOWS_ OVERLAPPED over; SetFilePointer(fd, fcb.pos, NULL, FILE_BEGIN); over.hEvent = 0; over.Offset = fcb.pos; over.OffsetHigh = 0; LockFileEx(fd, LOCKFILE_EXCLUSIVE_LOCK, 0, fcb.len, 0, &over); DWORD count; if(!ReadFile(fd, fcb.address, fcb.len, &count, NULL)) { leaveMutex(); return errReadFailure; } leaveMutex(); if(count < fcb.len) return errReadIncomplete; return errSuccess; #else lseek(fd, fcb.pos, SEEK_SET); if(lockf(fd, F_LOCK, fcb.len)) { leaveMutex(); return errLockFailure; } int io = ::read(fd, fcb.address, fcb.len); leaveMutex(); if((size_t) io == fcb.len) return errSuccess; if(io > -1) return errReadIncomplete; switch(errno) { case EINTR: return errReadInterrupted; default: return errReadFailure; } #endif } #ifndef _MSWINDOWS_ SharedFile::Error SharedFile::clear(ccxx_size_t len, off_t pos) { if(fd < 0) return errNotOpened; enterMutex(); if(len) fcb.len = len; if(pos != -1) fcb.pos = pos; lseek(fd, fcb.pos, SEEK_SET); if(lockf(fd, F_ULOCK, fcb.len)) { leaveMutex(); return errLockFailure; } leaveMutex(); return errSuccess; } #endif // ndef WIN32 SharedFile::Error SharedFile::update(caddr_t address, ccxx_size_t len, off_t pos) { #ifdef _MSWINDOWS_ if(fd == INVALID_HANDLE_VALUE) #else if(fd < 0) #endif return errNotOpened; enterMutex(); if(address) fcb.address = address; if(len) fcb.len = len; if(pos != -1) fcb.pos = pos; #ifdef _MSWINDOWS_ OVERLAPPED over; SetFilePointer(fd, fcb.pos, NULL, FILE_BEGIN); over.hEvent = 0; over.Offset = pos; over.OffsetHigh = 0; DWORD count; if(!WriteFile(fd, fcb.address, fcb.len, &count, NULL)) { SetFilePointer(fd, fcb.pos, NULL, FILE_CURRENT); UnlockFileEx(fd, 0, len, 0, &over); leaveMutex(); return errWriteFailure; } SetFilePointer(fd, fcb.pos, NULL, FILE_CURRENT); UnlockFileEx(fd, 0, len, 0, &over); leaveMutex(); if(count < fcb.len) return errWriteIncomplete; return errSuccess; #else lseek(fd, fcb.pos, SEEK_SET); int io = ::write(fd, fcb.address, fcb.len); if(lockf(fd, F_ULOCK, fcb.len)) { leaveMutex(); return errLockFailure; } leaveMutex(); if((size_t) io == fcb.len) return errSuccess; if(io > -1) return errWriteIncomplete; switch(errno) { case EINTR: return errWriteInterrupted; default: return errWriteFailure; } #endif // WIN32 } SharedFile::Error SharedFile::append(caddr_t address, ccxx_size_t len) { #ifdef _MSWINDOWS_ if(fd == INVALID_HANDLE_VALUE) #else if(fd < 0) #endif return errNotOpened; enterMutex(); if(address) fcb.address = address; if(len) fcb.len = len; #ifdef _MSWINDOWS_ fcb.pos = SetFilePointer(fd, 0l, NULL, FILE_END); OVERLAPPED over; over.hEvent = 0; over.Offset = fcb.pos; over.OffsetHigh = 0; LONG eof = fcb.pos; LockFileEx(fd, LOCKFILE_EXCLUSIVE_LOCK, 0, 0x7fffffff, 0, &over); fcb.pos = SetFilePointer(fd, 0l, NULL, FILE_END); DWORD count; if(!WriteFile(fd, fcb.address, fcb.len, &count, NULL)) { SetFilePointer(fd, eof, NULL, FILE_CURRENT); UnlockFileEx(fd, 0, 0x7fffffff, 0, &over); leaveMutex(); return errWriteFailure; } SetFilePointer(fd, eof, NULL, FILE_CURRENT); UnlockFileEx(fd, 0, 0x7fffffff, 0, &over); leaveMutex(); if(count < fcb.len) return errWriteIncomplete; return errSuccess; #else fcb.pos = lseek(fd, 0l, SEEK_END); if(lockf(fd, F_LOCK, -1)) { leaveMutex(); return errLockFailure; } fcb.pos = lseek(fd, 0l, SEEK_END); int io = ::write(fd, fcb.address, fcb.len); lseek(fd, fcb.pos, SEEK_SET); if(lockf(fd, F_ULOCK, -1)) { leaveMutex(); return errLockFailure; } leaveMutex(); if((size_t) io == fcb.len) return errSuccess; if(io > -1) return errWriteIncomplete; switch(errno) { case EINTR: return errWriteInterrupted; default: return errWriteFailure; } #endif // WIN32 } off_t SharedFile::getPosition(void) { return fcb.pos; } bool SharedFile::operator++(void) { off_t eof; enterMutex(); fcb.pos += fcb.len; #ifdef _MSWINDOWS_ eof = SetFilePointer(fd, 0l, NULL, FILE_END); #else eof = lseek(fd, 0l, SEEK_END); #endif if(fcb.pos >= eof) { fcb.pos = eof; leaveMutex(); return true; } leaveMutex(); return false; } bool SharedFile::operator--(void) { enterMutex(); fcb.pos -= fcb.len; if(fcb.pos <= 0) { fcb.pos = 0; leaveMutex(); return true; } leaveMutex(); return false; } size_t MappedFile::pageAligned(size_t size) { size_t pages = size / Process::getPageSize(); if(size % Process::getPageSize()) ++pages; return pages * Process::getPageSize(); } #ifdef _MSWINDOWS_ static void makemapname(const char *source, char *target) { unsigned count = 60; while(*source && count--) { if(*source == '/' || *source == '\\') *(target++) = '_'; else *(target++) = toupper(*source); ++source; } *target = 0; } MappedFile::MappedFile(const char *fname, Access mode, size_t size) : RandomFile(fname) { DWORD share = 0, page = 0; map = INVALID_HANDLE_VALUE; fcb.address = NULL; switch(mode) { case accessReadOnly: share = FILE_SHARE_READ; page = PAGE_READONLY; prot = FILE_MAP_READ; break; case accessWriteOnly: share = FILE_SHARE_WRITE; page = PAGE_WRITECOPY; prot = FILE_MAP_COPY; break; case accessReadWrite: share = FILE_SHARE_READ|FILE_SHARE_WRITE; page = PAGE_READWRITE; prot = FILE_MAP_WRITE; } if(share || page) fd = CreateFile(pathname, mode, share, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); else fd = INVALID_HANDLE_VALUE; if(fd == INVALID_HANDLE_VALUE) { error(errOpenFailed); return; } SetFilePointer(fd, (LONG)size, 0, FILE_BEGIN); SetEndOfFile(fd); makemapname(fname, mapname); map = CreateFileMapping(fd, NULL, page, 0, 0, mapname); if(!map) error(errMapFailed); else { fcb.address = (caddr_t)MapViewOfFile(map, prot, 0, 0, size); fcb.len = (ccxx_size_t)size; fcb.pos = 0; if (!fcb.address) error(errMapFailed); } } MappedFile::MappedFile(const char *fname, Access mode) : RandomFile(fname) { DWORD share = 0, page = 0; map = INVALID_HANDLE_VALUE; fcb.address = NULL; switch(mode) { case accessReadOnly: share = FILE_SHARE_READ; page = PAGE_READONLY; prot = FILE_MAP_READ; break; case accessWriteOnly: share = FILE_SHARE_WRITE; page = PAGE_WRITECOPY; prot = FILE_MAP_COPY; break; case accessReadWrite: share = FILE_SHARE_READ|FILE_SHARE_WRITE; page = PAGE_READWRITE; prot = FILE_MAP_WRITE; } if(share || page) fd = CreateFile(pathname, mode, share, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); else fd = INVALID_HANDLE_VALUE; if(fd == INVALID_HANDLE_VALUE) { error(errOpenFailed); return; } makemapname(fname, mapname); map = CreateFileMapping(fd, NULL, page, 0, 0, mapname); if(!map) error(errMapFailed); } MappedFile::MappedFile(const char *fname, pos_t pos, size_t len, Access mode) : RandomFile(fname) { DWORD share = 0, page = 0; map = INVALID_HANDLE_VALUE; fcb.address = NULL; switch(mode) { case accessReadOnly: share = FILE_SHARE_READ; page = PAGE_READONLY; prot = FILE_MAP_READ; break; case accessWriteOnly: share = FILE_SHARE_WRITE; page = PAGE_WRITECOPY; prot = FILE_MAP_COPY; break; case accessReadWrite: share = FILE_SHARE_READ|FILE_SHARE_WRITE; page = PAGE_READWRITE; prot = FILE_MAP_WRITE; } if(share || page) fd = CreateFile(pathname, mode, share, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); else fd = INVALID_HANDLE_VALUE; if(fd == INVALID_HANDLE_VALUE) { error(errOpenFailed); return; } makemapname(fname, mapname); map = CreateFileMapping(fd, NULL, page, 0, 0, mapname); if(!map) { error(errMapFailed); return; } fcb.address = (caddr_t)MapViewOfFile(map, prot, 0, pos, len); fcb.len = (ccxx_size_t)len; fcb.pos = pos; if(!fcb.address) error(errMapFailed); } MappedFile::~MappedFile() { if(fcb.address) { unlock(); UnmapViewOfFile(fcb.address); } if(map != INVALID_HANDLE_VALUE) CloseHandle(map); final(); } void MappedFile::sync(void) { } void MappedFile::sync(caddr_t address, size_t len) { } void MappedFile::release(caddr_t address, size_t len) { if(fcb.address) { unlock(); UnmapViewOfFile(fcb.address); } fcb.address = NULL; } caddr_t MappedFile::fetch(off_t pos, size_t len) { if(fcb.address) { unlock(); UnmapViewOfFile(fcb.address); } fcb.address = (caddr_t)MapViewOfFile(map, prot, 0, pos, len); fcb.len = (ccxx_size_t)len; fcb.pos = pos; if(!fcb.address) error(errMapFailed); return fcb.address; } void MappedFile::update(size_t offset, size_t len) { } void MappedFile::update(caddr_t address, size_t len) { } bool MappedFile::lock(void) { unlock(); if(VirtualLock(fcb.address, fcb.len)) fcb.locked = true; return fcb.locked; } void MappedFile::unlock(void) { if(!fcb.address) fcb.locked = false; if(!fcb.locked) return; VirtualUnlock(fcb.address, fcb.len); fcb.locked = false; } #else #ifdef HAVE_MLOCK MappedFile::MappedFile(const char *fname, Access mode) : RandomFile(fname) { fd = open(fname, (int)mode); if(fd < 0 && mode != accessReadOnly) fd = ::open(pathname, O_CREAT | O_RDWR | O_TRUNC, (int)attrPrivate); if(fd < 0) { error(errOpenFailed); return; } switch(mode) { case O_RDONLY: prot = PROT_READ; break; case O_WRONLY: prot = PROT_WRITE; break; default: prot = PROT_READ | PROT_WRITE; } } MappedFile::MappedFile(const char *fname, Access mode, size_t size) : RandomFile(fname) { fd = open(fname, (int)mode | O_CREAT, 0660); if(fd < 0) { error(errOpenFailed); return; } switch(mode) { case O_RDONLY: prot = PROT_READ; break; case O_WRONLY: prot = PROT_WRITE; break; default: prot = PROT_READ | PROT_WRITE; } enterMutex(); lseek(fd, size, SEEK_SET); fcb.address = (caddr_t)mmap(NULL, size, prot, MAP_SHARED, fd, 0); fcb.len = size; fcb.pos = 0; leaveMutex(); if((caddr_t)(fcb.address) == (caddr_t)(MAP_FAILED)) { close(fd); fd = -1; error(errMapFailed); } } MappedFile::MappedFile(const char *fname, pos_t pos, size_t len, Access mode) : RandomFile(fname) { fd = open(fname, (int)mode); if(fd < 0) { error(errOpenFailed); return; } switch(mode) { case O_RDONLY: prot = PROT_READ; break; case O_WRONLY: prot = PROT_WRITE; break; default: prot = PROT_READ | PROT_WRITE; } enterMutex(); lseek(fd, pos + len, SEEK_SET); fcb.address = (caddr_t)mmap(NULL, len, prot, MAP_SHARED, fd, pos); fcb.len = len; fcb.pos = pos; leaveMutex(); if((caddr_t)(fcb.address) == (caddr_t)(MAP_FAILED)) { close(fd); fd = -1; error(errMapFailed); } } MappedFile::~MappedFile() { unlock(); final(); } void MappedFile::sync(void) { msync(fcb.address, fcb.len, MS_SYNC); } void MappedFile::release(caddr_t address, size_t len) { enterMutex(); if(address) fcb.address = address; if(len) fcb.len = len; if(fcb.locked) unlock(); munmap(fcb.address, fcb.len); leaveMutex(); } caddr_t MappedFile::fetch(off_t pos, size_t len) { enterMutex(); unlock(); fcb.len = len; fcb.pos = pos; lseek(fd, fcb.pos + len, SEEK_SET); fcb.address = (caddr_t)mmap(NULL, len, prot, MAP_SHARED, fd, pos); leaveMutex(); return fcb.address; } bool MappedFile::lock(void) { unlock(); if(!mlock(fcb.address, fcb.len)) fcb.locked = true; return fcb.locked; } void MappedFile::unlock(void) { if(!fcb.address) fcb.locked = false; if(!fcb.locked) return; munlock(fcb.address, fcb.len); fcb.locked = false; } void MappedFile::update(size_t offset, size_t len) { int mode = MS_ASYNC; caddr_t address; if(flags.immediate) mode = MS_SYNC; enterMutex(); address = fcb.address; address += offset; if(!len) len = fcb.len; leaveMutex(); msync(address, len, mode); } void MappedFile::update(caddr_t address, size_t len) { int mode = MS_ASYNC; if(flags.immediate) mode = MS_SYNC; msync(address, len, mode); } #endif #endif // ndef WIN32 #ifdef _MSWINDOWS_ #ifndef SECS_BETWEEN_EPOCHS #define SECS_BETWEEN_EPOCHS 11644473600LL #endif #ifndef SECS_TO_100NS #define SECS_TO_100NS 10000000LL #endif #endif time_t lastAccessed(const char *path) { #ifdef _MSWINDOWS_ __int64 ts; WIN32_FILE_ATTRIBUTE_DATA ino; if(!GetFileAttributesEx(path, GetFileExInfoStandard, &ino)) return 0; ts = ((__int64)ino.ftLastAccessTime.dwHighDateTime << 32) + ino.ftLastAccessTime.dwLowDateTime; ts -= (SECS_BETWEEN_EPOCHS * SECS_TO_100NS); ts /= SECS_TO_100NS; return(time_t)ts; #else struct stat ino; if(stat(path, &ino)) return 0; return ino.st_atime; #endif } time_t lastModified(const char *path) { #ifdef _MSWINDOWS_ __int64 ts; WIN32_FILE_ATTRIBUTE_DATA ino; if(!GetFileAttributesEx(path, GetFileExInfoStandard, &ino)) return 0; ts = ((__int64)ino.ftLastWriteTime.dwHighDateTime << 32) + ino.ftLastWriteTime.dwLowDateTime; ts -= (SECS_BETWEEN_EPOCHS * SECS_TO_100NS); ts /= SECS_TO_100NS; return(time_t)ts; #else struct stat ino; if(stat(path, &ino)) return 0; return ino.st_mtime; #endif } bool isDir(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 // WIN32 } bool isFile(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 // WIN32 } #ifndef _MSWINDOWS_ // the Win32 version is given in line in the header bool isDevice(const char *path) { struct stat ino; if(stat(path, &ino)) return false; if(S_ISCHR(ino.st_mode)) return true; return false; } #endif bool canAccess(const char *path) { #ifdef _MSWINDOWS_ DWORD attr = GetFileAttributes(path); if(attr == (DWORD)~0l) return false; if(attr & FILE_ATTRIBUTE_SYSTEM) return false; if(attr & FILE_ATTRIBUTE_HIDDEN) return false; return true; #else if(!access(path, R_OK)) return true; return false; #endif } bool canModify(const char *path) { #ifdef _MSWINDOWS_ DWORD attr = GetFileAttributes(path); if(!canAccess(path)) return false; if(attr & FILE_ATTRIBUTE_READONLY) return false; if(attr & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_NORMAL)) return true; return false; #else if(!access(path, W_OK | R_OK)) return true; return false; #endif } #ifdef _MSWINDOWS_ const char *File::getExtension(const char *path) { const char *cp = strrchr(path, '\\'); if(!cp) cp = strrchr(path, '/'); if(!cp) cp = strrchr(path, ':'); if(cp) ++cp; else cp = path; if(*cp == '.') return ""; cp = strrchr(cp, '.'); if(!cp) cp = ""; return cp; } const char *File::getFilename(const char *path) { const char *cp = strrchr(path, '\\'); if(cp) return ++cp; cp = strrchr(path, '/'); if(cp) return ++cp; cp = strrchr(path, ':'); if(cp) ++cp; return path; } char *File::getFilename(const char *path, char *buffer, size_t size) { const char *cp = strrchr(path, '\\'); if(!cp) cp = strrchr(path, '/'); if(!cp) cp = strrchr(path, ':'); if(cp) snprintf(buffer, size, "%s", ++cp); else snprintf(buffer, size, "%s", path); return buffer; } char *File::getDirname(const char *path, char *buffer, size_t size) { size_t len = 0; const char *cp = strrchr(path, '\\'); snprintf(buffer, size, "%s", path); if(!cp) cp = strrchr(path, '/'); if(!cp) cp = strrchr(path, ':'); if(!cp) return buffer; if(cp) len = cp - path; if(len >= size) len = size - 1; buffer[len] = 0; return buffer; } #else const char *File::getExtension(const char *path) { const char *cp = strrchr(path, '/'); if(cp) ++cp; else cp = path; if(*cp == '.') return ""; cp = strrchr(cp, '.'); if(cp) return cp; return ""; } char *File::getDirname(const char *path, char *buffer, size_t size) { unsigned len; const char *cp = strrchr(path, '/'); snprintf(buffer, size, "%s", path); if(!cp) return buffer; else len = cp - path; if(len >= size) len = size - 1; buffer[len] = 0; return buffer; } const char *File::getFilename(const char *path) { const char *cp = strrchr(path, '/'); if(cp) return ++cp; return path; } char *File::getFilename(const char *path, char *buffer, size_t size) { const char *cp = strrchr(path, '/'); if(cp) snprintf(buffer, size, "%s", ++cp); else snprintf(buffer, size, "%s", path); return buffer; } #endif #ifdef HAVE_REALPATH char *File::getRealpath(const char *path, char *buffer, size_t size) { char temp[PATH_MAX]; setString(buffer, size, "."); if(!realpath(path, temp)) return NULL; if(strlen(temp) >= size) return NULL; setString(buffer, size, temp); return buffer; } #else #ifdef _MSWINDOWS_ static char *getFile(char *path) { char *cp = strchr(path, '\\'); if(!cp) cp = strchr(path, '/'); if(!cp) cp = strchr(path, ':'); return cp; } #else static char *getFile(char *path) { return strchr(path, '/'); } #endif char *File::getRealpath(const char *path, char *buffer, size_t size) { if(size > PATH_MAX) size = PATH_MAX; #ifdef HAVE_LSTAT unsigned symlinks = 0; #endif #if !defined(DYNAMCIC_LOCAL_ARRAYS) char left[PATH_MAX]; #else char left[size]; #endif size_t left_len, buffer_len; #ifdef _MSWINDOWS_ if(path[1] == ':') #else if(path[0] == '/') #endif { buffer[0] = '/'; buffer[1] = 0; if(!path[1]) return buffer; buffer_len = 1; snprintf(left, size, "%s", path + 1); left_len = strlen(left); } else { if(!Dir::getPrefix(buffer, size)) { snprintf(buffer, size, "%s", "."); return NULL; } buffer_len = strlen(buffer); snprintf(left, size, "%s", path); left_len = strlen(left); } if(left_len >= size || buffer_len >= size) return NULL; while(left_len > 0) { #ifdef HAVE_LSTAT struct stat ino; #endif #if !defined(DYNAMIC_LOCAL_ARRAYS) char next_token[PATH_MAX]; #else char next_token[size]; #endif char *p; const char *s = (p = getFile(left)) ? p : left + left_len; memmove(next_token, left, s - left); left_len -= s - left; if(p != NULL) memmove(left, s + 1, left_len + 1); next_token[s - left] = 0; if(buffer[buffer_len - 1] != '/') { if(buffer_len +1 >= size) return NULL; buffer[buffer_len++] = '/'; buffer[buffer_len] = 0; } if(!next_token[0]) continue; else if(!strcmp(next_token, ".")) continue; else if(!strcmp(next_token, "..")) { if(buffer_len > 1) { char *q; buffer[buffer_len - 1] = 0; #ifdef _MSWINDOWS_ q = strrchr(buffer, '\\'); if(!q) q = strrchr(buffer, '/'); if(!q) q = strchr(buffer, ':'); #else q = strrchr(buffer, '/'); #endif *q = 0; buffer_len = q - buffer; } continue; } snprintf(next_token, size, "%s", buffer); buffer_len = strlen(buffer); if(buffer_len >= size) return NULL; #ifndef HAVE_LSTAT if(!isFile(buffer) && !isDir(buffer)) return buffer; continue; #else if(lstat(buffer, &ino) < 0) { if(errno == ENOENT && !p) return buffer; return NULL; } if((ino.st_mode & S_IFLNK) == S_IFLNK) { char symlink[size]; int slen; if (symlinks++ > MAXSYMLINKS) return NULL; slen = readlink(buffer, symlink, size); if (slen < 0) return NULL; symlink[slen] = 0; if (symlink[0] == '/') { buffer[1] = 0; buffer_len = 1; } else if (buffer_len > 1) { char *q; buffer[buffer_len - 1] = 0; q = strrchr(buffer, '/'); *q = 0; buffer_len = q - buffer; } if (symlink[slen - 1] != '/' && p) { if (slen >= size) return NULL; symlink[slen] = '/'; symlink[slen + 1] = 0; } if(p) { snprintf(symlink, size, "%s", left); left_len = strlen(symlink); } if(left_len >= size) return NULL; snprintf(left, size, "%s", symlink); left_len = strlen(left); } #endif } #ifdef _MSWINDOWS_ if(buffer_len > 1 && buffer[buffer_len - 1] == '\\') buffer[buffer_len - 1] = 0; else if(buffer_len > 1 && buffer[buffer_len - 1] == '/') buffer[buffer_len - 1] = 0; #else if(buffer_len > 1 && buffer[buffer_len - 1] == '/') buffer[buffer_len - 1] = 0; #endif return buffer; } #endif } // namespace ost commoncpp-7.0.1/commoncpp/linked.cpp000066400000000000000000000114761411242573100174700ustar00rootroot00000000000000// Copyright (C) 2004-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include namespace ost { LinkedSingle::~LinkedSingle() {} LinkedSingle *LinkedSingle::getFirst(void) { return this; } LinkedSingle *LinkedSingle::getLast(void) { LinkedSingle *obj = this; while(obj->nextObject) obj = obj->nextObject; return obj; } void LinkedSingle::insert(LinkedSingle& obj) { obj.nextObject = nextObject; nextObject = &obj; } LinkedSingle &LinkedSingle::operator+=(LinkedSingle &obj) { insert(obj); return *this; } LinkedDouble::~LinkedDouble() { detach(); } void LinkedDouble::enterLock() {} void LinkedDouble::leaveLock() {} LinkedDouble *LinkedDouble::firstObject() { LinkedDouble *node = this; while(node->prevObject) node = node->prevObject; return node; } LinkedDouble *LinkedDouble::lastObject() { LinkedDouble *node = this; while(node->nextObject) node = node->nextObject; return node; } LinkedDouble *LinkedDouble::getFirst(void) { LinkedDouble *node; enterLock(); node = firstObject(); leaveLock(); return node; } LinkedDouble *LinkedDouble::getLast(void) { LinkedDouble *node; enterLock(); node = lastObject(); leaveLock(); return node; } LinkedDouble *LinkedDouble::getInsert(void) { return getLast(); } void LinkedDouble::insert(LinkedDouble& obj, InsertMode position) { LinkedDouble *node; enterLock(); obj.detach(); switch ( position ) { case modeAtFirst: node = firstObject(); obj.nextObject = node; node->prevObject = &obj; break; case modeBefore: obj.nextObject = this; obj.prevObject = this->prevObject; this->prevObject = &obj; if (obj.prevObject) obj.prevObject->nextObject = &obj; break; case modeAfter: obj.nextObject = this->nextObject; obj.prevObject = this; this->nextObject = &obj; if (obj.nextObject) obj.nextObject->prevObject = &obj; break; case modeAtLast: default: node = lastObject(); obj.nextObject = node->nextObject; obj.prevObject = node; node->nextObject = &obj; if(obj.nextObject) obj.nextObject->prevObject = &obj; break; } leaveLock(); } void LinkedDouble::detach(void) { enterLock(); if(prevObject) prevObject->nextObject = nextObject; if(nextObject) nextObject->prevObject = prevObject; prevObject = NULL; nextObject = NULL; leaveLock(); } LinkedDouble &LinkedDouble::operator+=(LinkedDouble &obj) { insert(obj); return *this; } LinkedDouble &LinkedDouble::operator--() { detach(); return *this; } } // namespace ost commoncpp-7.0.1/commoncpp/map.cpp000066400000000000000000000130511411242573100167660ustar00rootroot00000000000000// Copyright (C) 2004-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include namespace ost { MapIndex& MapIndex::operator=(MapObject *theObject) { thisObject = theObject; return *this; } MapIndex& MapIndex::operator++() { if ( thisObject == NULL ) return *this; if (thisObject->nextObject != NULL) { thisObject = thisObject->nextObject; } else if (thisObject->table != NULL) { MapObject* obj = NULL; unsigned i = thisObject->table->getIndex(thisObject->idObject) + 1; thisObject->table->enterMutex(); for ( ; obj == NULL && i < thisObject->table->range; i++) obj = thisObject->table->map[i]; thisObject->table->leaveMutex(); thisObject = obj; } return *this; } MapTable::MapTable(unsigned size) : Mutex() { map = new MapObject *[size + 1]; memset(map, 0, sizeof(MapObject *) * (size + 1)); range = size; count = 0; } MapTable::~MapTable() { cleanup(); } void MapTable::cleanup(void) { enterMutex(); if(map) delete[] map; map = NULL; leaveMutex(); } unsigned MapTable::getIndex(const char *id) { unsigned key = 0; while(*id) key = (key << 1) ^ (*(id++) & 0x1f); return key % range; } void *MapTable::getObject(const char *id) { if(!map) return NULL; enterMutex(); MapObject *obj = map[getIndex(id)]; while(obj) { if(!stricmp(obj->idObject, id)) break; obj = obj->nextObject; } leaveMutex(); return (void *)obj; } void *MapTable::getFirst() { MapObject *obj; if(!map) return NULL; enterMutex(); obj = *map; for (unsigned i = 0; obj == NULL && i < range; i++) obj = map[i]; leaveMutex(); return obj; } void *MapTable::getLast() { MapObject *obj = NULL; if(!map) return NULL; enterMutex(); for (int i = range - 1; obj == NULL && i >= 0; i--) obj = map[i]; if ( obj != NULL ) while ( obj->nextObject != NULL ) obj = obj->nextObject; leaveMutex(); return obj; } void *MapTable::getFree(void) { enterMutex(); MapObject *obj = map[range]; if(obj) map[range] = obj->nextObject; leaveMutex(); return obj; } void MapTable::addFree(MapObject *obj) { obj->detach(); enterMutex(); obj->nextObject = map[range]; map[range] = obj; leaveMutex(); } void MapTable::addObject(MapObject &obj) { unsigned idx = getIndex(obj.idObject); if(obj.table == this || !map) return; obj.detach(); enterMutex(); obj.nextObject = map[idx]; map[idx] = &obj; obj.table = this; count++; leaveMutex(); } MapTable &MapTable::operator+=(MapObject &obj) { addObject(obj); return *this; } MapTable &MapTable::operator-=(MapObject &obj) { if(obj.table == this) obj.detach(); return *this; } MapObject::MapObject(const char *id) { table = NULL; idObject = id; } void MapObject::detach(void) { MapObject *node, *prev = NULL; unsigned idx; if(!table) return; idx = table->getIndex(idObject); table->enterMutex(); node = table->map[idx]; while(node) { if(node == this) break; prev = node; node = prev->nextObject; } if(node && !prev) table->map[idx] = nextObject; else if(node) prev->nextObject = nextObject; table->count--; table->leaveMutex(); table = NULL; } } // namespace ost commoncpp-7.0.1/commoncpp/mime.cpp000066400000000000000000000076101411242573100171440ustar00rootroot00000000000000// Copyright (C) 2001-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include #include #include namespace ost { using std::ostream; using std::endl; MIMEMultipart::MIMEMultipart(const char *mt) { const char *cp = strchr(mt, '/'); if(cp) mt = ++cp; first = last = NULL; header[1] = NULL; header[0] = mtype; setString(boundry, sizeof(boundry), "xyzzy"); snprintf(mtype, sizeof(mtype), "Content-Type: multipart/%s, boundry=%s", mt, boundry); } MIMEMultipart::~MIMEMultipart() {} void MIMEMultipart::head(ostream *out) { char **list = header; while(**list) *out << *(list++) << "\r\n"; out->flush(); } void MIMEMultipart::body(ostream *out) { MIMEItemPart *item = first; while(item) { *out << "--" << boundry << "\r\n"; item->head(out); *out << "\r\n"; item->body(out); item = item->next; } *out << "--" << boundry << "--\r\n"; out->flush(); } MIMEItemPart::MIMEItemPart(MIMEMultipart *m, const char *ct) { if(m->last) { m->last->next = this; m->last = this; } else m->first = m->last = this; next = NULL; ctype = ct; } MIMEItemPart::~MIMEItemPart() {} MIMEMultipartForm::MIMEMultipartForm() : MIMEMultipart("form-data") {} MIMEMultipartForm::~MIMEMultipartForm() {} void MIMEItemPart::head(ostream *out) { *out << "Content-Type: " << ctype << "\r" << endl; } MIMEFormData::MIMEFormData(MIMEMultipartForm *m, const char *n, const char *v) : MIMEItemPart(m, "") { name = n; content = v; } MIMEFormData::~MIMEFormData() {} void MIMEFormData::head(ostream *out) { *out << "Content-Disposition: form-data; name=\"" << name << "\"\r\n"; } void MIMEFormData::body(ostream *out) { *out << content << "\r\n"; } } // namespace ost commoncpp-7.0.1/commoncpp/misc.cpp000066400000000000000000000071451411242573100171530ustar00rootroot00000000000000// Copyright (C) 2001-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include #include namespace ost { static unsigned getIndex(const char *id) { unsigned idx = 0; while(*id) idx = (idx << 1) ^ (*(id++) & 0x1f); return idx % KEYDATA_INDEX_SIZE; } char *MemPager::alloc(const char *str) { size_t len = strlen(str) + 1; char *cp = (char *)_alloc(len); if(cp) String::set(cp, len, str); return cp; } Assoc::Assoc() { clear(); } Assoc::~Assoc() { } void Assoc::clear(void) { memset(&entries, 0, sizeof(entries)); } void Assoc::setPointer(const char *id, void *data) { unsigned idx = getIndex(id); entry *e = (entry *)getMemory(sizeof(entry)); size_t size = strlen(id) + 1; e->id = (const char *)getMemory(size); String::set((char *)e->id, size, id); e->data = data; e->next = entries[idx]; entries[idx] = e; } void *Assoc::getPointer(const char *id) const { entry *e = entries[getIndex(id)]; while(e) { if(!stricmp(e->id, id)) break; e = e->next; } if(e) return e->data; return NULL; } SharedMemPager::SharedMemPager(size_t pg) : MemPager(pg), Mutex() {} void SharedMemPager::purge(void) { enterMutex(); MemPager::purge(); leaveMutex(); } void *SharedMemPager::alloc(size_t size) { void *mem; enterMutex(); mem = MemPager::alloc(size); leaveMutex(); return mem; } } // namespace ost /** EMACS ** * Local variables: * mode: c++ * c-basic-offset: 4 * End: */ commoncpp-7.0.1/commoncpp/persist.cpp000066400000000000000000000164721411242573100177140ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 UCOMMON_SYSRUNTIME #include #include #include // local includes #include namespace ost { const uint32_t NullObject = 0xffffffff; PersistException::PersistException(const std::string& reason) : _what(reason) { } const std::string& PersistException::getString() const { return _what; } PersistException::~PersistException() { } const char* PersistObject::getPersistenceID() const { return "PersistObject"; } PersistObject::PersistObject() { // Do nothing } PersistObject::~PersistObject() { // Do nothing } bool PersistObject::write(PersistEngine& archive) const { // Do nothing return true; // Successfully } bool PersistObject::read(PersistEngine& archive) { // Do nothing return true; // Successfully } static TypeManager::StringFunctionMap* theInstantiationFunctions = 0; static int refCount = 0; TypeManager::StringFunctionMap& _internal_GetMap() { return *theInstantiationFunctions; } void TypeManager::add(const char* name, NewPersistObjectFunction construction) { if (refCount++ == 0) { theInstantiationFunctions = new StringFunctionMap; } assert(_internal_GetMap().find(std::string(name)) == _internal_GetMap().end()); _internal_GetMap()[std::string(name)] = construction; } void TypeManager::remove(const char* name) { assert(_internal_GetMap().find(std::string(name)) != _internal_GetMap().end()); _internal_GetMap().erase(_internal_GetMap().find(std::string(name))); if (--refCount == 0) { delete theInstantiationFunctions; theInstantiationFunctions = 0; } } PersistObject* TypeManager::createInstanceOf(const char* name) { assert(refCount); assert(_internal_GetMap().find(std::string(name)) != _internal_GetMap().end()); return (_internal_GetMap()[std::string(name)])(); } TypeManager::registration::registration(const char *name, NewPersistObjectFunction func) : myName(name) { TypeManager::add(name, func); } TypeManager::registration::~registration() { TypeManager::remove(myName.c_str()); } PersistEngine::PersistEngine(std::iostream& stream, EngineMode mode) : myUnderlyingStream(stream), myOperationalMode(mode) { } PersistEngine::~PersistEngine() { if (myUnderlyingStream.good()) myUnderlyingStream.sync(); } void PersistEngine::writeBinary(const uint8_t* data, const uint32_t size) { if(myOperationalMode != modeWrite) throw(PersistException("Cannot write to an input Engine")); myUnderlyingStream.write((const char *)data,size); } void PersistEngine::readBinary(uint8_t* data, uint32_t size) { if(myOperationalMode != modeRead) throw(PersistException("Cannot read from an output Engine")); myUnderlyingStream.read((char *)data,size); } void PersistEngine::write(const PersistObject *object) { // Pre-step, if object is NULL, then don't serialize it - serialize a // marker to say that it is null. // as ID's are uint32's, NullObject will do nicely for the task if (object == NULL) { uint32_t id = NullObject; write(id); return; } // First off - has this Object been serialized already? ArchiveMap::const_iterator itor = myArchiveMap.find(object); if (itor == myArchiveMap.end()) { // Unfortunately we need to serialize it - here we go .... uint32_t id = (uint32_t)myArchiveMap.size(); myArchiveMap[object] = id; // bumps id automatically for next one write(id); ClassMap::const_iterator classItor = myClassMap.find(object->getPersistenceID()); if (classItor == myClassMap.end()) { uint32_t classId = (uint32_t)myClassMap.size(); myClassMap[object->getPersistenceID()] = classId; write(classId); write(static_cast(object->getPersistenceID())); } else { write(classItor->second); } std::string majik; majik = "OBST"; write(majik); object->write(*this); majik = "OBEN"; write(majik); } else { // This object has been serialized, so just pop its ID out write(itor->second); } } void PersistEngine::read(PersistObject &object) { uint32_t id = 0; read(id); if (id == NullObject) throw(PersistException("Object Id should not be NULL when un-persisting to a reference")); // Do we already have this object in memory? if (id < myArchiveVector.size()) { object = *(myArchiveVector[id]); return; } // Okay - read the identifier for the class in... // we won't need it later since this object is already allocated readClass(); // Okay then - we can read data straight into this object readObject(&object); } void PersistEngine::read(PersistObject *&object) { uint32_t id = 0; read(id); // Is the ID a NULL object? if (id == NullObject) { object = NULL; return; } // Do we already have this object in memory? if (id < myArchiveVector.size()) { object = myArchiveVector[id]; return; } // Okay - read the identifier for the class in... std::string className = readClass(); // is the pointer already initialized? if so then no need to reallocate if (object != NULL) { readObject(object); return; } // Create the object (of the relevant type) object = TypeManager::createInstanceOf(className.c_str()); if (object) { // Okay then - we can make this object readObject(object); } else throw(PersistException(std::string("Unable to instantiate object of class ")+className)); } void PersistEngine::readObject(PersistObject* object) { // Okay then - we can make this object myArchiveVector.push_back(object); std::string majik; read(majik); if(majik != std::string("OBST")) throw( PersistException("Missing Start-of-Object marker")); object->read(*this); read(majik); if(majik != std::string("OBEN")) throw( PersistException("Missing End-of-Object marker")); } const std::string PersistEngine::readClass() { // Okay - read the identifier for the class in... uint32_t classId = 0; read(classId); std::string className; if (classId < myClassVector.size()) { className = myClassVector[classId]; } else { // Okay the class wasn't known yet - save its name read(className); myClassVector.push_back(className); } return className; } void PersistEngine::write(const std::string& str) { uint32_t len = (uint32_t)str.length(); write(len); writeBinary((uint8_t*)str.c_str(),len); } void PersistEngine::read(std::string& str) { uint32_t len = 0; read(len); uint8_t *buffer = new uint8_t[len+1]; readBinary(buffer,len); buffer[len] = 0; str = (char*)buffer; delete[] buffer; } } // namespace ucommon #endif commoncpp-7.0.1/commoncpp/pointer.cpp000066400000000000000000000061611411242573100176750ustar00rootroot00000000000000// Copyright (C) 2004-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include namespace ost { RefObject::~RefObject() {} void RefPointer::enterLock(void) {} void RefPointer::leaveLock(void) {} void RefPointer::detach(void) { if(ref) { enterLock(); --(ref->refCount); if(!ref->refCount) delete ref; leaveLock(); ref = NULL; } } RefPointer::RefPointer(RefObject *obj) { enterLock(); ++obj->refCount; leaveLock(); ref = obj; } RefPointer::RefPointer(const RefPointer &ptr) : ref(ptr.ref) { detach(); if(ref) { enterLock(); ++ref->refCount; leaveLock(); } } RefPointer::~RefPointer() { detach(); } void *RefPointer::getObject() const { if(ref) return ref->getObject(); return NULL; } RefPointer::operator bool() const { if(ref && ref->refCount == 1) return false; return true; } bool RefPointer::operator!() const { if(ref && ref->refCount == 1) return true; return false; } } // namespace ost commoncpp-7.0.1/commoncpp/process.cpp000066400000000000000000000423531411242573100176760ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include #include #include #include #include #ifdef HAVE_FCNTL_H #include #endif #ifdef MACOSX #undef _POSIX_PRIORITY_SCHEDULING #endif #ifndef _MSWINDOWS_ #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_WAIT_H #include #endif #include #include #ifdef SIGTSTP #include #include #endif #ifndef _PATH_TTY #define _PATH_TTY "/dev/tty" #endif #endif #ifdef _MSWINDOWS_ #include #include #endif namespace ost { bool Process::rtflag = false; #ifdef _MSWINDOWS_ static SYSTEM_INFO sysinfo; static LPSYSTEM_INFO lpSysInfo = NULL; static void init_sysinfo(void) { if(!lpSysInfo) { lpSysInfo = &sysinfo; memset(&sysinfo, 0, sizeof(sysinfo)); GetSystemInfo(lpSysInfo); } } const char *Process::getUser(void) { static char userid[65]; DWORD length = sizeof(userid); if(GetUserName(userid, &length)) return userid; return NULL; } size_t Process::getPageSize(void) { init_sysinfo(); return (size_t) lpSysInfo->dwPageSize; } int Process::spawn(const char *exename, const char **args, bool wait) { int mode = P_NOWAIT; if(wait) mode = P_WAIT; return (int)::spawnvp(mode, (char *)exename, (char **)args); } int Process::join(int pid) { int status, result; if(pid == -1) return pid; result = (int)cwait(&status, pid, WAIT_CHILD); if(status & 0x0) return -1; return result; } bool Process::cancel(int pid, int sig) { HANDLE hPid = OpenProcess(PROCESS_TERMINATE, FALSE, pid); bool rtn = true; if(!hPid) return false; switch(sig) { case SIGABRT: case SIGTERM: if(!TerminateProcess(hPid, -1)) rtn = false; case 0: break; default: rtn = false; } CloseHandle(hPid); return rtn; } void Process::setPriority(int pri) { DWORD pc = NORMAL_PRIORITY_CLASS; DWORD pid = GetCurrentProcessId(); HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, TRUE, pid); #ifdef BELOW_NORMAL_PRIORITY_CLASS if(pri == -1) pc = BELOW_NORMAL_PRIORITY_CLASS; else if(pri == 1) pc = ABOVE_NORMAL_PRIORITY_CLASS; else #endif if(pri == 2) pc = HIGH_PRIORITY_CLASS; else if(pri > 2) pc = REALTIME_PRIORITY_CLASS; else if(pri < -1) pc = IDLE_PRIORITY_CLASS; SetPriorityClass(hProcess, pc); CloseHandle(hProcess); } void Process::setScheduler(const char *cp) { if(!stricmp(cp, "fifo")) setPriority(3); else if(!stricmp(cp, "rr")) setPriority(2); else if(!stricmp(cp, "idle")) setPriority(-2); else setPriority(0); } void Process::setRealtime(int pri) { setPriority(3); } bool Process::isScheduler(void) { return false; } #else #ifndef WEXITSTATUS #define WEXITSTATUS(status) ((unsigned)(status) >> 8) #endif #ifndef WIFEXITED #define WIFEXITED(status) (((status) & 255) == 0) #endif #ifndef WTERMSIG #define WTERMSIG(status) (((unsigned)(status)) & 0x7F) #endif #ifndef WIFSIGNALLED #define WIFSIGNALLED(status) (((status) & 255) != 0) #endif #ifndef WCOREDUMP #define WCOREDUMP(status) (((status) & 0x80) != 0) #endif static char *_pUser = NULL; static char *_pHome = NULL; static void lookup(void) { struct passwd *pw = NULL; #ifdef HAVE_GETPWUID_R struct passwd pwd; char buffer[1024]; ::getpwuid_r(geteuid(), &pwd, buffer, 1024, &pw); #else pw = ::getpwuid(geteuid()); #endif if(_pHome) delString(_pHome); if(_pUser) delString(_pUser); _pUser = _pHome = NULL; if(pw != NULL && pw->pw_dir != NULL) _pHome = newString(pw->pw_dir); if(pw != NULL && pw->pw_name != NULL) _pUser = newString(pw->pw_name); endpwent(); } const char *Process::getUser(void) { if(!_pUser) lookup(); return (const char *)_pUser; } const char *Process::getConfigDir(void) { #ifdef ETC_CONFDIR return ETC_CONFDIR; #else return "/etc"; #endif } const char *Process::getHomeDir(void) { if(!_pHome) lookup(); return (const char *)_pHome; } #ifdef HAVE_GETPAGESIZE size_t Process::getPageSize(void) { return (size_t)getpagesize(); } #else size_t Process::getPageSize(void) { return 1024; } #endif bool Process::setUser(const char *id, bool grp) { struct passwd *pw = NULL; #ifdef HAVE_GETPWNAM_R struct passwd pwd; char buffer[1024]; ::getpwnam_r(id, &pwd, buffer, 1024, &pw); #else pw = ::getpwnam(id); #endif if(!pw) return false; #ifdef HAVE_SETGROUPS setgroups(0, NULL); #endif if(grp) if(setgid(pw->pw_gid)) return false; if(setuid(pw->pw_uid)) return false; lookup(); return true; } bool Process::setGroup(const char *id) { struct group *group = NULL; #ifdef HAVE_GETGRNAM_R struct group grp; char buffer[2048]; ::getgrnam_r(id, &grp, buffer, 1024, &group); #else group = ::getgrnam(id); #endif if(!group) { #if HAVE_ENDGRENT endgrent(); #endif return false; } #ifdef HAVE_SETEGID setegid(group->gr_gid); #endif if(setgid(group->gr_gid)) { #if HAVE_ENDGRENT endgrent(); #endif return false; } #if HAVE_ENDGRENT endgrent(); #endif return true; } bool Process::cancel(int pid, int sig) { if(!sig) sig = SIGTERM; if(pid < 1) return false; if(::kill(pid, sig)) return false; return true; } int Process::join(int pid) { int status; if(pid < 1) return -1; #ifdef HAVE_WAITPID waitpid(pid, &status, 0); #else #ifdef HAVE_WAIT4 wait4(pid, &status, 0, NULL); #else int result; while((result = ::wait(&status)) != pid && result != -1) ; #endif #endif if(WIFEXITED(status)) return WEXITSTATUS(status); else if(WIFSIGNALLED(status)) return -WTERMSIG(status); else return -1; } int Process::spawn(const char *exename, const char **args, bool wait) { int pid; pid = fork(); if(pid == -1) return -1; if(!pid) { execvp((char *)exename, (char **)args); _exit(-1); } if(!wait) return pid; return join(pid); } Process::Trap Process::setInterruptSignal(int signo, Trap func) { struct sigaction sig_act, old_act; memset(&sig_act, 0, sizeof(sig_act)); sig_act.sa_handler = func; sigemptyset(&sig_act.sa_mask); if(signo != SIGALRM) sigaddset(&sig_act.sa_mask, SIGALRM); sig_act.sa_flags = 0; #ifdef SA_INTERRUPT sig_act.sa_flags |= SA_INTERRUPT; #endif if(sigaction(signo, &sig_act, &old_act) < 0) return SIG_ERR; return old_act.sa_handler; } Process::Trap Process::setPosixSignal(int signo, Trap func) { struct sigaction sig_act, old_act; memset(&sig_act, 0, sizeof(sig_act)); sig_act.sa_handler = func; sigemptyset(&sig_act.sa_mask); sig_act.sa_flags = 0; if(signo == SIGALRM) { #ifdef SA_INTERRUPT sig_act.sa_flags |= SA_INTERRUPT; #endif } else { sigaddset(&sig_act.sa_mask, SIGALRM); #ifdef SA_RESTART sig_act.sa_flags |= SA_RESTART; #endif } if(sigaction(signo, &sig_act, &old_act) < 0) return SIG_ERR; return old_act.sa_handler; } void Process::detach(void) { attach("/dev/null"); } void Process::attach(const char *dev) { int pid; if(getppid() == 1) return; ::close(0); ::close(1); ::close(2); #ifdef SIGTTOU setPosixSignal(SIGTTOU, SIG_IGN); #endif #ifdef SIGTTIN setPosixSignal(SIGTTIN, SIG_IGN); #endif #ifdef SIGTSTP setPosixSignal(SIGTSTP, SIG_IGN); #endif if((pid = fork()) < 0) THROW(pid); else if(pid > 0) exit(0); #if defined(SIGTSTP) && defined(TIOCNOTTY) int fd; if(setpgid(0, getpid()) == -1) THROW(-1); if((fd = open(_PATH_TTY, O_RDWR)) >= 0) { ioctl(fd, TIOCNOTTY, NULL); close(fd); } #else #ifdef HAVE_SETPGRP if(setpgrp() == -1) THROW(-1); #else if(setpgid(0, getpid()) == -1) THROW(-1); #endif setPosixSignal(SIGHUP, SIG_IGN); if((pid = fork()) < 0) THROW(-1); else if(pid > 0) exit(0); #endif if(dev && *dev) { ::open(dev, O_RDWR); ::open(dev, O_RDWR); ::open(dev, O_RDWR); } } void Process::setScheduler(const char *pol) { #ifdef _POSIX_PRIORITY_SCHEDULING struct sched_param p; int policy, orig; pthread_t ptid = pthread_self(); if(pthread_getschedparam(ptid, &policy, &p)) return; orig = policy; if(pol) { #if defined(SCHED_TS) policy = SCHED_TS; #elif defined(SCHED_OTHER) policy = SCHED_OTHER; #else policy = 0; #endif #ifdef SCHED_RR if(ucommon::eq_case(pol, "rr")) policy = SCHED_RR; #endif #if !defined(SCHED_RR) && defined(SCHED_FIFO) if(ucommon::eq_case(pol, "rr")) policy = SCHED_FIFO; #endif #ifdef SCHED_FIFO if(ucommon::eq_case(pol, "fifo")) { rtflag = true; policy = SCHED_FIFO; } #endif #ifdef SCHED_TS if(ucommon::eq_case(pol, "ts")) policy = SCHED_TS; #endif #ifdef SCHED_OTHER if(ucommon::eq_case(pol, "other")) policy = SCHED_OTHER; #endif } else policy = orig; int min = sched_get_priority_min(policy); int max = sched_get_priority_max(policy); if(p.sched_priority < min) p.sched_priority = min; else if(p.sched_priority > max) p.sched_priority = max; pthread_setschedparam(ptid, policy, &p); #endif } void Process::setPriority(int pri) { #ifdef _POSIX_PRIORITY_SCHEDULING struct sched_param p; int policy; pthread_t ptid = pthread_self(); pthread_getschedparam(ptid, &policy, &p); int min = sched_get_priority_min(policy); int max = sched_get_priority_max(policy); if(pri < min) pri = min; if(pri > max) pri = max; p.sched_priority = pri; pthread_setschedparam(ptid, policy, &p); #else if(pri < -20) pri = -20; if(pri > 20) pri = 20; nice(-pri); #endif } bool Process::isScheduler(void) { #ifdef _POSIX_PRIORITY_SCHEDULING return true; #else return false; #endif } void Process::setRealtime(int pri) { if(pri < 1) pri = 1; setScheduler("rr"); setPriority(pri); } #endif #ifdef _OSF_SOURCE #undef HAVE_SETENV #endif void Process::setEnv(const char *name, const char *value, bool overwrite) { #ifdef HAVE_SETENV ::setenv(name, value, (int)overwrite); #else char strbuf[256]; snprintf(strbuf, sizeof(strbuf), "%s=%s", name, value); if(!overwrite) if(getenv(strbuf)) return; ::putenv(strdup(strbuf)); #endif } const char *Process::getEnv(const char *name) { return ::getenv(name); } #if defined(HAVE_MLOCKALL) && defined(MCL_FUTURE) #include bool Process::lock(bool future) { int rc; if(future) rc = mlockall(MCL_CURRENT | MCL_FUTURE); else rc = mlockall(MCL_CURRENT); if(rc) return false; return true; } void Process::unlock(void) { munlockall(); } #else bool Process::lock(bool future) { return false; } void Process::unlock(void) { } #endif #ifdef _MSWINDOWS_ Lockfile::Lockfile() { _mutex = INVALID_HANDLE_VALUE; _flagged = false; } Lockfile::Lockfile(const char *name) { _mutex = INVALID_HANDLE_VALUE; _flagged = false; lock(name); } bool Lockfile::lock(const char *name) { char mname[65]; char *ext = strrchr((char *)name, '/'); if(ext) name = ++ext; unlock(); snprintf(mname, sizeof(mname) - 4, "_lock_%s", name); ext = strrchr(mname, '.'); if(ext && !stricmp(ext, ".lock")) { *ext = 0; ext = NULL; } if(!ext) addString(mname, sizeof(mname), ".lck"); _mutex = CreateMutex(NULL, FALSE, mname); if (!_mutex || _mutex == INVALID_HANDLE_VALUE) return false; if(WaitForSingleObject(_mutex, 200) == WAIT_OBJECT_0) _flagged = true; return _flagged; } void Lockfile::unlock(void) { if(_mutex == INVALID_HANDLE_VALUE) return; if(_flagged) ReleaseMutex(_mutex); CloseHandle(_mutex); _flagged = false; _mutex = INVALID_HANDLE_VALUE; } bool Lockfile::isLocked(void) { return _flagged; } #else Lockfile::Lockfile() { _path = NULL; } Lockfile::Lockfile(const char *name) { _path = NULL; lock(name); } bool Lockfile::lock(const char *name) { struct stat ino; int fd, pid, status; const char *ext; char buffer[128]; bool rtn = true; size_t size; unlock(); ext = strrchr(name, '/'); if(ext) ext = strrchr(ext, '.'); else ext = strrchr(name, '.'); if(strchr(name, '/')) { size = strlen(name) + 1; _path = new char[size]; String::set(_path, size, name); } else if(ext && !strcmp(ext, ".pid")) { if(stat("/var/run", &ino)) snprintf(buffer, sizeof(buffer), "/tmp/.%s", name); else snprintf(buffer, sizeof(buffer), "/var/run/%s", name); size = strlen(buffer) + 1; _path = new char[size]; String::set(_path, size, buffer); } else { if(!ext) ext = ".lock"; if(stat("/var/lock", &ino)) snprintf(buffer, sizeof(buffer), "/tmp/.%s%s", name, ext); else snprintf(buffer, sizeof(buffer), "/var/lock/%s%s", name, ext); size = strlen(buffer) + 1; _path = new char[size]; String::set(_path, size, buffer); } for(;;) { fd = ::open(_path, O_WRONLY | O_CREAT | O_EXCL, 0660); if(fd >= 0) { pid = getpid(); snprintf(buffer, sizeof(buffer), "%d\n", pid); if(::write(fd, buffer, strlen(buffer))) rtn = false; ::close(fd); return rtn; } if(fd < 0 && errno != EEXIST) { delete[] _path; return false; } fd = ::open(_path, O_RDONLY); if(fd < 0) { if(errno == ENOENT) continue; delete[] _path; return false; } Thread::sleep(2000); status = ::read(fd, buffer, sizeof(buffer) - 1); if(status < 1) { // ensure that buffer is null-terminated before continuing buffer[sizeof(buffer) - 1] = '\0'; ::close(fd); continue; } buffer[status] = 0; pid = atoi(buffer); if(pid) { if(pid == getpid()) { status = -1; errno = 0; } else status = kill(pid, 0); if(!status || (errno == EPERM)) { ::close(fd); delete[] _path; return false; } } ::close(fd); ::unlink(_path); } } void Lockfile::unlock(void) { if(_path) { remove(_path); delete[] _path; _path = NULL; } } bool Lockfile::isLocked(void) { if(_path) return true; return false; } #endif } // namespace ost commoncpp-7.0.1/commoncpp/serial.cpp000066400000000000000000001131721411242573100174750ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include #include #include #include #ifdef _MSWINDOWS_ #define B256000 CBR_256000 #define B128000 CBR_128000 #define B115200 CBR_115200 #define B57600 CBR_57600 #define B56000 CBR_56000 #define B38400 CBR_38400 #define B19200 CBR_19200 #define B14400 CBR_14400 #define B9600 CBR_9600 #define B4800 CBR_4800 #define B2400 CBR_2400 #define B1200 CBR_1200 #define B600 CBR_600 #define B300 CBR_300 #define B110 CBR_110 #include #else #include #ifdef HAVE_TERMIOS_H #include #endif #endif #include #include #include namespace ost { using std::streambuf; using std::iostream; using std::ios; #ifndef MAX_INPUT #define MAX_INPUT 255 #endif #ifndef MAX_CANON #define MAX_CANON MAX_INPUT #endif #ifdef __FreeBSD__ #undef _PC_MAX_INPUT #undef _PC_MAX_CANON #endif #if defined(__QNX__) #define CRTSCTS (IHFLOW | OHFLOW) #endif #if defined(_THR_UNIXWARE) || defined(__hpux) || defined(_AIX) #include #define CRTSCTS (CTSXON | RTSXOFF) #endif // IRIX #ifndef CRTSCTS #ifdef CNEW_RTSCTS #define CRTSCTS (CNEW_RTSCTS) #endif #endif #if defined(CTSXON) && defined(RTSXOFF) && !defined(CRTSCTS) #define CRTSCTS (CTSXON | RTSXOFF) #endif #ifndef CRTSCTS #define CRTSCTS 0 #endif Serial::Serial(const char *fname) { initSerial(); #if defined(_MSWINDOWS_) || defined(HAVE_TERMIOS_H) open(fname); #endif #ifdef _MSWINDOWS_ if(dev == INVALID_HANDLE_VALUE) #elif defined(HAVE_TERMIOS_H) if(dev < 0) #else if(1) #endif { error(errOpenFailed); return; } #ifdef _MSWINDOWS_ COMMTIMEOUTS CommTimeOuts ; GetCommTimeouts(dev, &CommTimeOuts); // CommTimeOuts.ReadIntervalTimeout = MAXDWORD; CommTimeOuts.ReadIntervalTimeout = 0; CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ; CommTimeOuts.ReadTotalTimeoutConstant = 0; CommTimeOuts.WriteTotalTimeoutMultiplier = 0 ; CommTimeOuts.WriteTotalTimeoutConstant = 1000; SetCommTimeouts(dev, &CommTimeOuts) ; #elif defined(HAVE_TERMIOS_H) if(!isatty(dev)) { Serial::close(); error(errOpenNoTty); return; } #endif } Serial::~Serial() { endSerial(); } void Serial::initConfig(void) { #ifdef _MSWINDOWS_ #define ASCII_XON 0x11 #define ASCII_XOFF 0x13 DCB * attr = (DCB *)current; DCB * orig = (DCB *)original; attr->DCBlength = sizeof(DCB); orig->DCBlength = sizeof(DCB); GetCommState(dev, orig); GetCommState(dev, attr); attr->DCBlength = sizeof(DCB); attr->BaudRate = 1200; attr->Parity = NOPARITY; attr->ByteSize = 8; attr->XonChar = ASCII_XON; attr->XoffChar = ASCII_XOFF; attr->XonLim = 100; attr->XoffLim = 100; attr->fOutxDsrFlow = 0; attr->fDtrControl = DTR_CONTROL_ENABLE; attr->fOutxCtsFlow = 1; attr->fRtsControl = RTS_CONTROL_ENABLE; attr->fInX = attr->fOutX = 0; attr->fBinary = true; attr->fParity = true; SetCommState(dev, attr); #elif defined(HAVE_TERMIOS_H) struct termios *attr = (struct termios *)current; struct termios *orig = (struct termios *)original; long ioflags = fcntl(dev, F_GETFL); tcgetattr(dev, (struct termios *)original); tcgetattr(dev, (struct termios *)current); attr->c_oflag = attr->c_lflag = 0; attr->c_cflag = CLOCAL | CREAD | HUPCL; attr->c_iflag = IGNBRK; memset(attr->c_cc, 0, sizeof(attr->c_cc)); attr->c_cc[VMIN] = 1; // inherit original settings, maybe we should keep more?? cfsetispeed(attr, cfgetispeed(orig)); cfsetospeed(attr, cfgetospeed(orig)); attr->c_cflag |= orig->c_cflag & (CRTSCTS | CSIZE | PARENB | PARODD | CSTOPB); attr->c_iflag |= orig->c_iflag & (IXON | IXANY | IXOFF); tcsetattr(dev, TCSANOW, attr); fcntl(dev, F_SETFL, ioflags & ~O_NDELAY); #if defined(TIOCM_RTS) && defined(TIOCMODG) int mcs = 0; ioctl(dev, TIOCMODG, &mcs); mcs |= TIOCM_RTS; ioctl(dev, TIOCMODS, &mcs); #endif #ifdef _COHERENT ioctl(dev, TIOCSRTS, 0); #endif #endif // WIN32 } void Serial::restore(void) { #ifdef _MSWINDOWS_ memcpy(current, original, sizeof(DCB)); SetCommState(dev, (DCB *)current); #elif defined(HAVE_TERMIOS_H) memcpy(current, original, sizeof(struct termios)); tcsetattr(dev, TCSANOW, (struct termios *)current); #endif } void Serial::initSerial(void) { flags.thrown = false; flags.linebuf = false; errid = errSuccess; errstr = NULL; dev = INVALID_HANDLE_VALUE; #ifdef _MSWINDOWS_ current = new DCB; original = new DCB; #elif defined(HAVE_TERMIOS_H) current = new struct termios; original = new struct termios; #endif } void Serial::endSerial(void) { #ifdef _MSWINDOWS_ if(dev == INVALID_HANDLE_VALUE && original) SetCommState(dev, (DCB *)original); if(current) delete (DCB *)current; if(original) delete (DCB *)original; #elif defined(HAVE_TERMIOS_H) if(dev < 0 && original) tcsetattr(dev, TCSANOW, (struct termios *)original); if(current) delete (struct termios *)current; if(original) delete (struct termios *)original; #endif Serial::close(); current = NULL; original = NULL; } Serial::Error Serial::error(Error err, char *errs) { errid = err; errstr = errs; if(!err) return err; if(flags.thrown) return err; // prevents recursive throws flags.thrown = true; #ifdef CCXX_EXCEPTIONS if(Thread::getException() == Thread::throwObject) throw((Serial *)this); #ifdef COMMON_STD_EXCEPTION else if(Thread::getException() == Thread::throwException) { if(!errs) errs = (char *)""; throw SerException(String(errs)); } #endif #endif return err; } int Serial::setPacketInput(int size, uint8_t btimer) { #ifdef _MSWINDOWS_ // Still to be done...... return 0; #elif defined(HAVE_TERMIOS_H) #ifdef _PC_MAX_INPUT int max = fpathconf(dev, _PC_MAX_INPUT); #else int max = MAX_INPUT; #endif struct termios *attr = (struct termios *)current; if(size > max) size = max; attr->c_cc[VEOL] = attr->c_cc[VEOL2] = 0; attr->c_cc[VMIN] = (uint8_t)size; attr->c_cc[VTIME] = btimer; attr->c_lflag &= ~ICANON; tcsetattr(dev, TCSANOW, attr); bufsize = size; return size; #endif } int Serial::setLineInput(char newline, char nl1) { #ifdef _MSWINDOWS_ // Still to be done...... return 0; #elif defined(HAVE_TERMIOS_H) struct termios *attr = (struct termios *)current; attr->c_cc[VMIN] = attr->c_cc[VTIME] = 0; attr->c_cc[VEOL] = newline; attr->c_cc[VEOL2] = nl1; attr->c_lflag |= ICANON; tcsetattr(dev, TCSANOW, attr); #ifdef _PC_MAX_CANON bufsize = fpathconf(dev, _PC_MAX_CANON); #else bufsize = MAX_CANON; #endif return bufsize; #endif } void Serial::flushInput(void) { #ifdef _MSWINDOWS_ PurgeComm(dev, PURGE_RXABORT | PURGE_RXCLEAR); #elif defined(HAVE_TERMIOS_H) tcflush(dev, TCIFLUSH); #endif } void Serial::flushOutput(void) { #ifdef _MSWINDOWS_ PurgeComm(dev, PURGE_TXABORT | PURGE_TXCLEAR); #elif defined(HAVE_TERMIOS_H) tcflush(dev, TCOFLUSH); #endif } void Serial::waitOutput(void) { #ifdef _MSWINDOWS_ #elif defined(HAVE_TERMIOS_H) #if defined(__ANDROID__) ioctl(dev, TCSBRK, 1); #else tcdrain(dev); #endif #endif } Serial &Serial::operator=(const Serial &ser) { Serial::close(); if(ser.dev < 0) return *this; #ifdef _MSWINDOWS_ HANDLE process = GetCurrentProcess(); int result = DuplicateHandle(process, ser.dev, process, &dev, DUPLICATE_SAME_ACCESS, 0, 0); if (0 == result) { memcpy(current, ser.current, sizeof(DCB)); memcpy(original, ser.original, sizeof(DCB)); } #elif defined(HAVE_TERMIOS_H) dev = dup(ser.dev); memcpy(current, ser.current, sizeof(struct termios)); memcpy(original, ser.original, sizeof(struct termios)); #endif return *this; } void Serial::open(const char * fname) { #ifndef _MSWINDOWS_ int cflags = O_RDWR | O_NDELAY; dev = ::open(fname, cflags); if(dev > -1) initConfig(); #elif defined(HAVE_TERMIOS_H) // open COMM device dev = CreateFile(fname, GENERIC_READ | GENERIC_WRITE, 0, // exclusive access NULL, // no security attrs OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL); if(dev != INVALID_HANDLE_VALUE) initConfig(); #endif } #ifdef _MSWINDOWS_ int Serial::aRead(char * Data, const int Length) { unsigned long dwLength = 0, dwError, dwReadLength; COMSTAT cs; OVERLAPPED ol; // Return zero if handle is invalid if(dev == INVALID_HANDLE_VALUE) return 0; // Read max length or only what is available ClearCommError(dev, &dwError, &cs); // If not requiring an exact byte count, get whatever is available if(Length > (int)cs.cbInQue) dwReadLength = cs.cbInQue; else dwReadLength = Length; memset(&ol, 0, sizeof(OVERLAPPED)); ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!ol.hEvent || ol.hEvent == INVALID_HANDLE_VALUE) return 0; if(dwReadLength > 0) { if(ReadFile(dev, Data, dwReadLength, &dwLength, &ol) == FALSE) { if(GetLastError() == ERROR_IO_PENDING) { WaitForSingleObject(ol.hEvent, INFINITE); GetOverlappedResult(dev, &ol, &dwLength, TRUE); } else ClearCommError(dev, &dwError, &cs); } } CloseHandle(ol.hEvent); return dwLength; } int Serial::aWrite(const char * Data, const int Length) { COMSTAT cs; unsigned long dwError = 0; OVERLAPPED ol; // Clear the com port of any error condition prior to read ClearCommError(dev, &dwError, &cs); unsigned long retSize = 0; memset(&ol, 0, sizeof(OVERLAPPED)); ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!ol.hEvent || ol.hEvent == INVALID_HANDLE_VALUE) return 0; if(WriteFile(dev, Data, Length, &retSize, &ol) == FALSE) { if(GetLastError() == ERROR_IO_PENDING) { WaitForSingleObject(ol.hEvent, INFINITE); GetOverlappedResult(dev, &ol, &retSize, TRUE); } else ClearCommError(dev, &dwError, &cs); } CloseHandle(ol.hEvent); return retSize; } #else int Serial::aRead(char *Data, const int Length) { return ::read(dev, Data, Length); } int Serial::aWrite(const char *Data, const int Length) { return ::write(dev, Data, Length); } #endif void Serial::close() { #ifdef _MSWINDOWS_ CloseHandle(dev); #else ::close(dev); #endif dev = INVALID_HANDLE_VALUE; } /* const int iAsync::getTimeOuts(unsigned long & readTimeout, unsigned long & writeTimeout) { return GetCommTimeouts(_TheHandle, &CommTimeOuts); } const int iAsync::setTimeOuts(unsigned long readTimeout, unsigned long writeTimeout) { COMMTIMEOUTS CommTimeOuts ; getTimeOuts(CommTimeOuts); CommTimeOuts.ReadIntervalTimeout = readTimeout; CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ; CommTimeOuts.ReadTotalTimeoutConstant = 0; CommTimeOuts.WriteTotalTimeoutMultiplier = 0 ; CommTimeOuts.WriteTotalTimeoutConstant = 1000; return GetCommTimeouts(_TheHandle, &CommTimeOuts); } return SetCommTimeouts(_TheHandle, &CommTimeOuts) ; { DCB dcb ; dcb.DCBlength = sizeof(DCB) ; GetCommState(_TheHandle, &dcb) ; // hardcode this stuff for now..... dcb.BaudRate = _TheBaudrate; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; dcb.fOutxDsrFlow = 0; dcb.fDtrControl = DTR_CONTROL_ENABLE ; dcb.fOutxCtsFlow = 1; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE ; dcb.fInX = dcb.fOutX = 0; dcb.XonChar = ASCII_XON; dcb.XoffChar = ASCII_XOFF; dcb.XonLim = 100; dcb.XoffLim = 100; // other various settings dcb.fBinary = TRUE; dcb.fParity = TRUE; GetCommState(_TheHandle, &dcb) ; dcb.DCBlength = sizeof(DCB) ; dcb.BaudRate = _TheBaudrate; SetCommState(_TheHandle, &dcb) ; } */ Serial::Error Serial::setSpeed(unsigned long speed) { unsigned long rate; switch(speed) { #ifdef B115200 case 115200: rate = B115200; break; #endif #ifdef B57600 case 57600: rate = B57600; break; #endif #ifdef B38400 case 38400: rate = B38400; break; #endif case 19200: rate = B19200; break; case 9600: rate = B9600; break; case 4800: rate = B4800; break; case 2400: rate = B2400; break; case 1200: rate = B1200; break; case 600: rate = B600; break; case 300: rate = B300; break; case 110: rate = B110; break; #ifdef B0 case 0: rate = B0; break; #endif default: return error(errSpeedInvalid); } #ifdef _MSWINDOWS_ DCB * dcb = (DCB *)current; dcb->DCBlength = sizeof(DCB); GetCommState(dev, dcb); dcb->BaudRate = rate; SetCommState(dev, dcb) ; #else struct termios *attr = (struct termios *)current; cfsetispeed(attr, rate); cfsetospeed(attr, rate); tcsetattr(dev, TCSANOW, attr); #endif return errSuccess; } Serial::Error Serial::setFlowControl(Flow flow) { #ifdef _MSWINDOWS_ DCB * attr = (DCB *)current; attr->XonChar = ASCII_XON; attr->XoffChar = ASCII_XOFF; attr->XonLim = 100; attr->XoffLim = 100; switch(flow) { case flowSoft: attr->fInX = attr->fOutX = 1; break; case flowBoth: attr->fInX = attr->fOutX = 1; case flowHard: attr->fOutxCtsFlow = 1; attr->fRtsControl = RTS_CONTROL_HANDSHAKE; break; case flowNone: break; default: return error(errFlowInvalid); } SetCommState(dev, attr); #else struct termios *attr = (struct termios *)current; attr->c_cflag &= ~CRTSCTS; attr->c_iflag &= ~(IXON | IXANY | IXOFF); switch(flow) { case flowSoft: attr->c_iflag |= (IXON | IXANY | IXOFF); break; case flowBoth: attr->c_iflag |= (IXON | IXANY | IXOFF); case flowHard: attr->c_cflag |= CRTSCTS; break; case flowNone: break; default: return error(errFlowInvalid); } tcsetattr(dev, TCSANOW, attr); #endif return errSuccess; } Serial::Error Serial::setStopBits(int bits) { #ifdef _MSWINDOWS_ DCB * attr = (DCB *)current; switch(bits) { case 1: attr->StopBits = ONESTOPBIT; break; case 2: attr->StopBits = TWOSTOPBITS; break; default: return error(errStopbitsInvalid); } SetCommState(dev, attr); #else struct termios *attr = (struct termios *)current; attr->c_cflag &= ~CSTOPB; switch(bits) { case 1: break; case 2: attr->c_cflag |= CSTOPB; break; default: return error(errStopbitsInvalid); } tcsetattr(dev, TCSANOW, attr); #endif return errSuccess; } Serial::Error Serial::setCharBits(int bits) { #ifdef _MSWINDOWS_ DCB * attr = (DCB *)current; switch(bits) { case 5: case 6: case 7: case 8: attr->ByteSize = bits; break; default: return error(errCharsizeInvalid); } SetCommState(dev, attr); #else struct termios *attr = (struct termios *)current; attr->c_cflag &= ~CSIZE; switch(bits) { case 5: attr->c_cflag |= CS5; break; case 6: attr->c_cflag |= CS6; break; case 7: attr->c_cflag |= CS7; break; case 8: attr->c_cflag |= CS8; break; default: return error(errCharsizeInvalid); } tcsetattr(dev, TCSANOW, attr); #endif return errSuccess; } Serial::Error Serial::setParity(Parity parity) { #ifdef _MSWINDOWS_ DCB * attr = (DCB *)current; switch(parity) { case parityEven: attr->Parity = EVENPARITY; break; case parityOdd: attr->Parity = ODDPARITY; break; case parityNone: attr->Parity = NOPARITY; break; default: return error(errParityInvalid); } SetCommState(dev, attr); #else struct termios *attr = (struct termios *)current; attr->c_cflag &= ~(PARENB | PARODD); switch(parity) { case parityEven: attr->c_cflag |= PARENB; break; case parityOdd: attr->c_cflag |= (PARENB | PARODD); break; case parityNone: break; default: return error(errParityInvalid); } tcsetattr(dev, TCSANOW, attr); #endif return errSuccess; } void Serial::sendBreak(void) { #ifdef _MSWINDOWS_ SetCommBreak(dev); Thread::sleep(100L); ClearCommBreak(dev); #else tcsendbreak(dev, 0); #endif } void Serial::toggleDTR(timeout_t millisec) { #ifdef _MSWINDOWS_ EscapeCommFunction(dev, CLRDTR); if(millisec) { Thread::sleep(millisec); EscapeCommFunction(dev, SETDTR); } #else struct termios tty, old; tcgetattr(dev, &tty); tcgetattr(dev, &old); cfsetospeed(&tty, B0); cfsetispeed(&tty, B0); tcsetattr(dev, TCSANOW, &tty); if(millisec) { Thread::sleep(millisec); tcsetattr(dev, TCSANOW, &old); } #endif } bool Serial::isPending(Pending pending, timeout_t timeout) { #ifdef _MSWINDOWS_ unsigned long dwError; COMSTAT cs; ClearCommError(dev, &dwError, &cs); if(timeout == 0 || ((pending == pendingInput) && (0 != cs.cbInQue)) || ((pending == pendingOutput) && (0 != cs.cbOutQue)) || (pending == pendingError)) { switch(pending) { case pendingInput: return (0 != cs.cbInQue); case pendingOutput: return (0 != cs.cbOutQue); case pendingError: return false; } } else { OVERLAPPED ol; DWORD dwMask; DWORD dwEvents = 0; BOOL suc; memset(&ol, 0, sizeof(OVERLAPPED)); ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!ol.hEvent) return false; if(pending == pendingInput) dwMask = EV_RXCHAR; else if(pending == pendingOutput) dwMask = EV_TXEMPTY; else // on error dwMask = EV_ERR; SetCommMask(dev, dwMask); // let's wait for event or timeout if((suc = WaitCommEvent(dev, &dwEvents, &ol)) == FALSE) { if(GetLastError() == ERROR_IO_PENDING) { DWORD transferred; dwError = WaitForSingleObject(ol.hEvent, timeout); if (dwError != WAIT_OBJECT_0) SetCommMask(dev, 0); suc = GetOverlappedResult(dev, &ol, &transferred, TRUE); if (suc) { suc = (dwEvents & dwMask) ? TRUE : FALSE; } } else ClearCommError(dev, &dwError, &cs); } CloseHandle(ol.hEvent); if(suc == FALSE) return false; return true; } #else int status = 0; #ifdef HAVE_POLL struct pollfd pfd; pfd.fd = dev; pfd.revents = 0; switch(pending) { case pendingInput: pfd.events = POLLIN; break; case pendingOutput: pfd.events = POLLOUT; break; case pendingError: pfd.events = POLLERR | POLLHUP; break; } status = 0; while(status < 1) { if(timeout == TIMEOUT_INF) status = poll(&pfd, 1, -1); else status = poll(&pfd, 1, timeout); if(status < 1) { if(status == -1 && errno == EINTR) continue; return false; } } if(pfd.revents & pfd.events) return true; #else struct timeval tv; fd_set grp; struct timeval *tvp = &tv; if(timeout == TIMEOUT_INF) tvp = NULL; else { tv.tv_usec = (timeout % 1000) * 1000; tv.tv_sec = timeout / 1000; } FD_ZERO(&grp); FD_SET(dev, &grp); switch(pending) { case pendingInput: status = select(dev + 1, &grp, NULL, NULL, tvp); break; case pendingOutput: status = select(dev + 1, NULL, &grp, NULL, tvp); break; case pendingError: status = select(dev + 1, NULL, NULL, &grp, tvp); break; } if(status < 1) return false; if(FD_ISSET(dev, &grp)) return true; #endif #endif // WIN32 return false; } TTYStream::TTYStream(const char *filename, timeout_t to) : streambuf(), Serial(filename), iostream((streambuf *)this) { gbuf = pbuf = NULL; timeout = to; if(INVALID_HANDLE_VALUE != dev) allocate(); } TTYStream::TTYStream() : streambuf(), Serial(), iostream((streambuf *)this) { timeout = 0; gbuf = pbuf = NULL; } TTYStream::~TTYStream() { endStream(); endSerial(); } void TTYStream::endStream(void) { if(bufsize) sync(); if(gbuf) { delete[] gbuf; gbuf = NULL; } if(pbuf) { delete[] pbuf; pbuf = NULL; } bufsize = 0; clear(); } void TTYStream::allocate(void) { if(INVALID_HANDLE_VALUE == dev) return; #ifdef _PC_MAX_INPUT bufsize = fpathconf(dev, _PC_MAX_INPUT); #else bufsize = MAX_INPUT; #endif gbuf = new char[bufsize]; pbuf = new char[bufsize]; if(!pbuf || !gbuf) { error(errResourceFailure); return; } clear(); #if !(defined(STLPORT) || defined(__KCC)) setg(gbuf, gbuf + bufsize, 0); #endif setg(gbuf, gbuf + bufsize, gbuf + bufsize); setp(pbuf, pbuf + bufsize); } int TTYStream::doallocate() { if(bufsize) return 0; allocate(); return 1; } void TTYStream::interactive(bool iflag) { #ifdef _MSWINDOWS_ if(dev == INVALID_HANDLE_VALUE) #else if(dev < 0) #endif return; if(bufsize >= 1) endStream(); if(iflag) { // setting to unbuffered mode bufsize = 1; gbuf = new char[bufsize]; #if !(defined(STLPORT) || defined(__KCC)) #if defined(__GNUC__) && (__GNUC__ < 3) setb(0,0); #endif #endif setg(gbuf, gbuf+bufsize, gbuf+bufsize); setp(pbuf, pbuf); return; } if(bufsize < 2) allocate(); } int TTYStream::uflow(void) { int rlen; uint8_t ch; if(bufsize < 2) { if(timeout) { if(Serial::isPending(pendingInput, timeout)) rlen = aRead((char *)&ch, 1); else rlen = -1; } else rlen = aRead((char *)&ch, 1); if(rlen < 1) { if(rlen < 0) clear(ios::failbit | rdstate()); return EOF; } return ch; } else { ch = underflow(); gbump(1); return ch; } } int TTYStream::underflow(void) { ssize_t rlen = 1; if(!gptr()) return EOF; if(gptr() < egptr()) return (uint8_t)*gptr(); rlen = (ssize_t)((gbuf + bufsize) - eback()); if(timeout && !Serial::isPending(pendingInput, timeout)) rlen = -1; else rlen = aRead((char *)eback(), rlen); if(rlen < 1) { if(rlen < 0) { clear(ios::failbit | rdstate()); error(errInput); } return EOF; } setg(eback(), eback(), eback() + rlen); return (uint8_t) *gptr(); } int TTYStream::sync(void) { if(bufsize > 1 && pbase() && ((pptr() - pbase()) > 0)) { overflow(0); waitOutput(); setp(pbuf, pbuf + bufsize); } setg(gbuf, gbuf + bufsize, gbuf + bufsize); return 0; } int TTYStream::overflow(int c) { uint8_t ch; ssize_t rlen, req; if(bufsize < 2) { if(c == EOF) return 0; ch = (uint8_t)(c); rlen = aWrite((char *)&ch, 1); if(rlen < 1) { if(rlen < 0) clear(ios::failbit | rdstate()); return EOF; } else return c; } if(!pbase()) return EOF; req = (ssize_t)(pptr() - pbase()); if(req) { rlen = aWrite((char *)pbase(), req); if(rlen < 1) { if(rlen < 0) clear(ios::failbit | rdstate()); return EOF; } req -= rlen; } if(req) // memmove(pptr(), pptr() + rlen, req); memmove(pbuf, pbuf + rlen, req); setp(pbuf + req, pbuf + bufsize); if(c != EOF) { *pptr() = (uint8_t)c; pbump(1); } return c; } bool TTYStream::isPending(Pending pending, timeout_t timer) { // if(pending == pendingInput && in_avail()) // return true; // else if(pending == pendingOutput) // flush(); return Serial::isPending(pending, timer); } ttystream::ttystream() : TTYStream() { setError(false); } ttystream::ttystream(const char *name) : TTYStream() { setError(false); open(name); } void ttystream::close(void) { #ifdef _MSWINDOWS_ if (INVALID_HANDLE_VALUE == dev) #else if(dev < 0) #endif return; endStream(); restore(); TTYStream::close(); } void ttystream::open(const char *name) { const char *cpp; char *cp; char pathname[256]; size_t namelen; long opt; if (INVALID_HANDLE_VALUE != dev) { restore(); close(); } cpp = strrchr(name, ':'); if(cpp) namelen = cpp - name; else namelen = strlen(name); cp = pathname; #ifndef _MSWINDOWS_ if(*name != '/') { setString(pathname, sizeof(pathname), "/dev/"); cp += 5; } if((cp - pathname) + namelen > 255) { error(errResourceFailure); return; } #endif setString(cp, pathname - cp + sizeof(pathname), name); cp += namelen; #ifdef _MSWINDOWS_ *cp++ = ':'; #endif *cp = 0; Serial::open(pathname); if(INVALID_HANDLE_VALUE == dev) { error(errOpenFailed); return; } allocate(); setString(pathname, sizeof(pathname), name + namelen); cp = pathname + 1; if(*pathname == ':') cp = strtok(cp, ","); else cp = NULL; while(cp) { switch(*cp) { case 'h': case 'H': setFlowControl(flowHard); break; case 's': case 'S': setFlowControl(flowSoft); break; case 'b': case 'B': setFlowControl(flowBoth); break; case 'n': case 'N': setParity(parityNone); break; case 'O': case 'o': setParity(parityOdd); break; case 'e': case 'E': setParity(parityEven); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': opt = atol(cp); if(opt == 1 || opt == 2) { setStopBits((int)opt); break; } if(opt > 4 && opt < 9) { setCharBits((int)opt); break; } setSpeed(opt); break; default: error(errOptionInvalid); } cp = strtok(NULL, ","); } } TTYSession::TTYSession(const char *filename, int pri, int stack) : Thread(pri, stack), TTYStream(filename) { setError(false); } TTYSession::~TTYSession() { terminate(); endSerial(); } #ifndef _MSWINDOWS_ // Not supporting this right now........ // SerialPort::SerialPort(SerialService *svc, const char *name) : Serial(name), detect_pending(true), detect_output(false), detect_disconnect(true) { next = prev = NULL; service = NULL; #ifdef _MSWINDOWS_ if(INVALID_HANDLE_VALUE != dev) #else if(dev > -1) #endif { setError(false); service = svc; svc->attach(this); } } SerialPort::~SerialPort() { if(service) service->detach(this); endSerial(); } void SerialPort::expired(void) { } void SerialPort::pending(void) { } void SerialPort::disconnect(void) { } void SerialPort::output(void) { } void SerialPort::setTimer(timeout_t ptimer) { TimerPort::setTimer(ptimer); service->update(); } void SerialPort::incTimer(timeout_t ptimer) { TimerPort::incTimer(ptimer); service->update(); } void SerialPort::setDetectPending( bool val ) { if ( detect_pending != val ) { detect_pending = val; #ifdef USE_POLL if ( ufd ) { if ( val ) { ufd->events |= POLLIN; } else { ufd->events &= ~POLLIN; } } #endif service->update(); } } void SerialPort::setDetectOutput( bool val ) { if ( detect_output != val ) { detect_output = val; #ifdef USE_POLL if ( ufd ) { if ( val ) { ufd->events |= POLLOUT; } else { ufd->events &= ~POLLOUT; } } #endif service->update(); } } SerialService::SerialService(int pri, size_t stack, const char *id) : Thread(pri, stack), Mutex() { long opt; first = last = NULL; count = 0; FD_ZERO(&connect); if(::pipe(iosync)) { #ifdef CCXX_EXCEPTIONS switch(Thread::getException()) { case throwObject: throw(this); return; #ifdef COMMON_STD_EXCEPTION case throwException: throw(ThrException("no service pipe")); return; #endif default: return; } #else return; #endif } hiwater = iosync[0] + 1; FD_SET(iosync[0], &connect); opt = fcntl(iosync[0], F_GETFL); fcntl(iosync[0], F_SETFL, opt | O_NDELAY); } SerialService::~SerialService() { update(0); terminate(); SerialPort *port = first; while (port) { SerialPort *tmp = port; port = port->next; delete tmp; } } void SerialService::onUpdate(uint8_t flag) { } void SerialService::onEvent(void) { } void SerialService::onCallback(SerialPort *port) { } void SerialService::attach(SerialPort *port) { enterMutex(); #ifdef USE_POLL port->ufd = 0; #endif if(last) last->next = port; port->prev = last; last = port; FD_SET(port->dev, &connect); if(port->dev >= hiwater) hiwater = port->dev + 1; if(!first) { first = port; leaveMutex(); ++count; start(); } else { leaveMutex(); update(); ++count; } } void SerialService::detach(SerialPort *port) { enterMutex(); #ifndef USE_POLL FD_CLR(port->dev, &connect); #endif if(port->prev) port->prev->next = port->next; else first = port->next; if(port->next) port->next->prev = port->prev; else last = port->prev; --count; leaveMutex(); update(); } void SerialService::update(uint8_t flag) { if(::write(iosync[1], (char *)&flag, 1) < 1) { #ifdef CCXX_EXCEPTIONS switch(Thread::getException()) { case throwObject: throw(this); return; #ifdef COMMON_STD_EXCEPTION case throwException: throw(ThrException("update failed")); return; #endif default: return; } #else return; #endif } } void SerialService::run(void) { timeout_t timer, expires; SerialPort *port; uint8_t buf; #ifdef USE_POLL Poller mfd; pollfd *p_ufd; int lastcount = 0; // initialize ufd in all attached ports : // probably don't need this but it can't hurt. enterMutex(); port = first; while(port) { port->ufd = 0; port = port->next; } leaveMutex(); #else struct timeval timeout, *tvp; fd_set inp, out, err; int dev; FD_ZERO(&inp); FD_ZERO(&out); FD_ZERO(&err); #endif for(;;) { timer = TIMEOUT_INF; while(1 == ::read(iosync[0], (char *)&buf, 1)) { if(buf) { onUpdate(buf); continue; } Thread::exit(); } #ifdef USE_POLL bool reallocate = false; enterMutex(); onEvent(); port = first; while(port) { onCallback(port); if ( ( p_ufd = port->ufd ) ) { if ( ( POLLHUP | POLLNVAL ) & p_ufd->revents ) { // Avoid infinite loop from disconnected sockets port->detect_disconnect = false; p_ufd->events &= ~POLLHUP; port->disconnect(); } if ( ( POLLIN | POLLPRI ) & p_ufd->revents ) port->pending(); if ( POLLOUT & p_ufd->revents ) port->output(); } else { reallocate = true; } retry: expires = port->getTimer(); if(expires > 0) if(expires < timer) timer = expires; if(!expires) { port->endTimer(); port->expired(); goto retry; } port = port->next; } // // reallocate things if we saw a ServerPort without // ufd set ! if ( reallocate || ( ( count + 1 ) != lastcount ) ) { lastcount = count + 1; p_ufd = mfd.getList( count + 1 ); // Set up iosync polling p_ufd->fd = iosync[0]; p_ufd->events = POLLIN | POLLHUP; p_ufd ++; port = first; while(port) { p_ufd->fd = port->dev; p_ufd->events = ( port->detect_disconnect ? POLLHUP : 0 ) | ( port->detect_output ? POLLOUT : 0 ) | ( port->detect_pending ? POLLIN : 0 ) ; port->ufd = p_ufd; p_ufd ++; port = port->next; } } leaveMutex(); poll( mfd.getList(), count + 1, timer ); #else enterMutex(); onEvent(); port = first; while(port) { onCallback(port); dev = port->dev; if(FD_ISSET(dev, &err)) { port->detect_disconnect = false; port->disconnect(); } if(FD_ISSET(dev, &inp)) port->pending(); if(FD_ISSET(dev, &out)) port->output(); retry: expires = port->getTimer(); if(expires > 0) if(expires < timer) timer = expires; if(!expires) { port->endTimer(); port->expired(); goto retry; } port = port->next; } FD_ZERO(&inp); FD_ZERO(&out); FD_ZERO(&err); int so; port = first; while(port) { so = port->dev; if(port->detect_pending) FD_SET(so, &inp); if(port->detect_output) FD_SET(so, &out); if(port->detect_disconnect) FD_SET(so, &err); port = port->next; } leaveMutex(); if(timer == TIMEOUT_INF) tvp = NULL; else { tvp = &timeout; timeout.tv_sec = timer / 1000; timeout.tv_usec = (timer % 1000) * 1000; } select(hiwater, &inp, &out, &err, tvp); #endif } } #endif } // namespace ost commoncpp-7.0.1/commoncpp/slog.cpp000066400000000000000000000261721411242573100171650ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #ifdef __BORLANDC__ #include #include #else #include #include #endif #ifdef HAVE_SYSLOG_H #include #endif namespace ost { using std::streambuf; using std::ofstream; using std::ostream; using std::clog; using std::endl; using std::ios; Slog slog; Slog::Slog(void) : streambuf() ,ostream((streambuf *)this) { _enable = true; _level = levelDebug; _clogEnable = true; syslog = NULL; } Slog::~Slog(void) { #ifdef HAVE_SYSLOG_H closelog(); #else if(syslog) fclose(syslog); #endif } void Slog::close(void) { pthread_mutex_lock(&lock); #ifdef HAVE_SYSLOG_H closelog(); #else if(syslog) fclose(syslog); syslog = NULL; #endif pthread_mutex_unlock(&lock); } void Slog::open(const char *ident, Class grp) { const char *cp; pthread_mutex_lock(&lock); #ifdef HAVE_SYSLOG_H cp = strrchr(ident, '/'); if(cp) ident = ++cp; int fac; switch(grp) { case classUser: fac = LOG_USER; break; case classDaemon: fac = LOG_DAEMON; break; case classAudit: #ifdef LOG_AUTHPRIV fac = LOG_AUTHPRIV; break; #endif case classSecurity: fac = LOG_AUTH; break; case classLocal0: fac = LOG_LOCAL0; break; case classLocal1: fac = LOG_LOCAL1; break; case classLocal2: fac = LOG_LOCAL2; break; case classLocal3: fac = LOG_LOCAL3; break; case classLocal4: fac = LOG_LOCAL4; break; case classLocal5: fac = LOG_LOCAL5; break; case classLocal6: fac = LOG_LOCAL6; break; case classLocal7: fac = LOG_LOCAL7; break; default: fac = LOG_USER; break; } openlog(ident, 0, fac); #else if(syslog) fclose(syslog); size_t size = strlen(ident) + 1; char *buf = new char[size]; String::set(buf, size, ident); cp = (const char *)buf; buf = strrchr(buf, '.'); if(buf) { if(!stricmp(buf, ".exe")) { String::set(buf, size, ".log"); } } syslog = fopen(cp, "a"); #endif pthread_mutex_unlock(&lock); } void Slog::error(const char *format, ...) { Thread *thread = Thread::get(); va_list args; va_start(args, format); overflow(EOF); if(!thread) { va_end(args); return; } error(); vsnprintf(thread->msgbuf, sizeof(thread->msgbuf), format, args); thread->msgpos = strlen(thread->msgbuf); overflow(EOF); va_end(args); } void Slog::warn(const char *format, ...) { Thread *thread = Thread::get(); va_list args; if(!thread) return; va_start(args, format); overflow(EOF); warn(); vsnprintf(thread->msgbuf, sizeof(thread->msgbuf), format, args); thread->msgpos = strlen(thread->msgbuf); overflow(EOF); va_end(args); } void Slog::debug(const char *format, ...) { Thread *thread = Thread::get(); va_list args; if(!thread) return; va_start(args, format); overflow(EOF); debug(); vsnprintf(thread->msgbuf, sizeof(thread->msgbuf), format, args); thread->msgpos = strlen(thread->msgbuf); overflow(EOF); va_end(args); } void Slog::emerg(const char *format, ...) { Thread *thread = Thread::get(); va_list args; if(!thread) return; va_start(args, format); overflow(EOF); emerg(); vsnprintf(thread->msgbuf, sizeof(thread->msgbuf), format, args); thread->msgpos = strlen(thread->msgbuf); overflow(EOF); va_end(args); } void Slog::alert(const char *format, ...) { Thread *thread = Thread::get(); va_list args; if(!thread) return; va_start(args, format); overflow(EOF); alert(); vsnprintf(thread->msgbuf, sizeof(thread->msgbuf), format, args); thread->msgpos = strlen(thread->msgbuf); overflow(EOF); va_end(args); } void Slog::critical(const char *format, ...) { Thread *thread = Thread::get(); va_list args; if(!thread) return; va_start(args, format); overflow(EOF); critical(); vsnprintf(thread->msgbuf, sizeof(thread->msgbuf), format, args); thread->msgpos = strlen(thread->msgbuf); overflow(EOF); va_end(args); } void Slog::notice(const char *format, ...) { Thread *thread = Thread::get(); va_list args; if(!thread) return; va_start(args, format); overflow(EOF); notice(); vsnprintf(thread->msgbuf, sizeof(thread->msgbuf), format, args); thread->msgpos = strlen(thread->msgbuf); overflow(EOF); va_end(args); } void Slog::info(const char *format, ...) { Thread *thread = Thread::get(); va_list args; if(!thread) return; va_start(args, format); overflow(EOF); info(); vsnprintf(thread->msgbuf, sizeof(thread->msgbuf), format, args); thread->msgpos = strlen(thread->msgbuf); overflow(EOF); va_end(args); } int Slog::overflow(int c) { Thread *thread = Thread::get(); if(!thread) return c; if(c == '\n' || !c || c == EOF) { if(!thread->msgpos) return c; thread->msgbuf[thread->msgpos] = 0; pthread_mutex_lock(&lock); if (_enable) #ifdef HAVE_SYSLOG_H ::syslog(priority, "%s", thread->msgbuf); #else { time_t now; struct tm *dt; time(&now); dt = localtime(&now); char buf[256]; const char *p = "unknown"; switch(priority) { case levelEmergency: p = "emerg"; break; case levelInfo: p = "info"; break; case levelError: p = "error"; break; case levelAlert: p = "alert"; break; case levelDebug: p = "debug"; break; case levelNotice: p = "notice"; break; case levelWarning: p = "warn"; break; case levelCritical: p = "crit"; break; } snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d [%s] %s\n", dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday, dt->tm_hour, dt->tm_min, dt->tm_sec, p, thread->msgbuf); if(syslog) fputs(buf, syslog); // syslog << "[" << priority << "] " << thread->msgbuf << endl; } #endif pthread_mutex_unlock(&lock); thread->msgpos = 0; if ( _enable && _clogEnable #ifndef _MSWINDOWS_ && (getppid() > 1) #endif ) clog << thread->msgbuf << endl; _enable = true; return c; } if (thread->msgpos < (int)(sizeof(thread->msgbuf) - 1)) thread->msgbuf[thread->msgpos++] = c; return c; } Slog &Slog::operator()(const char *ident, Class grp, Level lev) { Thread *thread = Thread::get(); if(!thread) return *this; thread->msgpos = 0; _enable = true; open(ident, grp); return this->operator()(lev, grp); } Slog &Slog::operator()(Level lev, Class grp) { Thread *thread = Thread::get(); if(!thread) return *this; thread->msgpos = 0; if(_level >= lev) _enable = true; else _enable = false; #ifdef HAVE_SYSLOG_H switch(lev) { case levelEmergency: priority = LOG_EMERG; break; case levelAlert: priority = LOG_ALERT; break; case levelCritical: priority = LOG_CRIT; break; case levelError: priority = LOG_ERR; break; case levelWarning: priority = LOG_WARNING; break; case levelNotice: priority = LOG_NOTICE; break; case levelInfo: priority = LOG_INFO; break; case levelDebug: priority = LOG_DEBUG; break; } switch(grp) { case classAudit: #ifdef LOG_AUTHPRIV priority |= LOG_AUTHPRIV; break; #endif case classSecurity: priority |= LOG_AUTH; break; case classUser: priority |= LOG_USER; break; case classDaemon: priority |= LOG_DAEMON; break; case classDefault: priority |= LOG_USER; break; case classLocal0: priority |= LOG_LOCAL0; break; case classLocal1: priority |= LOG_LOCAL1; break; case classLocal2: priority |= LOG_LOCAL2; break; case classLocal3: priority |= LOG_LOCAL3; break; case classLocal4: priority |= LOG_LOCAL4; break; case classLocal5: priority |= LOG_LOCAL5; break; case classLocal6: priority |= LOG_LOCAL6; break; case classLocal7: priority |= LOG_LOCAL7; break; } #else priority = lev; #endif return *this; } Slog &Slog::operator()(void) { return *this; } } // namespace ost commoncpp-7.0.1/commoncpp/socket.cpp000066400000000000000000000651321411242573100175100ustar00rootroot00000000000000// 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-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include #include #ifdef _MSWINDOWS_ #include #define _IOLEN64 (unsigned) #define _IORET64 (int) typedef int socklen_t; #define socket_errno WSAGetLastError() #else #include #include #ifdef HAVE_NET_IP6_H #include #endif #define socket_errno errno # ifndef O_NONBLOCK # define O_NONBLOCK O_NDELAY # endif # ifdef IPPROTO_IP # ifndef SOL_IP # define SOL_IP IPPROTO_IP # endif // !SOL_IP # endif // IPPROTO_IP #endif // !WIN32 #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK (in_addr_t)0x7f000001 #endif #ifdef HAVE_NETINET_IN_H #include #endif #if defined(__hpux) #define _XOPEN_SOURCE_EXTENDED #endif #ifdef HAVE_NET_IF_H #include #endif #ifndef _IOLEN64 #define _IOLEN64 #endif #ifndef _IORET64 #define _IORET64 #endif namespace ost { #if defined(_MSWINDOWS_) && !defined(__MINGW32__) socket_t Socket::dupSocket(socket_t so, enum Socket::State state) { if (state == Socket::STREAM) return dup((int)so); HANDLE pidHandle = GetCurrentProcess(); HANDLE dupHandle; if(DuplicateHandle(pidHandle, reinterpret_cast(so), pidHandle, &dupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) return reinterpret_cast(dupHandle); return (socket_t)(-1); } # define DUP_SOCK(s,state) dupSocket(s,state) #else socket_t Socket::dupSocket(socket_t so, State state) { return dup(so); } #endif void Socket::setSocket(void) { flags.thrown = false; flags.broadcast = false; flags.route = true; flags.keepalive = false; flags.loopback = true; flags.multicast = false; flags.linger = false; flags.ttl = 1; errid = errSuccess; errstr = NULL; syserr = 0; state = INITIAL; so = INVALID_SOCKET; } void Socket::endSocket(void) { if(Socket::state == STREAM) { state = INITIAL; if(so != INVALID_SOCKET) { SOCKET sosave = so; so = INVALID_SOCKET; release(sosave); } return; } state = INITIAL; if(so == INVALID_SOCKET) return; #ifdef SO_LINGER struct linger linger; if(flags.linger) { linger.l_onoff = 1; linger.l_linger = 60; } else linger.l_onoff = linger.l_linger = 0; setsockopt(so, SOL_SOCKET, SO_LINGER, (char *)&linger, (socklen_t)sizeof(linger)); #endif // shutdown(so, 2); ucommon::Socket::release(); } Socket::Socket() : ucommon::Socket() { setSocket(); } Socket::Socket(int domain, int type, int protocol) : ucommon::Socket() { setSocket(); so = socket(domain, type, protocol); if(so == INVALID_SOCKET) { error(errCreateFailed,(char *)"Could not create socket",socket_errno); return; } #ifdef SO_NOSIGPIPE int opt = 1; setsockopt(so, SOL_SOCKET, SO_NOSIGPIPE, (char *)&opt, sizeof(opt)); #endif state = AVAILABLE; } Socket::Socket(socket_t fd) : ucommon::Socket() { setSocket(); if (fd == INVALID_SOCKET) { error(errCreateFailed,(char *)"Invalid socket handle passed",0); return; } so = fd; state = AVAILABLE; } Socket::Socket(const Socket &orig) : ucommon::Socket() { setSocket(); so = dupSocket(orig.so,orig.state); if(so == INVALID_SOCKET) error(errCopyFailed,(char *)"Could not duplicate socket handle",socket_errno); state = orig.state; } Socket::~Socket() { endSocket(); } Socket::Error Socket::error(Error err, const char *errs, long systemError) const { errid = err; errstr = errs; syserr = systemError; if(!err) return err; if(flags.thrown) return err; // prevents recursive throws flags.thrown = true; #ifdef CCXX_EXCEPTIONS switch(Thread::getException()) { case Thread::throwObject: THROW((Socket *)this); case Thread::throwException: if(!errs) errs = (char *)""; THROW(SockException(String(errs), err, systemError)); case Thread::throwNothing: break; } #endif return err; } #ifdef _MSWINDOWS_ Socket::Error Socket::connectError(void) const { const char* str = "Could not connect to remote host"; switch(WSAGetLastError()) { case WSAENETDOWN: return error(errResourceFailure,str,socket_errno); case WSAEINPROGRESS: return error(errConnectBusy,str,socket_errno); case WSAEADDRNOTAVAIL: return error(errConnectInvalid,str,socket_errno); case WSAECONNREFUSED: return error(errConnectRefused,str,socket_errno); case WSAENETUNREACH: return error(errConnectNoRoute,str,socket_errno); default: return error(errConnectFailed,str,socket_errno); } } #else Socket::Error Socket::connectError(void) const { char* str = (char *)"Could not connect to remote host"; switch(errno) { #ifdef EHOSTUNREACH case EHOSTUNREACH: return error(errConnectNoRoute,str,socket_errno); #endif #ifdef ENETUNREACH case ENETUNREACH: return error(errConnectNoRoute,str,socket_errno); #endif case EINPROGRESS: return error(errConnectBusy,str,socket_errno); #ifdef EADDRNOTAVAIL case EADDRNOTAVAIL: return error(errConnectInvalid,str,socket_errno); #endif case ECONNREFUSED: return error(errConnectRefused,str,socket_errno); case ETIMEDOUT: return error(errConnectTimeout,str,socket_errno); default: return error(errConnectFailed,str,socket_errno); } } #endif Socket::Error Socket::sendLimit(int limit) { #ifdef SO_SNDLOWAT if(setsockopt(so, SOL_SOCKET, SO_SNDLOWAT, (char *)&limit, sizeof(limit))) return errInvalidValue; return errSuccess; #else return errServiceUnavailable; #endif } Socket::Error Socket::receiveLimit(int limit) { #ifdef SO_RCVLOWAT if(setsockopt(so, SOL_SOCKET, SO_RCVLOWAT, (char *)&limit, sizeof(limit))) return errInvalidValue; return errSuccess; #else return errServiceUnavailable; #endif } Socket::Error Socket::sendTimeout(timeout_t to) { #ifdef SO_SNDTIMEO struct timeval tv; tv.tv_sec = to / 1000; tv.tv_usec = (to % 1000) * 1000; if(setsockopt(so, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv))) return errInvalidValue; return errSuccess; #else return errServiceUnavailable; #endif } Socket::Error Socket::receiveTimeout(timeout_t to) { #ifdef SO_RCVTIMEO struct timeval tv; tv.tv_sec = to / 1000; tv.tv_usec = (to % 1000) * 1000; if(setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv))) return errInvalidValue; return errSuccess; #else return errServiceUnavailable; #endif } Socket::Error Socket::sendBuffer(unsigned bufsize) { #ifdef SO_SNDBUF if(setsockopt(so, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(bufsize))) return errInvalidValue; return errSuccess; #else return errServiceUnavailable; #endif } Socket::Error Socket::bufferSize(unsigned bufsize) { Error err = receiveBuffer(bufsize); if(err == errSuccess) err = sendBuffer(bufsize); return err; } Socket::Error Socket::receiveBuffer(unsigned bufsize) { #ifdef SO_RCVBUF if(setsockopt(so, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize))) return errInvalidValue; return errSuccess; #else return errServiceUnavailable; #endif } Socket::Error Socket::setBroadcast(bool enable) { int opt = (enable ? 1 : 0); if(setsockopt(so, SOL_SOCKET, SO_BROADCAST, (char *)&opt, (socklen_t)sizeof(opt))) return error(errBroadcastDenied,(char *)"Could not set socket broadcast option",socket_errno); flags.broadcast = enable; return errSuccess; } Socket::Error Socket::setMulticastByFamily(bool enable, Family family) { socklen_t len; switch(family) { #ifdef CCXX_IPV6 case IPV6: struct sockaddr_in6 addr; len = sizeof(addr); if(enable == flags.multicast) return errSuccess; flags.multicast = enable; if(enable) getsockname(so, (struct sockaddr *)&addr, &len); else memset(&addr.sin6_addr, 0, sizeof(addr.sin6_addr)); setsockopt(so, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&addr.sin6_addr, sizeof(addr.sin6_addr)); return errSuccess; #endif case IPV4: #ifdef IP_MULTICAST_IF struct sockaddr_in addr4; len = sizeof(addr4); if(enable == flags.multicast) return errSuccess; flags.multicast = enable; if(enable) getsockname(so, (struct sockaddr *)&addr4, &len); else memset(&addr4.sin_addr, 0, sizeof(addr4.sin_addr)); setsockopt(so, IPPROTO_IP, IP_MULTICAST_IF, (char *)&addr4.sin_addr, sizeof(addr4.sin_addr)); return errSuccess; #endif default: return error(errServiceUnavailable,(char *)"Multicast not supported"); } } Socket::Error Socket::setTimeToLiveByFamily(uint8_t ttl, Family fam) { if(!flags.multicast) return error(errMulticastDisabled,(char *)"Multicast not enabled on socket"); switch(fam) { #ifdef CCXX_IPV6 case IPV6: flags.ttl = ttl; setsockopt(so, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ttl, sizeof(ttl)); return errSuccess; #endif case IPV4: #ifdef IP_MULTICAST_TTL flags.ttl = ttl; setsockopt(so, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl)); return errSuccess; #endif default: return error(errServiceUnavailable, (char *)"Multicast not supported"); } } Socket::Error Socket::setLoopbackByFamily(bool enable, Family family) { uint8_t loop; if(!flags.multicast) return error(errMulticastDisabled,(char *)"Multicast not enabled on socket"); if(enable) loop = 1; else loop = 0; flags.loopback = enable; switch(family) { #ifdef CCXX_IPV6 case IPV6: setsockopt(so, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *)&loop, sizeof(loop)); return errSuccess; #endif case IPV4: #ifdef IP_MULTICAST_LOOP setsockopt(so, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loop, sizeof(loop)); return errSuccess; #endif default: return error(errServiceUnavailable,(char *)"Multicast not supported"); } } Socket::Error Socket::join(const ucommon::Socket::address &ia, int iface) { switch(ucommon::Socket::join(ia, iface)) { case 0: return errSuccess; case ENOSYS: return error(errMulticastDisabled,(char *)"Multicast not enabled on socket"); case EIO: return error(errServiceUnavailable,(char *)"Multicast not supported"); case EBADF: default: return error(errNotConnected,(char *)"Invalid socket operation"); } } Socket::Error Socket::drop(const ucommon::Socket::address &ia, int iface) { switch(ucommon::Socket::drop(ia, iface)) { case 0: return errSuccess; case ENOSYS: return error(errMulticastDisabled,(char *)"Multicast not enabled on socket"); case EIO: return error(errServiceUnavailable,(char *)"Multicast not supported"); case EBADF: default: return error(errNotConnected,(char *)"Invalid socket operation"); } } Socket::Error Socket::setRouting(bool enable) { int opt = (enable ? 1 : 0); #ifdef SO_DONTROUTE if(setsockopt(so, SOL_SOCKET, SO_DONTROUTE, (char *)&opt, (socklen_t)sizeof(opt))) return error(errRoutingDenied,(char *)"Could not set dont-route socket option",socket_errno); #endif flags.route = enable; return errSuccess; } Socket::Error Socket::setNoDelay(bool enable) { int opt = (enable ? 1 : 0); if(setsockopt(so, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, (socklen_t)sizeof(opt))) return error(errNoDelay,(char *)"Could not set tcp-nodelay socket option",socket_errno); return errSuccess; } ssize_t Socket::readLine(char *str, size_t request, timeout_t timeout) { bool crlf = false; bool nl = false; size_t nleft = request - 1; // leave also space for terminator int nstat,c; if(request < 1) return 0; str[0] = 0; while(nleft && !nl) { if(timeout) { if(!isPending(pendingInput, timeout)) { error(errTimeout,(char *)"Read timeout", 0); return -1; } } nstat = ::recv(so, str, _IOLEN64 nleft, MSG_PEEK); if(nstat <= 0) { error(errInput,(char *)"Could not read from socket", socket_errno); return -1; } // FIXME: if unique char in buffer is '\r' return "\r" // if buffer end in \r try to read another char? // and if timeout ?? // remember last \r for(c=0; c < nstat; ++c) { if(str[c] == '\n') { if (c > 0 && str[c-1] == '\r') crlf = true; ++c; nl = true; break; } } nstat = ::recv(so, str, _IOLEN64 c, 0); // TODO: correct ??? if(nstat < 0) break; // adjust ending \r\n in \n if(crlf) { --nstat; str[nstat - 1] = '\n'; } str += nstat; nleft -= nstat; } *str = 0; return (ssize_t)(request - nleft - 1); } ssize_t Socket::readData(void *Target, size_t Size, char Separator, timeout_t timeout) { if ((Separator == 0x0D) || (Separator == 0x0A)) return (readLine ((char *) Target, Size, timeout)); if (Size < 1) return (0); ssize_t nstat; if (Separator == 0) { // Flat-out read for a number of bytes. if (timeout) { if (!isPending (pendingInput, timeout)) { error(errTimeout); return (-1); } } nstat =::recv (so, (char *)Target, _IOLEN64 Size, 0); if (nstat < 0) { error (errInput); return (-1); } return (nstat); } ///////////////////////////////////////////////////////////// // Otherwise, we have a special char separator to use ///////////////////////////////////////////////////////////// bool found = false; size_t nleft = Size; int c; char *str = (char *) Target; memset (str, 0, Size); while (nleft && !found) { if (timeout) { if (!isPending (pendingInput, timeout)) { error(errTimeout); return (-1); } } nstat =::recv (so, str, _IOLEN64 nleft, MSG_PEEK); if (nstat <= 0) { error (errInput); return (-1); } for (c = 0; (c < nstat) && !found; ++c) { if (str[c] == Separator) found = true; } memset (str, 0, nleft); nstat =::recv (so, str, c, 0); if (nstat < 0) break; str += nstat; nleft -= nstat; } return (ssize_t)(Size - (ssize_t) nleft); } ssize_t Socket::writeData(const void *Source, size_t Size, timeout_t timeout) { if (Size < 1) return (0); ssize_t nstat; const char *Slide = (const char *) Source; while (true) { if (timeout) { if (!isPending (pendingOutput, timeout)) { error(errOutput); return (-1); } } nstat =::send (so, Slide, _IOLEN64 Size, MSG_NOSIGNAL); if (nstat <= 0) { error(errOutput); return (-1); } Size -= nstat; Slide += nstat; if (Size <= 0) break; } return (nstat); } const char *Socket::getSystemErrorString(void) const { #ifdef CCXX_EXCEPTIONS SockException e(errstr, errid, syserr); return e.getSystemErrorString(); #else return NULL; #endif } bool Socket::isPending(Pending pending, timeout_t timeout) { int status = 0; #ifdef USE_POLL struct pollfd pfd; pfd.fd = so; pfd.revents = 0; if(so == INVALID_SOCKET) return true; switch(pending) { case pendingInput: pfd.events = POLLIN; break; case pendingOutput: pfd.events = POLLOUT; break; case pendingError: pfd.events = POLLERR | POLLHUP; break; } status = 0; while(status < 1) { if(timeout == TIMEOUT_INF) status = poll(&pfd, 1, -1); else status = poll(&pfd, 1, timeout); if(status < 1) { // don't stop polling because of a simple // signal :) if(status == -1 && errno == EINTR) continue; return false; } } if(pfd.revents & pfd.events) return true; return false; #else struct timeval tv; struct timeval *tvp = &tv; fd_set grp; if(timeout == TIMEOUT_INF) tvp = NULL; else { tv.tv_usec = (timeout % 1000) * 1000; tv.tv_sec = timeout / 1000; } FD_ZERO(&grp); SOCKET sosave = so; if(so == INVALID_SOCKET) return true; FD_SET(sosave, &grp); switch(pending) { case pendingInput: status = ::select((int)so + 1, &grp, NULL, NULL, tvp); break; case pendingOutput: status = ::select((int)so + 1, NULL, &grp, NULL, tvp); break; case pendingError: status = ::select((int)so + 1, NULL, NULL, &grp, tvp); break; } if(status < 1) return false; if(FD_ISSET(so, &grp)) return true; return false; #endif } bool Socket::operator!() const { return (Socket::state == INITIAL) ? true : false; } Socket::operator bool() const { return (Socket::state == INITIAL) ? false : true; } Socket &Socket::operator=(const Socket &from) { if(so == from.so) return *this; if(state != INITIAL) endSocket(); so = dupSocket(from.so,from.state); if(so == INVALID_SOCKET) { error(errCopyFailed,(char *)"Could not duplicate socket handle",socket_errno); state = INITIAL; } else state = from.state; return *this; } bool Socket::check(Family fam) { SOCKET so = INVALID_SOCKET; switch(fam) { case IPV4: so = socket(fam, SOCK_DGRAM, IPPROTO_UDP); break; #ifdef CCXX_IPV6 case IPV6: so = socket(fam, SOCK_DGRAM, IPPROTO_UDP); break; #endif default: return false; } if(so == INVALID_SOCKET) return false; release(so); return true; } ucommon::Socket::address Socket::getSender() const { ucommon::Socket::address addr; sockaddr_in6 from; char buf; socklen_t len = sizeof(from); int rc = ::recvfrom(so, &buf, 1, MSG_PEEK, (sockaddr *)&from, &len); #ifdef _MSWINDOWS_ if(rc < 1 && WSAGetLastError() != WSAEMSGSIZE) { error(errInput,(char *)"Could not read from socket",socket_errno); return addr; } #else if(rc < 0) { error(errInput,(char *)"Could not read from socket",socket_errno); return addr; } #endif else { if(rc < 1) return addr; } addr.insert((sockaddr *)&from); return addr; } IPV4Host Socket::getIPV4Sender(in_port_t *port) const { ucommon::Socket::address addr = getSender(); sockaddr_in* from = addr; struct in_addr any; any.s_addr = INADDR_ANY; if (from == NULL) { if (port) *port = 0; return IPV4Host(any); } if (port) *port = ntohs(from->sin_port); return IPV4Host(from->sin_addr); } #ifdef CCXX_IPV6 IPV6Host Socket::getIPV6Sender(in_port_t *port) const { ucommon::Socket::address addr = getSender(); sockaddr_in6* from = addr; if (from == NULL) { if (port) *port = 0; return IPV6Host(in6addr_any); } if (port) *port = ntohs(from->sin6_port); return IPV6Host(from->sin6_addr); } #endif ucommon::Socket::address Socket::getLocal() const { ucommon::Socket::address saddr; struct sockaddr_in6 addr; socklen_t len = sizeof(addr); if(getsockname(so, (struct sockaddr *)&addr, &len)) { error(errResourceFailure,(char *)"Could not get socket address",socket_errno); return saddr; } saddr.insert((sockaddr *)&addr); return saddr; } IPV4Host Socket::getIPV4Local(in_port_t *port) const { const sockaddr_in* from = getLocal(); struct in_addr any; any.s_addr = INADDR_ANY; if (from == NULL) { if (port) *port = 0; return IPV4Host(any); } if (port) *port = ntohs(from->sin_port); return IPV4Host(from->sin_addr); } #ifdef CCXX_IPV6 IPV6Host Socket::getIPV6Local(in_port_t *port) const { const sockaddr_in6* from = getLocal(); if (from == NULL) { if (port) *port = 0; return IPV6Host(in6addr_any); } if (port) *port = ntohs(from->sin6_port); return IPV6Host(from->sin6_addr); } #endif ucommon::Socket::address Socket::getPeer() const { ucommon::Socket::address saddr; struct sockaddr_in6 addr; socklen_t len = sizeof(addr); if(getpeername(so, (struct sockaddr *)&addr, &len)) { #ifndef _MSWINDOWS_ if(errno == ENOTCONN) error(errNotConnected,(char *)"Could not get peer address",socket_errno); else #endif error(errResourceFailure,(char *)"Could not get peer address",socket_errno); return saddr; } saddr.insert((sockaddr *)&addr); return saddr; } IPV4Host Socket::getIPV4Peer(in_port_t *port) const { sockaddr_in* from = getPeer(); struct in_addr any; any.s_addr = INADDR_ANY; if (from == NULL) { if (port) *port = 0; return IPV4Host(any); } if (port) *port = ntohs(from->sin_port); return IPV4Host(from->sin_addr); } #ifdef CCXX_IPV6 IPV6Host Socket::getIPV6Peer(in_port_t *port) const { sockaddr_in6* from = getPeer(); if (from == NULL) { if (port) *port = 0; return IPV6Host(in6addr_any); } if (port) *port = ntohs(from->sin6_port); return IPV6Host(from->sin6_addr); } #endif void Socket::setCompletion(bool immediate) { flags.completion = immediate; #ifdef _MSWINDOWS_ unsigned long flag = 0; // note that this will not work on some versions of Windows for Workgroups. Tough. -- jfc switch( immediate ) { case false: // this will not work if you are using WSAAsyncSelect or WSAEventSelect. // -- perhaps I should throw an exception flag = 1; // ioctlsocket( so, FIONBIO, (unsigned long *) 1); break; case true: flag = 0; // ioctlsocket( so, FIONBIO, (unsigned long *) 0); break; } ioctlsocket(so, FIONBIO, &flag); #else int fflags = fcntl(so, F_GETFL); if(immediate) { fflags &=~ O_NONBLOCK; fcntl(so, F_SETFL, fflags); } else { fflags |= O_NONBLOCK; fcntl(so, F_SETFL, fflags); } #endif } Socket::Error Socket::setKeepAlive(bool enable) { int opt = (enable ? ~0: 0); #if (defined(SO_KEEPALIVE) || defined(_MSWINDOWS_)) if(setsockopt(so, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, (socklen_t)sizeof(opt))) return error(errKeepaliveDenied,(char *)"Could not set socket keep-alive option",socket_errno); #endif flags.keepalive = enable; return errSuccess; } Socket::Error Socket::setLinger(bool linger) { #ifdef SO_LINGER flags.linger = linger; return errSuccess; #else return error(errServiceUnavailable,(char *)"Socket lingering not supported"); #endif } Socket::Error Socket::setTypeOfService(Tos service) { #ifdef SOL_IP uint8_t tos; switch(service) { #ifdef IPTOS_LOWDELAY case tosLowDelay: tos = IPTOS_LOWDELAY; break; #endif #ifdef IPTOS_THROUGHPUT case tosThroughput: tos = IPTOS_THROUGHPUT; break; #endif #ifdef IPTOS_RELIABILITY case tosReliability: tos = IPTOS_RELIABILITY; break; #endif #ifdef IPTOS_MINCOST case tosMinCost: tos = IPTOS_MINCOST; break; #endif default: return error(errServiceUnavailable,(char *)"Unknown type-of-service"); } if(setsockopt(so, SOL_IP, IP_TOS,(char *)&tos, (socklen_t)sizeof(tos))) return error(errServiceDenied,(char *)"Could not set type-of-service",socket_errno); return errSuccess; #else return error(errServiceUnavailable,(char *)"Socket type-of-service not supported",socket_errno); #endif } bool Socket::isConnected(void) const { return (Socket::state == CONNECTED) ? true : false; } bool Socket::isActive(void) const { return (state != INITIAL) ? true : false; } } // namespace ost commoncpp-7.0.1/commoncpp/strchar.cpp000066400000000000000000000070341411242573100176630ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include #include namespace ost { char *newString(const char *src, size_t size) { char *dest; if(!size) size = strlen(src) + 1; dest = new char[size]; return setString(dest, size, src); } void delString(char *str) { delete[] str; } char *setUpper(char *string, size_t size) { char *ret = string; if(!size) size = strlen(string); while(size && *string) { *string = toupper(*string); ++string; --size; } return ret; } char *setLower(char *string, size_t size) { char *ret = string; if(!size) size = strlen(string); while(size && *string) { *string = tolower(*string); ++string; --size; } return ret; } char *rsetField(char *dest, size_t size, const char *src, const char fill) { size_t len = 0; if(src) len = strlen(src); if(len > size) len = size; if(len) memmove(dest + size - len, (void *)src, len); if(len < size && fill) memset(dest, fill, size - len); return dest; } char *lsetField(char *dest, size_t size, const char *src, const char fill) { size_t len = 0; if(src) len = strlen(src); if(len > size) len = size; if(len) memmove(dest, src, len); if(len < size && fill) memset(dest + len, fill, size - len); return dest; } } // namespace ost commoncpp-7.0.1/commoncpp/tcp.cpp000066400000000000000000000715271411242573100170130ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include #include #include #ifdef _MSWINDOWS_ #include #define _IOLEN64 (unsigned) #define _IORET64 (int) typedef int socklen_t; #define socket_errno WSAGetLastError() #else #include #include #ifdef HAVE_NET_IP6_H #include #endif #define socket_errno errno # ifndef O_NONBLOCK # define O_NONBLOCK O_NDELAY # endif # ifdef IPPROTO_IP # ifndef SOL_IP # define SOL_IP IPPROTO_IP # endif // !SOL_IP # endif // IPPROTO_IP #endif // !WIN32 #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK (unsigned long)0x7f000001 #endif #ifdef HAVE_NETINET_IN_H #include #endif #if defined(__hpux) #define _XOPEN_SOURCE_EXTENDED #endif #ifdef HAVE_NET_IF_H #include #endif #ifndef _IOLEN64 #define _IOLEN64 #endif #ifndef _IORET64 #define _IORET64 #endif namespace ost { using std::streambuf; using std::iostream; using std::ios; void TCPSocket::setSegmentSize(unsigned mss) { #ifdef TCP_MAXSEG if(mss > 1) setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, sizeof(mss)); #endif segsize = mss; } #ifdef HAVE_GETADDRINFO TCPSocket::TCPSocket(const char *name, unsigned backlog, unsigned mss) : Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) { char namebuf[128], *cp; struct addrinfo hint, *list = NULL, *first; snprintf(namebuf, sizeof(namebuf), "%s", name); cp = strrchr(namebuf, '/'); if(!cp) cp = strrchr(namebuf, ':'); if(!cp) { cp = namebuf; name = NULL; } else { name = namebuf; *(cp++) = 0; if(!strcmp(name, "*")) name = NULL; } memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_INET; hint.ai_socktype = SOCK_STREAM; hint.ai_protocol = IPPROTO_TCP; hint.ai_flags = AI_PASSIVE; if(getaddrinfo(name, cp, &hint, &list) || !list) { endSocket(); error(errBindingFailed, (char *)"Could not find service", errno); return; } #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif first = list; while(list) { if(!bind(so, list->ai_addr, (socklen_t)list->ai_addrlen)) { state = BOUND; break; } list = list->ai_next; } freeaddrinfo(first); if(state != BOUND) { endSocket(); error(errBindingFailed,(char *)"Could not bind socket",socket_errno); return; } setSegmentSize(mss); if(listen(so, backlog)) { endSocket(); error(errBindingFailed,(char *)"Could not listen on socket",socket_errno); return; } } #else TCPSocket::TCPSocket(const char *name, unsigned backlog, unsigned mss) : Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) { char namebuf[128], *cp; struct sockaddr_in addr; struct servent *svc; memset(&addr, 0, sizeof(addr)); snprintf(namebuf, sizeof(namebuf), "%s", name); cp = strrchr(namebuf, '/'); if(!cp) cp = strrchr(namebuf, ':'); if(!cp) { cp = namebuf; name = "*"; } else { name = namebuf; *(cp++) = 0; } addr.sin_family = AF_INET; if(isdigit(*cp)) addr.sin_port = htons(atoi(cp)); else { svc = getservbyname(cp, "tcp"); if(svc) addr.sin_port = svc->s_port; if(!svc) { endSocket(); error(errBindingFailed, "Could not find service", errno); return; } } IPV4Address ia(name); addr.sin_addr = getaddress(ia); #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif if(bind(so, (struct sockaddr *)&addr, sizeof(addr))) { endSocket(); error(errBindingFailed,(char *)"Could not bind socket",socket_errno); return; } setSegmentSize(mss); if(listen(so, backlog)) { endSocket(); error(errBindingFailed,(char *)"Could not listen on socket", socket_errno); return; } state = BOUND; } #endif TCPSocket::TCPSocket(const IPV4Address &ia, in_port_t port, unsigned backlog, unsigned mss) : Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr = getaddress(ia); addr.sin_port = htons(port); #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif if(bind(so, (struct sockaddr *)&addr, sizeof(addr))) { endSocket(); error(errBindingFailed,(char *)"Could not bind socket",socket_errno); return; } setSegmentSize(mss); if(listen(so, backlog)) { endSocket(); error(errBindingFailed,(char *)"Could not listen on socket",socket_errno); return; } state = BOUND; } bool TCPSocket::onAccept(const IPV4Host &ia, in_port_t port) { return true; } TCPSocket::~TCPSocket() { endSocket(); } #ifdef CCXX_IPV6 void TCPV6Socket::setSegmentSize(unsigned mss) { #ifdef TCP_MAXSEG if(mss > 1) setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, sizeof(mss)); #endif segsize = mss; } TCPV6Socket::TCPV6Socket(const char *name, unsigned backlog, unsigned mss) : Socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP) { char namebuf[128], *cp; struct addrinfo hint, *list = NULL, *first; snprintf(namebuf, sizeof(namebuf), "%s", name); cp = strrchr(namebuf, '/'); if(!cp) { cp = namebuf; name = NULL; } else { name = namebuf; *(cp++) = 0; if(!strcmp(name, "*")) name = NULL; } memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_INET6; hint.ai_socktype = SOCK_STREAM; hint.ai_protocol = IPPROTO_TCP; hint.ai_flags = AI_PASSIVE; if(getaddrinfo(name, cp, &hint, &list) || !list) { endSocket(); error(errBindingFailed, (char *)"Could not find service", errno); return; } #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif first = list; while(list) { if(!bind(so, list->ai_addr, (socklen_t)list->ai_addrlen)) { state = BOUND; break; } list = list->ai_next; } freeaddrinfo(first); if(state != BOUND) { endSocket(); error(errBindingFailed,(char *)"Could not bind socket",socket_errno); return; } setSegmentSize(mss); if(listen(so, backlog)) { endSocket(); error(errBindingFailed,(char *)"Could not listen on socket",socket_errno); return; } } TCPV6Socket::TCPV6Socket(const IPV6Address &ia, in_port_t port, unsigned backlog, unsigned mss) : Socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP) { struct sockaddr_in6 addr; memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_addr = getaddress(ia); addr.sin6_port = htons(port); #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif if(bind(so, (struct sockaddr *)&addr, sizeof(addr))) { endSocket(); error(errBindingFailed,(char *)"Could not bind socket",socket_errno); return; } setSegmentSize(mss); if(listen(so, backlog)) { endSocket(); error(errBindingFailed,(char *)"Could not listen on socket",socket_errno); return; } state = BOUND; } bool TCPV6Socket::onAccept(const IPV6Host &ia, in_port_t port) { return true; } TCPV6Socket::~TCPV6Socket() { endSocket(); } #endif void TCPSocket::reject(void) { SOCKET rej = accept(so, NULL, NULL); ::shutdown(rej, 2); release(rej); } #ifdef CCXX_IPV6 void TCPV6Socket::reject(void) { SOCKET rej = accept(so, NULL, NULL); ::shutdown(rej, 2); release(rej); } #endif TCPStream::TCPStream(TCPSocket &server, bool throwflag, timeout_t to) : streambuf(), Socket(accept(server.getSocket(), NULL, NULL)) ,iostream((streambuf *)this) ,bufsize(0) ,gbuf(NULL) ,pbuf(NULL) { in_port_t port; family = IPV4; timeout = to; setError(throwflag); IPV4Host host = getPeer(&port); if(!server.onAccept(host, port)) { endSocket(); error(errConnectRejected); iostream::clear(ios::failbit | rdstate()); return; } segmentBuffering(server.getSegmentSize()); Socket::state = CONNECTED; } #ifdef CCXX_IPV6 TCPStream::TCPStream(TCPV6Socket &server, bool throwflag, timeout_t to) : streambuf(), Socket(accept(server.getSocket(), NULL, NULL)) ,iostream((streambuf *)this) ,bufsize(0) ,gbuf(NULL) ,pbuf(NULL) { in_port_t port; family = IPV6; timeout = to; setError(throwflag); IPV6Host host = getIPV6Peer(&port); if(!server.onAccept(host, port)) { endSocket(); error(errConnectRejected); iostream::clear(ios::failbit | rdstate()); return; } segmentBuffering(server.getSegmentSize()); Socket::state = CONNECTED; } #endif TCPStream::TCPStream(const IPV4Host &host, in_port_t port, unsigned size, bool throwflag, timeout_t to) : streambuf(), Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) ,iostream((streambuf *)this), bufsize(0),gbuf(NULL),pbuf(NULL) { family = IPV4; timeout = to; setError(throwflag); connect(host, port, size); } #ifdef CCXX_IPV6 TCPStream::TCPStream(const IPV6Host &host, in_port_t port, unsigned size, bool throwflag, timeout_t to) : streambuf(), Socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP), iostream((streambuf *)this), bufsize(0),gbuf(NULL),pbuf(NULL) { family = IPV6; timeout = to; setError(throwflag); connect(host, port, size); } #endif TCPStream::~TCPStream() { endStream(); } #ifdef HAVE_GETADDRINFO void TCPStream::connect(const char *target, unsigned mss) { char namebuf[128]; char *cp; struct addrinfo hint, *list = NULL, *next, *first; bool connected = false; snprintf(namebuf, sizeof(namebuf), "%s", target); cp = strrchr(namebuf, '/'); if(!cp) cp = strrchr(namebuf, ':'); if(!cp) { endStream(); connectError(); return; } *(cp++) = 0; memset(&hint, 0, sizeof(hint)); hint.ai_family = family; hint.ai_socktype = SOCK_STREAM; hint.ai_protocol = IPPROTO_TCP; if(getaddrinfo(namebuf, cp, &hint, &list) || !list) { endStream(); connectError(); return; } first = list; #ifdef TCP_MAXSEG if(mss) setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, sizeof(mss)); #endif while(list) { if(!::connect(so, list->ai_addr, (socklen_t)list->ai_addrlen)) { connected = true; break; } next = list->ai_next; list = next; } freeaddrinfo(first); if(!connected) { endStream(); connectError(); return; } segmentBuffering(mss); Socket::state = CONNECTED; } #else void TCPStream::connect(const char *target, unsigned mss) { char namebuf[128]; char *cp; struct servent *svc; in_port_t port; snprintf(namebuf, sizeof(namebuf), "%s", target); cp = strrchr(namebuf, '/'); if(!cp) cp = strrchr(namebuf, ':'); if(!cp) { endStream(); connectError(); return; } *(cp++) = 0; if(isdigit(*cp)) port = atoi(cp); else { svc = getservbyname(cp, "tcp"); if(svc) port = ntohs(svc->s_port); if(!svc) { endStream(); connectError(); return; } } switch(family) { case IPV4: connect(IPV4Host(namebuf), port, mss); break; #ifdef CCXX_IPV6 case IPV6: connect(IPV6Host(namebuf), port, mss); break; #endif default: endStream(); connectError(); } } #endif void TCPStream::connect(const IPV4Host &host, in_port_t port, unsigned mss) { size_t i; fd_set fds; struct timeval to; bool connected = false; int rtn; int sockopt; socklen_t len = sizeof(sockopt); #ifdef TCP_MAXSEG if(mss) setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, sizeof(mss)); #endif for(i = 0 ; i < host.getAddressCount(); i++) { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr = host.getAddress(i); addr.sin_port = htons(port); if(timeout) setCompletion(false); // Win32 will crash if you try to connect to INADDR_ANY. if ( INADDR_ANY == addr.sin_addr.s_addr ) addr.sin_addr.s_addr = INADDR_LOOPBACK; rtn = ::connect(so, (struct sockaddr *)&addr, (socklen_t)sizeof(addr)); if(!rtn) { connected = true; break; } #ifndef _MSWINDOWS_ if(errno == EINPROGRESS) #else if(WSAGetLastError() == WSAEINPROGRESS) #endif { FD_ZERO(&fds); FD_SET(so, &fds); to.tv_sec = timeout / 1000; to.tv_usec = timeout % 1000 * 1000; // timeout check for connect completion if(::select((int)so + 1, NULL, &fds, NULL, &to) < 1) continue; getsockopt(so, SOL_SOCKET, SO_ERROR, (char *)&sockopt, &len); if(!sockopt) { connected = true; break; } endSocket(); so = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(so == INVALID_SOCKET) break; } } setCompletion(true); if(!connected) { rtn = errno; endStream(); errno = rtn; connectError(); return; } segmentBuffering(mss); Socket::state = CONNECTED; } #ifdef CCXX_IPV6 void TCPStream::connect(const IPV6Host &host, in_port_t port, unsigned mss) { size_t i; fd_set fds; struct timeval to; bool connected = false; int rtn; int sockopt; socklen_t len = sizeof(sockopt); #ifdef TCP_MAXSEG if(mss) setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, sizeof(mss)); #endif for(i = 0 ; i < host.getAddressCount(); i++) { struct sockaddr_in6 addr; memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_addr = host.getAddress(i); addr.sin6_port = htons(port); if(timeout) setCompletion(false); // Win32 will crash if you try to connect to INADDR_ANY. if ( !memcmp(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any))) memcpy(&addr.sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback)); rtn = ::connect(so, (struct sockaddr *)&addr, (socklen_t)sizeof(addr)); if(!rtn) { connected = true; break; } #ifndef _MSWINDOWS_ if(errno == EINPROGRESS) #else if(WSAGetLastError() == WSAEINPROGRESS) #endif { FD_ZERO(&fds); FD_SET(so, &fds); to.tv_sec = timeout / 1000; to.tv_usec = timeout % 1000 * 1000; // timeout check for connect completion if(::select((int)so + 1, NULL, &fds, NULL, &to) < 1) continue; getsockopt(so, SOL_SOCKET, SO_ERROR, (char *)&sockopt, &len); if(!sockopt) { connected = true; break; } endSocket(); so = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); if(so == INVALID_SOCKET) break; } } setCompletion(true); if(!connected) { rtn = errno; endStream(); errno = rtn; connectError(); return; } segmentBuffering(mss); Socket::state = CONNECTED; } #endif TCPStream::TCPStream(const char *target, Family fam, unsigned mss, bool throwflag, timeout_t to) : streambuf(), Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP), iostream((streambuf *)this), timeout(to), bufsize(0),gbuf(NULL),pbuf(NULL) { family = fam; setError(throwflag); connect(target, mss); } TCPStream::TCPStream(Family fam, bool throwflag, timeout_t to) : streambuf(), Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP), iostream((streambuf *)this), timeout(to), bufsize(0),gbuf(NULL),pbuf(NULL) { family = fam; setError(throwflag); } void TCPStream::connect(TCPSocket &tcpip) { in_port_t port; endStream(); family = IPV4; so = accept(tcpip.getSocket(), NULL, NULL); if(so == INVALID_SOCKET) return; IPV4Host host = getPeer(&port); if(!tcpip.onAccept(host, port)) { endSocket(); iostream::clear(ios::failbit | rdstate()); return; } segmentBuffering(tcpip.getSegmentSize()); Socket::state = CONNECTED; } #ifdef CCXX_IPV6 void TCPStream::connect(TCPV6Socket &tcpip) { in_port_t port; endStream(); family = IPV6; so = accept(tcpip.getSocket(), NULL, NULL); if(so == INVALID_SOCKET) return; IPV6Host host = getIPV6Peer(&port); if(!tcpip.onAccept(host, port)) { endSocket(); iostream::clear(ios::failbit | rdstate()); return; } segmentBuffering(tcpip.getSegmentSize()); Socket::state = CONNECTED; } #endif void TCPStream::segmentBuffering(unsigned mss) { unsigned max = 0; if(mss == 1) { // special interactive allocate(1); return; } #ifdef TCP_MAXSEG socklen_t alen = sizeof(max); if(mss) setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&max, sizeof(max)); getsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&max, &alen); #endif if(max && max < mss) mss = max; if(!mss) { if(max) mss = max; else mss = 536; allocate(mss); return; } #ifdef TCP_MAXSEG setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, sizeof(mss)); #endif if(mss < 80) mss = 80; if(mss * 7 < 64000) bufferSize(mss * 7); else if(mss * 6 < 64000) bufferSize(mss * 6); else bufferSize(mss * 5); if(mss < 512) sendLimit(mss * 4); allocate(mss); } int TCPStream::getSegmentSize(void) { unsigned mss = 0; #ifdef TCP_MAXSEG socklen_t alen = sizeof(mss); getsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &alen); #endif if(!mss) return (int)bufsize; return mss; } void TCPStream::disconnect(void) { if(Socket::state == AVAILABLE) return; endStream(); so = socket(family, SOCK_STREAM, IPPROTO_TCP); if(so != INVALID_SOCKET) Socket::state = AVAILABLE; } void TCPStream::endStream(void) { if(bufsize) sync(); if(gbuf) delete[] gbuf; if(pbuf) delete[] pbuf; gbuf = pbuf = NULL; bufsize = 0; iostream::clear(); endSocket(); } void TCPStream::allocate(size_t size) { if(size < 2) { bufsize = 1; gbuf = pbuf = 0; return; } gbuf = new char[size]; pbuf = new char[size]; if(!pbuf || !gbuf) { error(errResourceFailure, (char *)"Could not allocate socket stream buffers"); return; } bufsize = size; iostream::clear(); #if (defined(__GNUC__) && (__GNUC__ < 3)) && !defined(_MSWINDOWS_) && !defined(STLPORT) setb(gbuf, gbuf + size, 0); #endif setg(gbuf, gbuf + size, gbuf + size); setp(pbuf, pbuf + size); } int TCPStream::doallocate() { if(bufsize) return 0; allocate(1); return 1; } int TCPStream::uflow() { int ret = underflow(); if (ret == EOF) return EOF; if (bufsize != 1) gbump(1); return ret; } int TCPStream::underflow() { ssize_t rlen = 1; uint8_t ch; if(bufsize == 1) { if(Socket::state == STREAM) rlen = ::read((int)so, (char *)&ch, 1); else if(timeout && !Socket::isPending(pendingInput, timeout)) { iostream::clear(ios::failbit | rdstate()); error(errTimeout,(char *)"Socket read timed out",socket_errno); return EOF; } else rlen = readData(&ch, 1); if(rlen < 1) { if(rlen < 0) { iostream::clear(ios::failbit | rdstate()); error(errInput,(char *)"Could not read from socket",socket_errno); } return EOF; } return ch; } if(!gptr()) return EOF; if(gptr() < egptr()) return (uint8_t)*gptr(); rlen = (ssize_t)((gbuf + bufsize) - eback()); if(Socket::state == STREAM) rlen = ::read((int)so, (char *)eback(), _IOLEN64 rlen); else if(timeout && !Socket::isPending(pendingInput, timeout)) { iostream::clear(ios::failbit | rdstate()); error(errTimeout,(char *)"Socket read timed out",socket_errno); return EOF; } else rlen = readData(eback(), rlen); if(rlen < 1) { // clear(ios::failbit | rdstate()); if(rlen < 0) error(errNotConnected,(char *)"Connection error",socket_errno); else { error(errInput,(char *)"Could not read from socket",socket_errno); iostream::clear(ios::failbit | rdstate()); } return EOF; } error(errSuccess); setg(eback(), eback(), eback() + rlen); return (uint8_t) *gptr(); } bool TCPStream::isPending(Pending pending, timeout_t timer) { if(pending == pendingInput && in_avail()) return true; else if(pending == pendingOutput) flush(); return Socket::isPending(pending, timer); } int TCPStream::sync(void) { overflow(EOF); setg(gbuf, gbuf + bufsize, gbuf + bufsize); return 0; } size_t TCPStream::printf(const char *format, ...) { va_list args; size_t len; char *buf; va_start(args, format); overflow(EOF); len = pptr() - pbase(); buf = pptr(); vsnprintf(buf, len, format, args); va_end(args); len = strlen(buf); if(Socket::state == STREAM) return ::write((int)so, buf, _IOLEN64 len); else return writeData(buf, len); } int TCPStream::overflow(int c) { uint8_t ch; ssize_t rlen, req; if(bufsize == 1) { if(c == EOF) return 0; ch = (uint8_t)(c); if(Socket::state == STREAM) rlen = ::write((int)so, (const char *)&ch, 1); else rlen = writeData(&ch, 1); if(rlen < 1) { if(rlen < 0) { iostream::clear(ios::failbit | rdstate()); error(errOutput,(char *)"Could not write to socket",socket_errno); } return EOF; } else return c; } if(!pbase()) return EOF; req = (ssize_t)(pptr() - pbase()); if(req) { if(Socket::state == STREAM) rlen = ::write((int)so, (const char *)pbase(), req); else rlen = writeData(pbase(), req); if(rlen < 1) { if(rlen < 0) { iostream::clear(ios::failbit | rdstate()); error(errOutput,(char *)"Could not write to socket",socket_errno); } return EOF; } req -= rlen; } // if write "partial", rebuffer remainder if(req) // memmove(pbuf, pptr() + rlen, req); memmove(pbuf, pbuf + rlen, req); setp(pbuf, pbuf + bufsize); pbump(req); if(c != EOF) { *pptr() = (uint8_t)c; pbump(1); } return c; } TCPSession::TCPSession(const IPV4Host &ia, in_port_t port, size_t size, int pri, size_t stack) : Thread(pri, stack), TCPStream(IPV4) { setCompletion(false); setError(false); allocate(size); size_t i; for(i = 0 ; i < ia.getAddressCount(); i++) { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr = ia.getAddress(i); addr.sin_port = htons(port); // Win32 will crash if you try to connect to INADDR_ANY. if ( INADDR_ANY == addr.sin_addr.s_addr ) addr.sin_addr.s_addr = INADDR_LOOPBACK; if(::connect(so, (struct sockaddr *)&addr, (socklen_t)sizeof(addr)) == 0) break; #ifdef _MSWINDOWS_ if(WSAGetLastError() == WSAEISCONN || WSAGetLastError() == WSAEWOULDBLOCK) #else if(errno == EINPROGRESS) #endif { Socket::state = CONNECTING; return; } } if(i == ia.getAddressCount()) { endSocket(); Socket::state = INITIAL; return; } setCompletion(true); Socket::state = CONNECTED; } #ifdef CCXX_IPV6 TCPSession::TCPSession(const IPV6Host &ia, in_port_t port, size_t size, int pri, size_t stack) : Thread(pri, stack), TCPStream(IPV6) { setCompletion(false); setError(false); allocate(size); size_t i; for(i = 0 ; i < ia.getAddressCount(); i++) { struct sockaddr_in6 addr; memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_addr = ia.getAddress(i); addr.sin6_port = htons(port); // Win32 will crash if you try to connect to INADDR_ANY. if(!memcmp(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any))) memcpy(&addr.sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback)); if(::connect(so, (struct sockaddr *)&addr, (socklen_t)sizeof(addr)) == 0) break; #ifdef _MSWINDOWS_ // if(WSAGetLastError() == WSAEWOULDBLOCK) if(WSAGetLastError() == WSAEISCONN) #else if(errno == EINPROGRESS) #endif { Socket::state = CONNECTING; return; } } if(i == ia.getAddressCount()) { endSocket(); Socket::state = INITIAL; return; } setCompletion(true); Socket::state = CONNECTED; } #endif TCPSession::TCPSession(TCPSocket &s, int pri, size_t stack) : Thread(pri, stack), TCPStream(s) { setCompletion(true); setError(false); } #ifdef CCXX_IPV6 TCPSession::TCPSession(TCPV6Socket &s, int pri, size_t stack) : Thread(pri, stack), TCPStream(s) { setCompletion(true); setError(false); } #endif TCPSession::~TCPSession() { endStream(); } int TCPSession::waitConnection(timeout_t timer) { int sockopt = 0; socklen_t len = sizeof(sockopt); switch(Socket::state) { case INITIAL: return -1; case CONNECTED: break; case CONNECTING: if(!Socket::isPending(pendingOutput, timer)) { endSocket(); Socket::state = INITIAL; return -1; } getsockopt(so, SOL_SOCKET, SO_ERROR, (char *)&sockopt, &len); if(sockopt) { endSocket(); Socket::state = INITIAL; return -1; } default: break; } Socket::state = CONNECTED; return 0; } void TCPSession::initial(void) { if(waitConnection(60000)) exit(); } } // namespace ost commoncpp-7.0.1/commoncpp/thread.cpp000066400000000000000000000455041411242573100174700ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include #include #ifdef _MSWINDOWS_ #define MAX_SEM_VALUE 1000000 #endif namespace ost { #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) extern int _posix_clocking; #endif static class __EXPORT MainThread : public Thread { private: void run(void); public: MainThread(); ~MainThread(); } _mainthread; extern "C" { #ifdef _MSTHREADS_ static unsigned __stdcall exec_thread(void *obj) { assert(obj != NULL); ucommon::Thread *th = static_cast(obj); Thread *cth = static_cast(obj); th->setPriority(); cth->map(); cth->initial(); cth->run(); cth->finalize(); cth->exit(); return 0; } #else static void *exec_thread(void *obj) { assert(obj != NULL); ucommon::Thread *th = static_cast(obj); Thread *cth = static_cast(obj); th->setPriority(); cth->map(); cth->initial(); cth->run(); cth->finalize(); cth->exit(); return NULL; } #endif } MainThread::MainThread() : Thread() { ucommon::Thread::init(); ucommon::Socket::init(); map(); } MainThread::~MainThread() { } void MainThread::run(void) { } Thread::Thread(int pri, size_t stack) : ucommon::JoinableThread(stack) { priority = pri; detached = false; terminated = false; msgpos = 0; if(this == &_mainthread) { parent = this; exceptions = throwObject; } else { parent = Thread::get(); if(!parent) parent = &_mainthread; exceptions = parent->exceptions; } } Thread::~Thread() { if(!detached) join(); finalize(); } bool Thread::isRunning(void) { return !detached && running && !terminated; } void Thread::finalize(void) { if(terminated) return; terminated = true; if(parent) parent->notify(this); final(); } bool Thread::isThread(void) { pthread_t self = pthread_self(); if(equal(tid, self)) return true; return false; } void Thread::terminate(void) { pthread_t self = pthread_self(); if(detached && equal(tid, self)) ucommon::Thread::exit(); else if(!detached) join(); } void Thread::exit(void) { pthread_t self = pthread_self(); if(detached && equal(tid, self)) { delete this; pthread_exit(NULL); } terminate(); } void Thread::initial(void) { } void Thread::final(void) { } void Thread::notify(Thread *thread) { } #ifdef _MSTHREADS_ void Thread::start(void) { if(running != INVALID_HANDLE_VALUE) return; if(stack == 1) stack = 1024; running = (HANDLE)_beginthreadex(NULL, stack, &exec_thread, this, 0, (unsigned int *)&tid); if(!running) running = INVALID_HANDLE_VALUE; else terminated = false; } void Thread::detach(void) { HANDLE hThread;; if(stack == 1) stack = 1024; hThread = (HANDLE)_beginthreadex(NULL, stack, &exec_thread, this, 0, (unsigned int *)&tid); CloseHandle(hThread); } #else void Thread::start(void) { int result; if(running) return; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); #if HAVE_PTHREAD_ATTR_SETINHRITSCHED pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); #endif // we typically use "stack 1" for min stack... #ifdef PTHREAD_STACK_MIN if(stack && stack < PTHREAD_STACK_MIN) stack = PTHREAD_STACK_MIN; #else if(stack && stack < 2) stack = 0; #endif if(stack) pthread_attr_setstacksize(&attr, stack); result = pthread_create(&tid, &attr, &exec_thread, this); pthread_attr_destroy(&attr); if(!result) { terminated = false; running = true; } } void Thread::detach(void) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); #if HAVE_PTHREAD_ATTR_SETINHRITSCHED pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); #endif // we typically use "stack 1" for min stack... #ifdef PTHREAD_STACK_MIN if(stack && stack < PTHREAD_STACK_MIN) stack = PTHREAD_STACK_MIN; #else if(stack && stack < 2) stack = 0; #endif if(stack) pthread_attr_setstacksize(&attr, stack); pthread_create(&tid, &attr, &exec_thread, this); pthread_attr_destroy(&attr); } #endif Thread::Throw Thread::getException(void) { Thread *th = Thread::get(); if(!th) return throwNothing; return th->exceptions; } void Thread::setException(Thread::Throw _throw) { Thread *th = Thread::get(); if(th) th->exceptions = _throw; } void Conditional::signal(bool broadcast) { if(broadcast) ucommon::Conditional::broadcast(); else ucommon::Conditional::signal(); } bool Conditional::wait(timeout_t timeout, bool locked) { bool result; if(!locked) ucommon::Conditional::lock(); result = ucommon::Conditional::wait(timeout); if(!locked) ucommon::Conditional::unlock(); return result; } static pthread_mutex_t mlock; time_t SysTime::getTime(time_t *tloc) { time_t ret; pthread_mutex_lock(&mlock); time_t temp; ::time(&temp); memcpy(&ret, &temp, sizeof(time_t)); if (tloc != NULL) memcpy(tloc, &ret, sizeof(time_t)); pthread_mutex_unlock(&mlock); return ret; } int SysTime::getTimeOfDay(struct timeval *tp) { struct timeval temp; int ret(0); pthread_mutex_lock(&mlock); #ifdef _MSWINDOWS_ // We could use _ftime(), but it is not available on WinCE. // (WinCE also lacks time.h) // Note also that the average error of _ftime is around 20 ms :) time_t now; time(&now); temp.tv_sec = (long)now; temp.tv_usec = (GetTickCount() % 1000) * 1000; memcpy(tp, &temp, sizeof(struct timeval)); #else ret = ::gettimeofday(&temp, NULL); if(ret == 0) memcpy(tp, &temp, sizeof(struct timeval)); #endif pthread_mutex_unlock(&mlock); return ret; } struct tm *SysTime::getLocalTime(const time_t *clock, struct tm* result) { pthread_mutex_lock(&mlock); struct tm *temp = ::localtime(clock); memcpy(result, temp, sizeof(struct tm)); pthread_mutex_unlock(&mlock); return result; } struct tm *SysTime::getGMTTime(const time_t *clock, struct tm* result) { pthread_mutex_lock(&mlock); struct tm *temp = ::gmtime(clock); memcpy(result, temp, sizeof(struct tm)); pthread_mutex_unlock(&mlock); return result; } #ifndef _MSWINDOWS_ #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) TimerPort::TimerPort() { struct timespec ts; active = false; ::clock_gettime(_posix_clocking, &ts); timer.tv_sec = ts.tv_sec; timer.tv_usec = ts.tv_nsec / 1000; } #else TimerPort::TimerPort() { active = false; SysTime::getTimeOfDay(&timer); } #endif void TimerPort::setTimer(timeout_t timeout) { #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) struct timespec ts; ::clock_gettime(_posix_clocking, &ts); timer.tv_sec = ts.tv_sec; timer.tv_usec = ts.tv_nsec / 1000l; #else SysTime::getTimeOfDay(&timer); #endif active = false; if(timeout) incTimer(timeout); } void TimerPort::incTimer(timeout_t timeout) { int secs = timeout / 1000; int usecs = (timeout % 1000) * 1000; timer.tv_usec += usecs; if(timer.tv_usec >= 1000000l) { ++timer.tv_sec; timer.tv_usec %= 1000000l; } timer.tv_sec += secs; active = true; } void TimerPort::decTimer(timeout_t timeout) { int secs = timeout / 1000; int usecs = (timeout % 1000) * 1000; if(timer.tv_usec < usecs) { --timer.tv_sec; timer.tv_usec = 1000000l + timer.tv_usec - usecs; } else timer.tv_usec -= usecs; timer.tv_sec -= secs; active = true; } #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) void TimerPort::sleepTimer(void) { struct timespec ts; ts.tv_sec = timer.tv_sec; ts.tv_nsec = timer.tv_usec * 1000l; ::clock_nanosleep(_posix_clocking, TIMER_ABSTIME, &ts, NULL); } #else void TimerPort::sleepTimer(void) { timeout_t remaining = getTimer(); if(remaining && remaining != TIMEOUT_INF) Thread::sleep(remaining); } #endif void TimerPort::endTimer(void) { active = false; } timeout_t TimerPort::getTimer(void) const { #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) struct timespec now; #else struct timeval now; #endif long diff; if(!active) return TIMEOUT_INF; #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) ::clock_gettime(_posix_clocking, &now); diff = (timer.tv_sec - now.tv_sec) * 1000l; diff += (timer.tv_usec - (now.tv_nsec / 1000)) / 1000l; #else SysTime::getTimeOfDay(&now); diff = (timer.tv_sec - now.tv_sec) * 1000l; diff += (timer.tv_usec - now.tv_usec) / 1000l; #endif if(diff < 0) return 0l; return diff; } timeout_t TimerPort::getElapsed(void) const { #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) struct timespec now; #else struct timeval now; #endif long diff; if(!active) return TIMEOUT_INF; #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS) ::clock_gettime(_posix_clocking, &now); diff = (now.tv_sec - timer.tv_sec) * 1000l; diff += ((now.tv_nsec / 1000l) - timer.tv_usec) / 1000l; #else SysTime::getTimeOfDay(&now); diff = (now.tv_sec -timer.tv_sec) * 1000l; diff += (now.tv_usec - timer.tv_usec) / 1000l; #endif if(diff < 0) return 0; return diff; } #else // WIN32 TimerPort::TimerPort() { active = false; timer = GetTickCount(); } void TimerPort::setTimer(timeout_t timeout) { timer = GetTickCount(); active = false; if(timeout) incTimer(timeout); } void TimerPort::incTimer(timeout_t timeout) { timer += timeout; active = true; } void TimerPort::decTimer(timeout_t timeout) { timer -= timeout; active = true; } void TimerPort::sleepTimer(void) { timeout_t remaining = getTimer(); if(remaining && remaining != TIMEOUT_INF) Thread::sleep(remaining); } void TimerPort::endTimer(void) { active = false; } timeout_t TimerPort::getTimer(void) const { DWORD now; long diff; if(!active) return TIMEOUT_INF; now = GetTickCount(); diff = timer - now; if(diff < 0) return 0l; return diff; } timeout_t TimerPort::getElapsed(void) const { DWORD now; long diff; if(!active) return TIMEOUT_INF; now = GetTickCount(); diff = now - timer; if(diff < 0) return 0l; return diff; } #endif MutexCounter::MutexCounter() : Mutex() { counter = 0; } MutexCounter::MutexCounter(int initial) : Mutex() { counter = initial; } int MutexCounter::operator++() { int rtn; enterMutex(); rtn = counter++; leaveMutex(); return rtn; } // ??? why cannot be < 0 ??? int MutexCounter::operator--() { int rtn = 0; enterMutex(); if(counter) { rtn = --counter; if(!rtn) { leaveMutex(); THROW(counter); } } leaveMutex(); return rtn; } #ifndef _MSWINDOWS_ timespec *getTimeout(struct timespec *spec, timeout_t timer) { static struct timespec myspec; if(spec == NULL) spec = &myspec; #ifdef PTHREAD_GET_EXPIRATION_NP struct timespec offset; offset.tv_sec = timer / 1000; offset.tv_nsec = (timer % 1000) * 1000000; pthread_get_expiration_np(&offset, spec); #else struct timeval current; SysTime::getTimeOfDay(¤t); spec->tv_sec = current.tv_sec + ((timer + current.tv_usec / 1000) / 1000); spec->tv_nsec = ((current.tv_usec / 1000 + timer) % 1000) * 1000000; #endif return spec; } #endif const size_t Buffer::timeout = ((size_t)(-1l)); #ifdef _MSWINDOWS_ Buffer::Buffer(size_t capacity) : Mutex() #else Buffer::Buffer(size_t capacity) : Conditional() #endif { #ifdef _MSWINDOWS_ sem_head = ::CreateSemaphore((LPSECURITY_ATTRIBUTES)NULL, 0, MAX_SEM_VALUE, (LPCTSTR)NULL); sem_tail = ::CreateSemaphore((LPSECURITY_ATTRIBUTES)NULL, (LONG)capacity, MAX_SEM_VALUE, (LPCTSTR)NULL); #endif _size = capacity; _used = 0; } Buffer::~Buffer() { #ifdef _MSWINDOWS_ ::CloseHandle(sem_head); ::CloseHandle(sem_tail); #endif } #ifdef _MSWINDOWS_ size_t Buffer::wait(void *buf, timeout_t timeout) { size_t rc; if(!timeout) timeout = INFINITE; if(WaitForSingleObject(sem_head, timeout) != WAIT_OBJECT_0) return Buffer::timeout; enterMutex(); rc = onWait(buf); --_used; leaveMutex(); ::ReleaseSemaphore(sem_tail, 1, (LPLONG)NULL); return rc; } size_t Buffer::post(void *buf, timeout_t timeout) { size_t rc; if(!timeout) timeout = INFINITE; if(WaitForSingleObject(sem_tail, timeout) != WAIT_OBJECT_0) return Buffer::timeout; enterMutex(); rc = onPost(buf); ++_used; leaveMutex(); ::ReleaseSemaphore(sem_head, 1, (LPLONG)NULL); return rc; } #else size_t Buffer::wait(void *buf, timeout_t waiting) { size_t rc = 0; enterMutex(); while(!_used) { if(!Conditional::wait(waiting, true)) { leaveMutex(); return Buffer::timeout; } } rc = (ssize_t)onWait(buf); --_used; Conditional::signal(false); leaveMutex(); return rc; } size_t Buffer::post(void *buf, timeout_t waiting) { size_t rc = 0; enterMutex(); while(_used == _size) { if(!Conditional::wait(waiting, true)) { leaveMutex(); return Buffer::timeout; } } rc = (ssize_t)onPost(buf); ++_used; Conditional::signal(false); leaveMutex(); return rc; } size_t Buffer::peek(void *buf) { size_t rc; enterMutex(); if(!_used) { leaveMutex(); return 0; } rc = onPeek(buf); leaveMutex(); return rc; } #endif bool Buffer::isValid(void) { return true; } FixedBuffer::FixedBuffer(size_t capacity, size_t osize) : Buffer(capacity) { objsize = osize; buf = new char[capacity * objsize]; #ifdef CCXX_EXCEPTIONS if(!buf && Thread::getException() == Thread::throwObject) throw(this); else if(!buf && Thread::getException() == Thread::throwException) throw(SyncException("fixed buffer failure")); #endif head = tail = buf; } FixedBuffer::~FixedBuffer() { if(buf) delete[] buf; } bool FixedBuffer::isValid(void) { if(head && tail) return true; return false; } #define MAXBUF (buf + (getSize() * objsize)) size_t FixedBuffer::onWait(void *data) { memcpy(data, head, objsize); if((head += objsize) >= MAXBUF) head = buf; return objsize; } size_t FixedBuffer::onPost(void *data) { memcpy(tail, data, objsize); if((tail += objsize) >= MAXBUF) tail = buf; return objsize; } size_t FixedBuffer::onPeek(void *data) { memcpy(data, head, objsize); return objsize; } ThreadQueue::ThreadQueue(const char *id, int pri, size_t stack) : Mutex(), Thread(pri, stack), Semaphore(0), name(id) { first = last = NULL; started = false; timeout = 0; } ThreadQueue::~ThreadQueue() { data_t *data, *next; if(started) { started = false; } data = first; while(data) { next = data->next; delete[] data; data = next; } } void ThreadQueue::run(void) { bool posted; data_t *prev; started = true; for(;;) { posted = Semaphore::wait(timeout); if(!posted) { onTimer(); if(!first) continue; } if(!started) sleep((timeout_t)~0); startQueue(); while(first) { runQueue(first->data); enterMutex(); prev = first; first = first->next; delete[] prev; if(!first) last = NULL; leaveMutex(); if(first) Semaphore::wait(); // demark semaphore } stopQueue(); } } void ThreadQueue::final() { } void ThreadQueue::onTimer(void) { } void ThreadQueue::setTimer(timeout_t timed) { enterMutex(); timeout = timed; leaveMutex(); if(!started) { start(); started = true; } else if(!first) Semaphore::post(); } void ThreadQueue::post(const void *dp, unsigned len) { data_t *data = (data_t *)new char[sizeof(data_t) + len]; memcpy(data->data, dp, len); data->len = len; data->next = NULL; enterMutex(); if(!first) first = data; if(last) last->next = data; last = data; if(!started) { start(); started = true; } leaveMutex(); Semaphore::post(); } void ThreadQueue::startQueue(void) { } void ThreadQueue::stopQueue(void) { } } // namespace ost commoncpp-7.0.1/commoncpp/tokenizer.cpp000066400000000000000000000112531411242573100202250ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include #include #include namespace ost { // sorted by the usual probability of occurence // see also: manpage of isspace() const char * const StringTokenizer::SPACE=" \t\n\r\f\v"; StringTokenizer::StringTokenizer (const char *_str, const char *_delim, bool _skipAll, bool _trim) : str(_str),delim(_delim),skipAll(_skipAll),trim(_trim) { if (str == 0) itEnd = iterator(*this, 0); else itEnd = iterator(*this,strchr(str, '\0')+1); } StringTokenizer::StringTokenizer (const char *s) : str(s), delim(SPACE), skipAll(false),trim(true) { if (str == 0) itEnd = iterator(*this, 0); else itEnd = iterator(*this,strchr(str, '\0')+1); } StringTokenizer::iterator& StringTokenizer::iterator::operator ++ () THROWS (StringTokenizer::NoSuchElementException) { // someone requested to read beyond the end .. tsts if (endp == myTok->itEnd.endp) THROW (NoSuchElementException()); if (token) { // this is to help people find their bugs, if they // still maintain a pointer to this invalidated // area :-) *token = '\0'; delete[] token; token = 0; } start = ++endp; if (endp == myTok->itEnd.endp) return *this; // done // search for next delimiter while (*endp && strchr(myTok->delim, *endp)==NULL) ++endp; tokEnd = endp; if (*endp && myTok->skipAll) { // skip all delimiters while (*(endp+1) && strchr(myTok->delim, *(endp+1))) ++endp; } return *this; } /* * if no one requests the token, no time is spent skipping the whitespaces * or allocating memory. */ const char * StringTokenizer::iterator::operator * () THROWS (StringTokenizer::NoSuchElementException) { // someone requested to read beyond the end .. tsts if (endp == myTok->itEnd.endp) THROW (NoSuchElementException()); if (!token) { /* * someone requests this token; return a copy to provide * a NULL terminated string. */ /* don't clobber tokEnd, it is used in nextDelimiter() */ const char *wsTokEnd = tokEnd; if (myTok->trim) { while (wsTokEnd > start && strchr(SPACE, *start)) ++start; while (wsTokEnd > start && strchr(SPACE,*(wsTokEnd-1))) --wsTokEnd; } size_t tokLen = wsTokEnd - start; if (start > wsTokEnd) { tokLen = 0; } token = newString(start, tokLen + 1); } return token; } } // namespace ost commoncpp-7.0.1/commoncpp/udp.cpp000066400000000000000000000420441411242573100170050ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, 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. // #include #include #include #include #include #include #ifdef _MSWINDOWS_ #include #define _IOLEN64 (unsigned) #define _IORET64 (int) typedef int socklen_t; #define socket_errno WSAGetLastError() #else #include #include #ifdef HAVE_NET_IP6_H #include #endif #define socket_errno errno # ifndef O_NONBLOCK # define O_NONBLOCK O_NDELAY # endif # ifdef IPPROTO_IP # ifndef SOL_IP # define SOL_IP IPPROTO_IP # endif // !SOL_IP # endif // IPPROTO_IP #endif // !WIN32 #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK (unsigned long)0x7f000001 #endif #ifdef HAVE_NETINET_IN_H #include #endif #if defined(__hpux) #define _XOPEN_SOURCE_EXTENDED #endif #ifdef HAVE_NET_IF_H #include #endif #ifndef _IOLEN64 #define _IOLEN64 #endif #ifndef _IORET64 #define _IORET64 #endif namespace ost { #ifdef HAVE_GETADDRINFO UDPSocket::UDPSocket(const char *name, Family fam) : Socket(fam, SOCK_DGRAM, IPPROTO_UDP) { char namebuf[128], *cp; struct addrinfo hint, *list = NULL, *first; family = fam; peer.setAny(fam); snprintf(namebuf, sizeof(namebuf), "%s", name); cp = strrchr(namebuf, '/'); if(!cp && family == IPV4) cp = strrchr(namebuf, ':'); if(!cp) { cp = namebuf; name = NULL; } else { name = namebuf; *(cp++) = 0; if(!strcmp(name, "*")) name = NULL; } memset(&hint, 0, sizeof(hint)); hint.ai_family = family; hint.ai_socktype = SOCK_DGRAM; hint.ai_protocol = IPPROTO_UDP; hint.ai_flags = AI_PASSIVE; if(getaddrinfo(name, cp, &hint, &list) || !list) { error(errBindingFailed, (char *)"Could not find service", errno); endSocket(); return; } #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif first = list; while(list) { if(!bind(so, list->ai_addr, (socklen_t)list->ai_addrlen)) { state = BOUND; break; } list = list->ai_next; } freeaddrinfo(first); if(state != BOUND) { endSocket(); error(errBindingFailed, (char *)"Count not bind socket", errno); return; } } #else UDPSocket::UDPSocket(const char *name, Family fam) : Socket(fam, SOCK_DGRAM, IPPROTO_UDP) { char namebuf[128], *cp; family = fam; peer.setAny(fam); snprintf(namebuf, sizeof(namebuf), "%s", name); cp = strrchr(namebuf, '/'); if(!cp && family == IPV4) cp = strrchr(namebuf, ':'); if(!cp) { cp = namebuf; name = "*"; } else { name = namebuf; *(cp++) = 0; } Socket::address addr(namebuf, cp, SOCK_DGRAM); #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif if(addr.isValid() && !bind(so, addr, addr.getLength())) state = BOUND; if(state != BOUND) { endSocket(); error(errBindingFailed, (char *)"Count not bind socket", errno); return; } } #endif UDPSocket::UDPSocket(Family fam) : Socket(fam, SOCK_DGRAM, IPPROTO_UDP) { family = fam; peer.setAny(fam); } UDPSocket::UDPSocket(const ucommon::Socket::address &ia) : Socket(ia.family(), SOCK_DGRAM, IPPROTO_UDP) { family = ia.family() == AF_INET6 ? IPV6 : IPV4; peer = ia; #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif if(bind(so, peer, (socklen_t)peer.getLength())) { endSocket(); error(errBindingFailed,(char *)"Could not bind socket",socket_errno); return; } state = BOUND; } UDPSocket::UDPSocket(const IPV4Address &ia, in_port_t port) : Socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP), peer(ia.getAddress(), port), family(IPV4) { #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif if(bind(so, peer, sizeof(sockaddr_in))) { endSocket(); error(errBindingFailed,(char *)"Could not bind socket",socket_errno); return; } state = BOUND; } #ifdef CCXX_IPV6 UDPSocket::UDPSocket(const IPV6Address &ia, in_port_t port) : Socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP), peer(ia.getAddress(), port), family(IPV6) { #if defined(SO_REUSEADDR) int opt = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt)); #endif if(bind(so, peer, sizeof(sockaddr_in6))) { endSocket(); error(errBindingFailed,(char *)"Could not bind socket",socket_errno); return; } state = BOUND; } #endif UDPSocket::~UDPSocket() { endSocket(); } ssize_t UDPSocket::send(const void *buf, size_t len) { const struct sockaddr *addr = peer; socklen_t alen = (socklen_t)peer.getLength(); if(isConnected()) { addr = NULL; alen = 0; } return _IORET64 ::sendto(so, (const char *)buf, _IOLEN64 len, MSG_NOSIGNAL, addr, alen); } ssize_t UDPSocket::receive(void *buf, size_t len, bool reply) { struct sockaddr *addr = peer; socklen_t alen = (socklen_t)peer.getLength(); struct sockaddr_in6 senderAddress; // DMC 2/7/05 ADD for use below. if(isConnected() || !reply) { // DMC 2/7/05 MOD to use senderAddress instead of NULL, to prevent 10014 error // from recvfrom. //addr = NULL; //alen = 0; addr = (struct sockaddr*)(&senderAddress); alen = sizeof(struct sockaddr_in6); } int bytes = ::recvfrom(so, (char *)buf, _IOLEN64 len, 0, addr, &alen); #ifdef _MSWINDOWS_ if (bytes == SOCKET_ERROR) { WSAGetLastError(); } #endif return _IORET64 bytes; } Socket::Error UDPSocket::join(const IPV4Multicast &ia,int InterfaceIndex) { return join(Socket::address(getaddress(ia)), InterfaceIndex); } Socket::Error UDPSocket::join(const ucommon::Socket::address &ia, int InterfaceIndex) { return Socket::join(ia, InterfaceIndex); } Socket::Error UDPSocket::getInterfaceIndex(const char *DeviceName,int& InterfaceIndex) { #ifndef _MSWINDOWS_ #if defined(IP_ADD_MEMBERSHIP) && defined(SIOCGIFINDEX) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && !defined(_OSF_SOURCE) && !defined(__hpux) && !defined(__GNU__) && !defined(__NetBSD__) struct ip_mreqn mreqn; struct ifreq m_ifreq; int i; sockaddr_in* in4 = (sockaddr_in*)peer.get(AF_INET); InterfaceIndex = -1; memset(&mreqn, 0, sizeof(mreqn)); memcpy(&mreqn.imr_multiaddr.s_addr, &in4->sin_addr, sizeof(mreqn.imr_multiaddr.s_addr)); for (i = 0; i < IFNAMSIZ && DeviceName[i]; ++i) m_ifreq.ifr_name[i] = DeviceName[i]; for (; i < IFNAMSIZ; ++i) m_ifreq.ifr_name[i] = 0; if (ioctl (so, SIOCGIFINDEX, &m_ifreq)) return error(errServiceUnavailable); #if defined(__FreeBSD__) || defined(__GNU__) InterfaceIndex = m_ifreq.ifr_ifru.ifru_index; #else InterfaceIndex = m_ifreq.ifr_ifindex; #endif return errSuccess; #else return error(errServiceUnavailable); #endif #else return error(errServiceUnavailable); #endif // WIN32 } #ifdef AF_UNSPEC Socket::Error UDPSocket::disconnect(void) { struct sockaddr_in addr; int len = sizeof(addr); if(so == INVALID_SOCKET) return errSuccess; Socket::state = BOUND; memset(&addr, 0, len); #ifndef _MSWINDOWS_ addr.sin_family = AF_UNSPEC; #else addr.sin_family = AF_INET; memset(&addr.sin_addr, 0, sizeof(addr.sin_addr)); #endif if(::connect(so, (sockaddr *)&addr, len)) return connectError(); return errSuccess; } #else Socket::Error UDPSocket::disconnect(void) { if(so == INVALID_SOCKET) return errSuccess; Socket::state = BOUND; return connect(getLocal()); } #endif void UDPSocket::setPeer(const ucommon::Socket::address &host) { peer = host; } void UDPSocket::connect(const ucommon::Socket::address &host) { peer = host; if(so == INVALID_SOCKET) return; if(!::connect(so, host.get(), (socklen_t)host.getLength())) Socket::state = CONNECTED; } void UDPSocket::setPeer(const IPV4Host &ia, in_port_t port) { peer = ucommon::Socket::address(ia.getAddress(), port); } void UDPSocket::connect(const IPV4Host &ia, in_port_t port) { setPeer(ia, port); if(so == INVALID_SOCKET) return; if(!::connect(so, (struct sockaddr *)peer.get(AF_INET), sizeof(struct sockaddr_in))) Socket::state = CONNECTED; } #ifdef CCXX_IPV6 void UDPSocket::setPeer(const IPV6Host &ia, in_port_t port) { peer = ucommon::Socket::address(ia.getAddress(), port); } void UDPSocket::connect(const IPV6Host &ia, in_port_t port) { setPeer(ia, port); if(so == INVALID_SOCKET) return; if(!::connect(so, (struct sockaddr *)peer.get(AF_INET6), sizeof(struct sockaddr_in6))) Socket::state = CONNECTED; } #endif void UDPSocket::setPeer(const char *name) { struct addrinfo *list = ucommon::Socket::query(name, NULL, SOCK_DGRAM, IPPROTO_UDP); peer = ucommon::Socket::address(list); freeaddrinfo(list); } void UDPSocket::connect(const char *service) { int rtn = -1; setPeer(service); if(so == INVALID_SOCKET) return; rtn = ::connect(so, peer, (socklen_t)peer.getLength()); if(!rtn) Socket::state = CONNECTED; } ucommon::Socket::address UDPSocket::getPeer() { ucommon::Socket::address addr = Socket::getPeer(); setPeer(addr); return addr; } IPV4Host UDPSocket::getIPV4Peer(in_port_t *port) { ucommon::Socket::address addr = getPeer(); if (addr.is_valid()) { if(port) *port = peer.getPort(); } else { peer.setAny(); if(port) *port = 0; } return IPV4Host(ucommon::Socket::address::ipv4(addr)->sin_addr); } #ifdef CCXX_IPV6 IPV6Host UDPSocket::getIPV6Peer(in_port_t *port) { ucommon::Socket::address addr = getPeer(); if (addr.is_valid()) { if(port) *port = peer.getPort(); } else { peer.setAny(); if(port) *port = 0; } return IPV6Host(ucommon::Socket::address::ipv6(addr)->sin6_addr); } #endif UDPBroadcast::UDPBroadcast(const IPV4Address &ia, in_port_t port) : UDPSocket(ia, port) { if(so != INVALID_SOCKET) setBroadcast(true); } void UDPBroadcast::setPeer(const IPV4Broadcast &ia, in_port_t port) { peer = ucommon::Socket::address(ia.getAddress(), port); } UDPTransmit::UDPTransmit(const ucommon::Socket::address &ia) : UDPSocket(ia) { disconnect(); // assure not started live ::shutdown(so, 0); receiveBuffer(0); } UDPTransmit::UDPTransmit(const IPV4Address &ia, in_port_t port) : UDPSocket(ia, port) { disconnect(); // assure not started live ::shutdown(so, 0); receiveBuffer(0); } #ifdef CCXX_IPV6 UDPTransmit::UDPTransmit(const IPV6Address &ia, in_port_t port) : UDPSocket(ia, port) { disconnect(); // assure not started live ::shutdown(so, 0); receiveBuffer(0); } #endif UDPTransmit::UDPTransmit(Family family) : UDPSocket(family) { disconnect(); ::shutdown(so, 0); receiveBuffer(0); } Socket::Error UDPTransmit::connect(const ucommon::Socket::address &host) { peer = host; if(peer.isAny()) peer.setLoopback(); if(::connect(so, peer, (socklen_t)peer.getLength())) return connectError(); return errSuccess; } Socket::Error UDPTransmit::cConnect(const IPV4Address &ia, in_port_t port) { return connect(ucommon::Socket::address(ia.getAddress(), port)); } #ifdef CCXX_IPV6 Socket::Error UDPTransmit::connect(const IPV6Address &ia, in_port_t port) { return connect(ucommon::Socket::address(ia.getAddress(), port)); } #endif Socket::Error UDPTransmit::connect(const IPV4Host &ia, in_port_t port) { if(isBroadcast()) setBroadcast(false); return cConnect((IPV4Address)ia,port); } Socket::Error UDPTransmit::connect(const IPV4Broadcast &subnet, in_port_t port) { if(!isBroadcast()) setBroadcast(true); return cConnect((IPV4Address)subnet,port); } Socket::Error UDPTransmit::connect(const IPV4Multicast &group, in_port_t port) { Error err; if(!( err = UDPSocket::setMulticast(true) )) return err; return cConnect((IPV4Address)group,port); } #ifdef CCXX_IPV6 Socket::Error UDPTransmit::connect(const IPV6Multicast &group, in_port_t port) { Error error; if(!( error = UDPSocket::setMulticast(true) )) return error; return connect((IPV6Address)group,port); } #endif UDPReceive::UDPReceive(const ucommon::Socket::address &ia) : UDPSocket(ia) { ::shutdown(so, 1); sendBuffer(0); } UDPReceive::UDPReceive(const IPV4Address &ia, in_port_t port) : UDPSocket(ia, port) { ::shutdown(so, 1); sendBuffer(0); } #ifdef CCXX_IPV6 UDPReceive::UDPReceive(const IPV6Address &ia, in_port_t port) : UDPSocket(ia, port) { ::shutdown(so, 1); sendBuffer(0); } #endif Socket::Error UDPReceive::connect(const ucommon::Socket::address &ia) { ucommon::Socket::address host = ia; setPeer(host); // Win32 will crash if you try to connect to INADDR_ANY. if(host.isAny()) host.setLoopback(); if(::connect(so, host, (socklen_t)host.getLength())) return connectError(); return errSuccess; } Socket::Error UDPReceive::connect(const IPV4Host &ia, in_port_t port) { return connect(ucommon::Socket::address(ia.getAddress(), port)); } #ifdef CCXX_IPV6 Socket::Error UDPReceive::connect(const IPV6Host &ia, in_port_t port) { return connect(ucommon::Socket::address(ia.getAddress(), port)); } #endif UDPDuplex::UDPDuplex(const ucommon::Socket::address &bind) : UDPTransmit(bind.withPort(bind.getPort() + 1)), UDPReceive(bind) {} UDPDuplex::UDPDuplex(const IPV4Address &bind, in_port_t port) : UDPTransmit(bind, port + 1), UDPReceive(bind, port) {} #ifdef CCXX_IPV6 UDPDuplex::UDPDuplex(const IPV6Address &bind, in_port_t port) : UDPTransmit(bind, port + 1), UDPReceive(bind, port) {} #endif Socket::Error UDPDuplex::connect(const ucommon::Socket::address &host) { Error rtn = UDPTransmit::connect(host); if(rtn) { UDPTransmit::disconnect(); UDPReceive::disconnect(); return rtn; } return UDPReceive::connect(host.withPort(host.getPort() + 1)); } Socket::Error UDPDuplex::connect(const IPV4Host &host, in_port_t port) { Error rtn = UDPTransmit::connect(host, port); if(rtn) { UDPTransmit::disconnect(); UDPReceive::disconnect(); return rtn; } return UDPReceive::connect(host, port + 1); } #ifdef CCXX_IPV6 Socket::Error UDPDuplex::connect(const IPV6Host &host, in_port_t port) { Error rtn = UDPTransmit::connect(host, port); if(rtn) { UDPTransmit::disconnect(); UDPReceive::disconnect(); return rtn; } return UDPReceive::connect(host, port + 1); } #endif Socket::Error UDPDuplex::disconnect(void) { Error rtn = UDPTransmit::disconnect(); Error rtn2 = UDPReceive::disconnect(); if (rtn) return rtn; return rtn2; } } // namespace ost commoncpp-7.0.1/commoncpp/xml.cpp000066400000000000000000000350671411242573100170240ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 // local includes #include static bool isElement(char c) { return isalnum(c) || c == ':' || c == '-' || c == '.' || c == '_'; } namespace ost { using namespace ucommon; XMLParser::XMLParser(unsigned size) { state = NONE; bufpos = 0; bufsize = size; buffer = new char[size]; ecount = dcount = 0; } XMLParser::~XMLParser() { if(buffer) { delete[] buffer; buffer = NULL; } } void XMLParser::putBuffer(char c) { buffer[bufpos++] = c; if(bufpos >= bufsize) { if(ecount) characters((caddr_t)buffer, bufpos); bufpos = 0; } } void XMLParser::clearBuffer(void) { if(bufpos && ecount) characters((caddr_t)buffer, bufpos); bufpos = 0; } bool XMLParser::parse(FILE *fp) { state = NONE; bufpos = 0; ecount = dcount = 0; int ch; unsigned char cp; while((ch = fgetc(fp)) != EOF) { switch(state) { case AMP: if((!bufpos && ch == '#') || isElement(ch)) { buffer[bufpos++] = ch; break; } if(ch != ';') return false; buffer[bufpos] = 0; if(buffer[0] == '#') cp = atoi(buffer + 1); else if(eq(buffer, "amp")) cp = '&'; else if(eq(buffer, "lt")) cp = '<'; else if(eq(buffer, "gt")) cp = '>'; else if(eq(buffer, "apos")) cp = '`'; else if(eq(buffer, "quot")) cp = '\"'; else return false; characters((caddr_t)&cp, 1); bufpos = 0; state = NONE; break; case TAG: if(ch == '>') { state = NONE; if(!parseTag()) return false; } else if(ch == '[' && bufpos == 7 && !strncmp(buffer, "![CDATA", 7)) { state = CDATA; } else if(ch == '-' && bufpos == 2 && !strncmp(buffer, "!-", 2)) { state = COMMENT; bufpos = 0; } else if(ch == '[' && !strncmp(buffer, "!DOCTYPE ", 9)) { state = DTD; bufpos = 0; } else putBuffer(ch); break; case COMMENT: if(ch == '>' && bufpos >= 2 && !strncmp(&buffer[bufpos - 2], "--", 2)) { bufpos -= 2; if(bufpos) comment((caddr_t)buffer, bufpos); bufpos = 0; state = NONE; } else { buffer[bufpos++] = ch; if(bufpos == bufsize) { comment((caddr_t)buffer, bufpos); bufpos = 0; } } break; case CDATA: putBuffer(ch); if(bufpos > 2) if(eq(&buffer[bufpos - 3], "]]>")) { bufpos -= 3; state = NONE; clearBuffer(); } break; case DTD: if(ch == '<') ++dcount; else if(ch == '>' && dcount) --dcount; else if(ch == '>') state = NONE; break; case NONE: if(ch == '<') { clearBuffer(); state = TAG; } else if(ecount && ch == '&') { clearBuffer(); state = AMP; } else if(ecount) putBuffer(ch); break; case END: return true; } if(state == END) return true; } // eof before end of ducument... return false; } bool XMLParser::parse(const char *buf) { state = NONE; bufpos = 0; ecount = dcount = 0; uint8_t ch; unsigned char cp; while((ch = (uint8_t)*(buf++)) != 0) { switch(state) { case AMP: if((!bufpos && ch == '#') || isElement(ch)) { buffer[bufpos++] = ch; break; } if(ch != ';') return false; buffer[bufpos] = 0; if(buffer[0] == '#') cp = atoi(buffer + 1); else if(eq(buffer, "amp")) cp = '&'; else if(eq(buffer, "lt")) cp = '<'; else if(eq(buffer, "gt")) cp = '>'; else if(eq(buffer, "apos")) cp = '`'; else if(eq(buffer, "quot")) cp = '\"'; else return false; characters((caddr_t)&cp, 1); bufpos = 0; state = NONE; break; case TAG: if(ch == '>') { state = NONE; if(!parseTag()) return false; } else if(ch == '[' && bufpos == 7 && !strncmp(buffer, "![CDATA", 7)) { state = CDATA; } else if(ch == '-' && bufpos == 2 && !strncmp(buffer, "!-", 2)) { state = COMMENT; bufpos = 0; } else if(ch == '[' && !strncmp(buffer, "!DOCTYPE ", 9)) { state = DTD; bufpos = 0; } else putBuffer(ch); break; case COMMENT: if(ch == '>' && bufpos >= 2 && !strncmp(&buffer[bufpos - 2], "--", 2)) { bufpos -= 2; if(bufpos) comment((caddr_t)buffer, bufpos); bufpos = 0; state = NONE; } else { buffer[bufpos++] = ch; if(bufpos == bufsize) { comment((caddr_t)buffer, bufpos); bufpos = 0; } } break; case CDATA: putBuffer(ch); if(bufpos > 2) if(eq(&buffer[bufpos - 3], "]]>")) { bufpos -= 3; state = NONE; clearBuffer(); } break; case DTD: if(ch == '<') ++dcount; else if(ch == '>' && dcount) --dcount; else if(ch == '>') state = NONE; break; case NONE: if(ch == '<') { clearBuffer(); state = TAG; } else if(ecount && ch == '&') { clearBuffer(); state = AMP; } else if(ecount) putBuffer(ch); break; case END: return true; } if(state == END) return true; } // eof before end of ducument... return false; } bool XMLParser::partial(const char *data, size_t len) { if(state == END) state = NONE; unsigned char cp; while(len--) { switch(state) { case AMP: if((!bufpos && *data == '#') || isElement(*data)) { buffer[bufpos++] = *data; break; } if(*data != ';') return false; buffer[bufpos] = 0; if(buffer[0] == '#') cp = atoi(buffer + 1); else if(eq(buffer, "amp")) cp = '&'; else if(eq(buffer, "lt")) cp = '<'; else if(eq(buffer, "gt")) cp = '>'; else if(eq(buffer, "apos")) cp = '`'; else if(eq(buffer, "quot")) cp = '\"'; else return false; characters((caddr_t)&cp, 1); bufpos = 0; state = NONE; break; case TAG: if(*data == '>') { state = NONE; if(!parseTag()) return false; } else if(*data == '[' && bufpos == 7 && !strncmp(buffer, "![CDATA", 7)) { state = CDATA; } else if(*data == '-' && bufpos == 2 && !strncmp(buffer, "!-", 2)) { state = COMMENT; bufpos = 0; } else if(*data == '[' && !strncmp(buffer, "!DOCTYPE ", 9)) { state = DTD; bufpos = 0; } else putBuffer(*data); break; case COMMENT: if(*data == '>' && bufpos >= 2 && !strncmp(&buffer[bufpos - 2], "--", 2)) { bufpos -= 2; if(bufpos) comment((caddr_t)buffer, bufpos); bufpos = 0; state = NONE; } else { buffer[bufpos++] = *data; if(bufpos == bufsize) { comment((caddr_t)buffer, bufpos); bufpos = 0; } } break; case CDATA: putBuffer(*data); if(bufpos > 2) if(eq(&buffer[bufpos - 3], "]]>")) { bufpos -= 3; state = NONE; clearBuffer(); } break; case DTD: if(*data == '<') ++dcount; else if(*data == '>' && dcount) --dcount; else if(*data == '>') state = NONE; break; case NONE: case END: if(*data == '<') { clearBuffer(); state = TAG; } else if(ecount && *data == '&') { clearBuffer(); state = AMP; } else if(ecount) putBuffer(*data); } ++data; } return true; } bool XMLParser::parseTag(void) { size_t len = bufpos; const char *data = buffer; bool end = false; caddr_t attrib[128]; unsigned attr = 0; char *ep; if(*data == '/') { while(--len) { if(!isElement(*(++data))) break; } if(len) return false; buffer[bufpos] = 0; endElement((caddr_t)(buffer + 1)); bufpos = 0; --ecount; if(ecount < 0) return false; if(!ecount) { state = END; endDocument(); } } else if(*data == '!') { bufpos = 0; return true; // dtd } else if(*data == '?') { if(!strnicmp(data, "?xml version=\"", 14)) { // version info } bufpos = 0; } else if(!isElement(*data)) return false; else { end = false; if(buffer[bufpos - 1] == '/') { --bufpos; end = true; } len = 0; data = buffer; while(len < bufpos) { if(!isElement(*data)) break; ++len; ++data; } if(len == bufpos) { if(!ecount) startDocument(); ++ecount; attrib[0] = attrib[1] = NULL; buffer[bufpos] = 0; startElement((caddr_t)buffer, attrib); if(end) { ending: --ecount; endElement((caddr_t)buffer); if(!ecount) { state = END; endDocument(); } } bufpos = 0; return true; } if(!ecount) startDocument(); ++ecount; // attributes, name is between data and len for(;;) { while(!isElement(buffer[len]) && len < bufpos) { if(!isspace(buffer[len])) return false; buffer[len++] = 0; } if(len == bufpos) break; attrib[attr++] = (caddr_t)(buffer + len); while(len < bufpos && isElement(buffer[len])) ++len; if(len == bufpos) return false; if(buffer[len] != '=') return false; buffer[len++] = 0; if(len == bufpos) { attrib[attr++] = (caddr_t)""; break; } if(isspace(buffer[len])) { attrib[attr++] = (caddr_t)""; continue; } if(buffer[len] == '\'' || buffer[len] == '\"') { ep = strchr(buffer + len + 1, buffer[len]); if(!ep) return false; attrib[attr++] = (caddr_t)buffer + len + 1; *(ep++) = 0; len = ep - buffer; continue; } if(!isElement(buffer[len])) return false; attrib[attr++] = (caddr_t)buffer; while(isElement(buffer[len]) && len < bufpos) ++len; if(len == bufpos) { buffer[len] = 0; break; } } attrib[attr++] = NULL; attrib[attr++] = NULL; startElement((caddr_t)buffer, attrib); if(end) goto ending; bufpos = 0; return true; } return true; } // all our lovely base virtuals stubbed out so if we are lazy and forget to // implement something we want to ignore anyway (say comments...) we don't // bring whatever it is crashing down one day when we choose to add a // comment into an xml stream... void XMLParser::startDocument() { } void XMLParser::endDocument() { } void XMLParser::comment(const caddr_t text, size_t len) { } void XMLParser::characters(const caddr_t text, size_t len) { } } // namespace ucommon commoncpp-7.0.1/configure.ac000066400000000000000000000452411411242573100160060ustar00rootroot00000000000000# Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015-2020 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. AC_INIT([ucommon],[7.0.1]) AC_CONFIG_SRCDIR([inc/ucommon/ucommon.h]) LT_VERSION="8:1:0" OPENSSL_REQUIRES="0.9.7" AC_CONFIG_AUX_DIR(autoconf) AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_SYSTEM AC_PROG_CPP AC_PROG_CC AC_PROG_CXXCPP AC_PROG_CXX AC_LIBTOOL_WIN32_DLL AM_PROG_LIBTOOL AM_INIT_AUTOMAKE([dist-zip subdir-objects]) AM_CONFIG_HEADER(ucommon-config.h) AC_C_RESTRICT AC_C_VOLATILE AC_C_INLINE UCOMMON_FLAGS="" UCOMMON_MODEL="CXX" UCOMMON_LIBC="-lc" UCOMMON_LIBS="" OPENSSL_LINK="" MODULE_FLAGS="-module -shared -avoid-version" CHECKFLAGS="$CHECKFLAGS" case "$with_crypto" in ssl|openssl) ssl="openssl" ;; gnutls|gnu) ssl="gnutls" ;; none|nossl) ssl="nossl" ;; *) ssl="detect" ;; esac have_gettext="no" socket_lib="" posix4_lib="" rt_lib="" test -z "$localedir" && localedir='${datadir}/locale' AC_DEFUN([AC_SUBST_DIR], [ ifelse($2,,,$1="[$]$2") result="***" prior="A" while test "$prior" != "$result" ; do prior=`(echo "[$]$1")` $1=`( test "x$prefix" = xNONE && prefix="$ac_default_prefix" test "x$exec_prefix" = xNONE && exec_prefix="${prefix}" eval echo \""[$]$1"\" )` result=`(echo "[$]$1")` done AC_SUBST($1) ]) # for very old gcc and for minix we disable full ucommon build by default # we also disable for mingw32 or when no "shared" library support because # libstdc++ is not dll and really bloats in linkage of plugins. Any case, # you can always override with --enable-stdcpp... if test -z "$enable_stdcpp" ; then if test "x$GCC" = "xyes" ; then gccver=`$CC -dumpversion | cut -f1 -d.` fi if test -z "$gccver" ; then gccver="3" fi if test "$gccver" -lt "3" ; then enable_stdcpp="no" fi if test "x$enable_shared" = "xno" ; then enable_stdcpp="no" fi case "$target_os" in *minix*|mingw*) enable_stdcpp="no" ;; esac fi case "$target_os" in osf*|cygwin*|mingw*) MODULE_FLAGS="-module -shared -no-undefined" ;; darwin*) MODULE_FLAGS="-dynamic -bundle -undefined suppress -flat_namespace -read_only_relocs suppress" ;; esac AC_ARG_ENABLE(posix-timers, AC_HELP_STRING([--enable-posix-timers], [enable posix timers])) if test "x$enable_posix_timers" = "xyes" ; then UCOMMON_FLAGS="$UCOMMON_FLAGS -DPOSIX_TIMERS" fi AC_ARG_ENABLE(utils, [ --disable-utils Do not build the utilities]) if test x"$enable_utils" == "xno"; then AM_CONDITIONAL([BUILD_UTILS], false), else AM_CONDITIONAL([BUILD_UTILS], true) fi AC_ARG_ENABLE(stdcpp, AC_HELP_STRING([--disable-stdcpp], [compile without stdc++ runtime overhead])) AC_MSG_CHECKING([full c++ support and linking model]) if test "x$enable_stdcpp" = "xno" ; then UCOMMON_MODEL="CC" AC_MSG_RESULT(no) COMPAT="" COMPAT_PC="" COMPAT_CONFIG="" else COMPAT="commoncpp" COMPAT_PC="commoncpp.pc" COMPAT_CONFIG="commoncpp-config" AC_MSG_RESULT(yes) fi AC_ARG_WITH(sslstack, AC_HELP_STRING([--with-sslstack=lib],[specify which ssl stack to build]),[ if test x$with_sslstack != x ; then ssl="${with_sslstack}" ; fi ]) AC_ARG_WITH(libc, AC_HELP_STRING([--with-libc=path],[specify path to alternate libc]),[ if test x$with_libc != x ; then clib=`echo ${with_libc} | sed s/[-]l//` UCOMMON_LIBC=-l${clib} ; fi ]) AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[compile for debugging])) if test -z "$enable_debug" ; then enable_debug="no" elif test $enable_debug = "yes" ; then CXXFLAGS="${CXXFLAGS} -g -DDEBUG" fi AH_BOTTOM([ #include ]) threading="none" clib=`echo ${UCOMMON_LIBC} | sed s/[-]l//` tlib="" AC_CHECK_HEADERS(stdint.h poll.h sys/mman.h sys/shm.h sys/poll.h sys/timeb.h endian.h sys/filio.h dirent.h sys/resource.h wchar.h netinet/in.h net/if.h) AC_CHECK_HEADERS(mach/clock.h mach-o/dyld.h linux/version.h sys/inotify.h sys/event.h syslog.h sys/wait.h termios.h termio.h fcntl.h unistd.h) AC_CHECK_HEADERS(sys/param.h sys/lockf.h sys/file.h dlfcn.h stdatomic.h) AC_CHECK_HEADER(regex.h, [ AC_DEFINE(HAVE_REGEX_H, [1], [have regex header]) AC_CHECK_LIB(regex, regfree, [ UCOMMON_LIBS="$UCOMMON_LIBS -lregex" ]) ]) AC_CHECK_LIB(msvcrt, fopen, [ threading="msw" clib="msvcrt" UCOMMON_LIBS="--enable-stdcall-fixup $UCOMMON_LIBS -lmingwex -lmingw32 -lcrypt32 -ladvapi32 -luser32 -lws2_32 -lwsock32 -lkernel32" UCOMMON_LIBC="-lmsvcrt -lgcc" OPENSSL_LINK="-lgdi32" AC_DEFINE(HAVE_INET_NTOP, [1], [have inet_ntop]) AC_DEFINE(HAVE_GETADDRINFO, [1], [have getaddrinfo]) ],[ AC_CHECK_LIB(gcc, __modsi3, [ UCOMMON_LIBC="$UCOMMON_LIBC -lgcc" ]) AC_CHECK_LIB($clib, socketpair, [ AC_DEFINE(HAVE_SOCKETPAIR, [1], [have socketpair]) ],[ AC_CHECK_LIB(socket, socketpair, [AC_DEFINE(HAVE_SOCKETPAIR, [1], [have socketpair])]) ]) AC_CHECK_LIB($clib, getaddrinfo, [ AC_DEFINE(HAVE_GETADDRINFO, [1], [have getaddrinfo]) ],[ AC_CHECK_LIB(socket, getaddrinfo, [AC_DEFINE(HAVE_GETADDRINFO, [1], [have getaddrinfo])]) ]) AC_CHECK_LIB($clib, gethostbyname2, [ AC_DEFINE(HAVE_GETHOSTBYNAME2, [1], [have gethostbyname2]) ],[ AC_CHECK_LIB(socket, gethostbyname2, [AC_DEFINE(HAVE_GETHOSTBYNAME2, [1], [have gethostbyname2])]) ]) AC_CHECK_LIB($clib, inet_ntop, [ AC_DEFINE(HAVE_INET_NTOP, [1], [have inet ntop]) ],[ AC_CHECK_LIB(socket, inet_ntop, [ AC_DEFINE(HAVE_INET_NTOP, [1], [have inet ntop]) ],[ AC_CHECK_LIB(nsl, inet_ntop, [ AC_DEFINE(HAVE_INET_NTOP, [1], [have inet_ntop]) socket_lib="$socket_lib -lnsl" ]) ]) ]) AC_CHECK_LIB(socket, socket,[ AC_CHECK_LIB(socket, socketpair,[ AC_DEFINE(HAVE_SOCKETPAIR, [1], [have socketpair in libsocket]) ]) socket_lib="-lsocket" ]) ]) AC_CHECK_LIB($clib, lstat, [ AC_DEFINE(HAVE_LSTAT, [1], [have lstat]) ]) AC_CHECK_LIB($clib, strcoll, [ AC_DEFINE(HAVE_STRCOLL, [1], [string collation]) ]) AC_CHECK_LIB($clib, strlcpy, [ AC_DEFINE(HAVE_STRLCPY, [1], [string lcpy]) ]) AC_CHECK_LIB($clib, stricmp, [ AC_DEFINE(HAVE_STRICMP, [1], [string icmp]) ]) AC_CHECK_LIB($clib, stristr, [ AC_DEFINE(HAVE_STRISTR, [1], [string istr]) ]) AC_CHECK_LIB($clib, sysconf, [ AC_DEFINE(HAVE_SYSCONF, [1], [system config]) ]) AC_CHECK_LIB($clib, posix_memalign, [ AC_DEFINE(HAVE_POSIX_MEMALIGN, [1], [posix memory alignment]) ]) AC_CHECK_LIB($clib, aligned_alloc, [ AC_DEFINE(HAVE_ALIGNED_ALLOC, [1], [aligned memory allocation]) ]) AC_CHECK_LIB($clib, dlopen,,[ AC_CHECK_LIB(dl, dlopen, [UCOMMON_LIBS="$UCOMMON_LIBS -ldl"],[ AC_CHECK_LIB(compat, dlopen, [UCOMMON_LIBS="$UCOMMON_LIBS -lcompat"]) AC_CHECK_LIB(dld, shl_load,[ AC_DEFINE(HAVE_SHL_LOAD, [1], [alternate dyn loader]) UCOMMON_LIBS="$UCOMMON_LIBS -ldld" ]) ]) ]) PTHREAD_FLAGS="" if test "$enable_shared" = "no" ; then UCOMMON_FLAGS="$UCOMMON_FLAGS -DUCOMMON_STATIC" ; fi AC_ARG_ENABLE(pth, [ AC_HELP_STRING([--enable-pth],[always use GNU pth for threading]) ]) if test "$threading" = "none" ; then if test "$enable_pth" != "yes" ; then AC_CHECK_HEADER(pthread.h, [ PTHREAD_FLAGS="-mt -pthread -pthreads" AC_CHECK_LIB(pthread,pthread_create,[ tlib="pthread" UCOMMON_LIBS="$UCOMMON_LIBS -lpthread" ]) if test -z "$tlib" ; then AC_CHECK_LIB($clib, pthread_create, [tlib="$clib"]) fi if test -z "$tlib" ; then AC_CHECK_LIB(c_r, pthread_create, [ tlib="c_r" if test "$clib" = "c" ; then AC_CHECK_LIB(c_r, malloc, [clib="c_r"]) fi ]) fi if test ! -z "$tlib" ; then AC_CHECK_LIB($tlib,pthread_condattr_setclock,[ AC_DEFINE(HAVE_PTHREAD_CONDATTR_SETCLOCK, [1], ["pthread clocking"]) ]) AC_CHECK_LIB($tlib,pthread_setconcurrency,[ AC_DEFINE(HAVE_PTHREAD_SETCONCURRENCY, [1], ["pthread concurrency"]) ]) AC_CHECK_LIB($tlib,pthread_yield,[ AC_DEFINE(HAVE_PTHREAD_YIELD, [1], ["pthread yield"],[ AC_CHECK_LIB($tlib,pthread_yield_np,[ AC_DEFINE(HAVE_PTHREAD_YIELD_NP, [1], ["pthread yield np"]) ]) ]) ]) AC_CHECK_LIB($tlib,pthread_delay,[ AC_DEFINE(HAVE_PTHREAD_DELAY, [1], ["pthread delay"]) ]) AC_CHECK_LIB($tlib,pthread_delay_np,[ AC_DEFINE(HAVE_PTHREAD_DELAY_NP, [1], ["pthread delay np"]) ]) AC_CHECK_LIB($tlib,pthread_setschedprio,[ AC_DEFINE(HAVE_PTHREAD_SETSCHEDPRIO, [1], ["pthread scheduling"]) ]) # Missing from Android's pthread implementation but the default # values for newly created threads corresponds to the one we set AC_CHECK_LIB($tlib,pthread_attr_setinheritsched,[ AC_DEFINE(HAVE_PTHREAD_ATTR_SETINHRITSCHED, [1], ["pthread inherit scheduling attribute"]) ]) fi ],[ AC_CHECK_HEADER(windows.h,, [ AC_MSG_ERROR("pthread support required") ]) ]) else AC_MSG_ERROR("thread support required") fi fi for func in ftok shm_open nanosleep clock_nanosleep clock_gettime strerror_r localtime_r gmtime_r posix_fadvise ftruncate pwrite setgroups setpgrp setlocale gettext execvp atexit realpath symlink readlink waitpid wait4 endgrent strlcpy; do found="no" AC_CHECK_FUNC($func,[ found=$func ],[ AC_CHECK_LIB(posix4, $func, [ found=$func posix4_lib="-lposix4" ],[ AC_CHECK_LIB(rt, $func, [ found=$func rt_lib="-lrt" ],[ if test ! -z "$tlib" ; then AC_CHECK_LIB($tlib, $func, [ found=$func ]) fi ]) ]) ]) case $found in setgroups) AC_DEFINE(HAVE_SETGROUPS, [1], [setgroups support]) ;; shm_open) AC_DEFINE(HAVE_SHM_OPEN, [1], [shared memory open]) ;; setpgrp) AC_DEFINE(HAVE_SETPGRP, [1], [process group control]) ;; realpath) AC_DEFINE(HAVE_REALPATH, [1], [realpath support]) ;; ftok) AC_DEFINE(HAVE_FTOK, [1], [has ftok]) ;; gmtime_r) AC_DEFINE(HAVE_GMTIME_R, [1], [has localtime_r]) ;; localtime_r) AC_DEFINE(HAVE_LOCALTIME_R, [1], [has localtime_r]) ;; strerror_r) AC_DEFINE(HAVE_STRERROR_R, [1], [has strerror_r]) ;; nanosleep) AC_DEFINE(HAVE_NANOSLEEP, [1], [has nanosleep]) ;; clock_nanosleep) AC_DEFINE(HAVE_CLOCK_NANOSLEEP, [1], [has clocked nanosleep]) ;; clock_gettime) AC_DEFINE(HAVE_CLOCK_GETTIME, [1], [has posix clock functions]) ;; posix_fadvise) AC_DEFINE(HAVE_POSIX_FADVISE, [1], [can specify access options]) ;; ftruncate) AC_DEFINE(HAVE_FTRUNCATE, [1], [can truncate files]) ;; pwrite) AC_DEFINE(HAVE_PWRITE, [1], [can do atomic write with offset]) ;; setlocale) AC_DEFINE(HAVE_SETLOCALE, [1], [can set localization]) ;; gettext) AC_DEFINE(HAVE_GETTEXT, [1], [has gettext in libc]) have_gettext="yes" ;; execvp) AC_DEFINE(HAVE_EXECVP, [1], [has execvp in libc]) ;; symlink) AC_DEFINE(HAVE_SYMLINK, [1], [has symlink in libc]) ;; readlink) AC_DEFINE(HAVE_READLINK, [1], [has readlink in libc]) ;; waitpid) AC_DEFINE(HAVE_WAITPID, [1], [has waitpid in libc]) ;; wait4) AC_DEFINE(HAVE_WAIT4, [1], [has wait4 in libc]) ;; endgrent) AC_DEFINE(HAVE_ENDGRENT, [1], [has endgrent in libc]) ;; esac done UCOMMON_LINKED="$socket_lib $posix4_lib $rt_lib $UCOMMON_LIBS" UCOMMON_LIBS="$socket_lib $posix4_lib $rt_lib $UCOMMON_LIBS $UCOMMON_LIBC" if test "$UCOMMON_MODEL" = "CC" ; then AC_CHECK_LIB(Systemstubs, printf, [ UCOMMON_LIBC="$UCOMMON_LIBC -lgcc" ]) fi if test "x$GCC" = "xyes" ; then UCOMMON_FLAGS="$UCOMMON_FLAGS -Wno-long-long" ; fi AC_LANG_SAVE AC_LANG_CPLUSPLUS if test ! -z "$PTHREAD_FLAGS" ; then for flag in $PTHREAD_FLAGS ; do AC_MSG_CHECKING([whether ${CXX} supports $flag]) echo 'void f(){}' >conftest.cpp if test -z "`${CXX} $flag -c conftest.cpp 2>&1`"; then AC_MSG_RESULT(yes) UCOMMON_FLAGS="$UCOMMON_FLAGS $flag" break else AC_MSG_RESULT(no) fi done fi # libstdc++ on some targets broken badly if inlines hidden. Might be # deeper issue with ansi c++ library model... flags="-fno-check-new -finline" for flag in $flags ; do AC_MSG_CHECKING([whether ${CXX} supports $flag]) echo 'void f(){}' >conftest.cpp if test -z "`${CXX} $flag -c conftest.cpp 2>&1`"; then UCOMMON_FLAGS="$UCOMMON_FLAGS $flag" AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi rm -f conftest* done AC_MSG_CHECKING([whether ${CXX} supports visibility]) echo 'void f(){}' >conftest.cpp if test -z "`${CXX} -fvisibility=hidden -c conftest.cpp 2>&1`"; then UCOMMON_FLAGS="$UCOMMON_FLAGS -fvisibility=hidden" AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi rm -f conftest* AC_LANG_RESTORE AC_SUBST_DIR(includes, includedir) AC_SUBST_DIR(libs, libdir) case "$libs" in /usr/*) ;; *) UCOMMON_LINKED="-L$libs $UCOMMON_LINKED" ;; esac case "$includes" in /usr/*) ;; *) UCOMMON_FLAGS="$UCOMMON_FLAGS -I$includes" ;; esac case "$target_os" in osf*) UCOMMON_FLAGS="$UCOMMON_FLAGS -D_POSIX_C_SOURCE=1 -D_OSF_SOURCE=1 -D__USE_STD_IOSTREAM" ;; cygwin*|mingw*) UCOMMON_LINKED="$UCOMMON_LINKED -no-undefined" UCOMMON_LIBS="$UCOMMON_LIBS -no-undefined" ;; esac if test -z "$UCOMMON_SSLSTACK" ; then UCOMMON_SSLSTACK="$sslstack" ; fi OPENSSL_LIBS="" GNUTLS_LIBS="" AC_ARG_WITH(pkg-config, AC_HELP_STRING([--with-pkg-config],[enable support for pkg-config]),[ PKG_CHECK_MODULES(OPENSSL, [openssl >= $OPENSSL_REQUIRES], [], [ OPENSSL_LIBS="" AC_CHECK_HEADERS(openssl/ssl.h, [ OPENSSL_LIBS="-lssl -lcrypto -lz $OPENSSL_LINK" ]) AC_CHECK_HEADERS(openssl/fips.h) AC_CHECK_HEADERS(openssl/rsa.h) ]) PKG_CHECK_MODULES(GNUTLS, [gnutls >= 3.0.0], [], [GNUTLS_LIBS=""]) ],[ AC_CHECK_HEADERS(openssl/ssl.h, [ OPENSSL_LIBS="-lssl -lcrypto -lz $OPENSSL_LINK" ]) AC_CHECK_HEADERS(openssl/rsa.h) AC_CHECK_HEADERS(openssl/fips.h) AC_CHECK_LIB(gnutls, gnutls_init, [ GNUTLS_LIBS="-lgnutls" ]) ]) SECURE="" case "$ssl" in secure|any|detect) if test ! -z "$GNUTLS_LIBS" ; then SECURE_LIBS="$GNUTLS_LIBS" SECURE="gnutls" fi if test -z "$SECURE" ; then if test ! -z "$OPENSSL_LIBS" ; then SECURE_LIBS="$OPENSSL_LIBS" SECURE="openssl" fi fi ;; gnutls|gnu) if test ! -z "$GNUTLS_LIBS" ; then SECURE_LIBS="$GNUTLS_LIBS" SECURE="gnutls" fi ;; openssl|ssl) if test ! -z "$OPENSSL_LIBS" ; then SECURE_LIBS="$OPENSSL_LIBS" SECURE="openssl" fi ;; esac if test -z "$SECURE" ; then SECURE_LIBS="" SECURE="nossl" fi AC_MSG_CHECKING([secure library mode]) AC_MSG_RESULT([$SECURE]) SECURE_LOCAL="../$SECURE/libusecure.la $SECURE_LIBS" includes='${includedir}/ucommon' if test "$sysconfdir" = '${prefix}/etc' ; then sysconfdir="/etc" ; fi if test "$localstatedir" = '${prefix}/var' ; then localstatedir="/var" ; fi AC_CHECK_HEADER(libintl.h, [ AC_DEFINE(HAVE_LIBINTL_H, [1], [international headers]) if test "$have_gettext" = "no" ; then AC_CHECK_LIB(intl, gettext, [ AC_DEFINE(HAVE_GETTEXT, [1], [has gettext in glibc]) UCOMMON_LIBS="$UCOMMON_LIBS -lintl" ]) fi ]) if test "$prefix" = "NONE" ; then prefixdir="$ac_default_prefix" else prefixdir="$prefix" ; fi PKG_UCOMMON_LIBS="$UCOMMON_LINKED" PKG_UCOMMON_FLAGS="$UCOMMON_FLAGS" PKG_UCOMMON_INCLUDES="$UCOMMON_INCLUDES" PKG_SECURE_LIBS="$SECURE_LIBS" AC_SUBST(PKG_UCOMMON_LIBS) AC_SUBST(PKG_UCOMMON_FLAGS) AC_SUBST(PKG_UCOMMON_INCLUDES) AC_SUBST(PKG_SECURE_LIBS) AC_SUBST_DIR(CMAKE_CURRENT_SOURCE_DIR, srcdir) AC_SUBST_DIR(CMAKE_INSTALL_PREFIX, prefixdir) AC_SUBST_DIR(CMAKE_INSTALL_FULL_LIBDIR, libdir) AC_SUBST_DIR(CMAKE_INSTALL_FULL_DATADIR, datadir) AC_SUBST_DIR(CMAKE_INSTALL_FULL_INCLUDEDIR, includedir) AC_SUBST_DIR(UCOMMON_INCLUDES, includes) AC_SUBST_DIR(UCOMMON_LOCALE, localedir) AC_SUBST_DIR(UCOMMON_CFGPATH, sysconfdir) AC_SUBST_DIR(UCOMMON_VARPATH, localstatedir) AC_SUBST_DIR(UCOMMON_PREFIX, prefixdir) AC_DEFINE_UNQUOTED(UCOMMON_PREFIX, "$UCOMMON_PREFIX", [config path]) AC_DEFINE_UNQUOTED(UCOMMON_CFGPATH, "$UCOMMON_CFGPATH", [config path]) AC_DEFINE_UNQUOTED(UCOMMON_VARPATH, "$UCOMMON_VARPATH", [config path]) AC_DEFINE_UNQUOTED(UCOMMON_LOCALE, "$UCOMMON_LOCALE", [locale path]) AC_PATH_PROG(DOXYGEN, doxygen, doxygen) AC_SUBST(DOXYGEN) AC_SUBST(CHECKFLAGS) AC_SUBST(CXXFLAGS) AC_SUBST(MODULE_FLAGS) AC_SUBST(UCOMMON_INCLUDES) AC_SUBST(UCOMMON_LOCALE) AC_SUBST(UCOMMON_FLAGS) AC_SUBST(UCOMMON_LINKED) AC_SUBST(UCOMMON_LIBC) AC_SUBST(UCOMMON_LIBS) AC_SUBST(SECURE_LOCAL) AC_SUBST(SECURE_LIBS) AC_SUBST(SECURE) AC_SUBST(COMPAT) AC_SUBST(COMPAT_PC) AC_SUBST(COMPAT_CONFIG) AC_SUBST(OPENSSL_LIBS) AC_SUBST(GNUTLS_LIBS) AC_SUBST(LT_VERSION) AC_SUBST(localedir) AC_OUTPUT(Makefile corelib/Makefile commoncpp/Makefile openssl/Makefile gnutls/Makefile nossl/Makefile utils/Makefile Doxyfile inc/Makefile inc/ucommon/Makefile inc/commoncpp/Makefile test/Makefile directive commoncpp.pc ucommon.pc ucommon.spec ucommon-config commoncpp-config) commoncpp-7.0.1/corelib/000077500000000000000000000000001411242573100151315ustar00rootroot00000000000000commoncpp-7.0.1/corelib/Makefile.am000066400000000000000000000020661411242573100171710ustar00rootroot00000000000000# Copyright (C) 2006-2014 David Sugar, Tycho Softworks. # Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/access.cpp000066400000000000000000000051501411242573100170770ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/arrayref.cpp000066400000000000000000000235611411242573100174570ustar00rootroot00000000000000// Copyright (C) 2015-2020 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 { ArrayRef::Array::Array(arraytype_t arraymode, void *addr, size_t used) : Counted(addr, used), ConditionalAccess() { size_t index = 0; Counted **list = get(); head = 0; type = arraymode; if(type == ARRAY) tail = size; else tail = 0; if(!used) return; while(index < used) { list[index++] = NULL; } } void ArrayRef::Array::dealloc() { size_t index = 0; Counted **list = get(); if(!size) return; while(index < size) { Counted *object = list[index]; if(object) { object->release(); list[index] = NULL; } ++index; } size = 0; Counted::dealloc(); } size_t ArrayRef::Array::count(void) { if(head <= tail) return tail - head; return (tail + size) - head; } TypeRef::Counted *ArrayRef::Array::get(size_t index) { if(index >= size) return NULL; return (get())[index]; } TypeRef::Counted *ArrayRef::Array::remove(size_t index) { if(index >= size) return NULL; Counted *result = get(index); (get())[index] = NULL; return result; } void ArrayRef::Array::assign(size_t index, Counted *object) { if(index >= size) return; if(object) object->retain(); Counted *replace = get(index); if(replace) replace->release(); (get())[index] = object; } ArrayRef::ArrayRef() : TypeRef() { } ArrayRef::ArrayRef(arraytype_t type, size_t size) : TypeRef(create(type, size)) { } ArrayRef::ArrayRef(arraytype_t type, size_t size, TypeRef& object) : TypeRef(create(type, size)) { size_t index = 0; Array *array = polystatic_cast(ref); if(!array || !array->size) return; while(index < array->size) { array->assign(index++, object.ref); } } ArrayRef::ArrayRef(const ArrayRef& copy) : TypeRef(copy) { } void ArrayRef::reset(Counted *object) { size_t index = 0; size_t max; Array *array = polystatic_cast(ref); if(!array || !array->size || !object) return; switch(array->type) { case ARRAY: max = array->size; break; case FALLBACK: max = 1; break; default: max = 0; } array->lock(); array->head = 0; array->tail = max; while(index < max) { array->assign(index++, object); } array->signal(); array->unlock(); } void ArrayRef::pop(void) { bool popped = false; Array *array = polystatic_cast(ref); if(!array || !array->size) return; array->lock(); switch(array->type) { case STACK: if(array->head != array->tail) { if(array->tail == 0) array->tail = array->size; --array->tail; array->assign(array->tail, NULL); popped = true; } break; case FALLBACK: if(array->count() == 1) break; case QUEUE: if(array->head != array->tail) { array->assign(array->head, NULL); if(++array->head >= array->size) array->head = 0; popped = true; } break; default: break; } if(popped) array->signal(); array->unlock(); } void ArrayRef::reset(TypeRef& var) { reset(var.ref); } void ArrayRef::clear(void) { reset(nullptr); } ArrayRef::Array *ArrayRef::create(arraytype_t mode, size_t size) { if(!size) return NULL; size_t s = sizeof(Array) + (size * sizeof(Counted *)); caddr_t p = auto_release.allocate(s); return new(mem(p)) Array(mode, p, size); } bool ArrayRef::push(const TypeRef& object, timeout_t timeout) { Array *array = polystatic_cast(ref); if(!array || array->type == ARRAY) return false; array->lock(); while(array->count() >= (array->size - 1)) { if(!array->waitSignal(timeout)) { array->unlock(); return false; } } array->assign(array->tail, object.ref); if(++array->tail >= array->size) array->tail = 0; array->broadcast(); array->unlock(); return true; } size_t ArrayRef::count() { size_t result = 0; Array *array = polystatic_cast(ref); if(array) { array->lock(); result = array->count(); array->unlock(); } return result; } void ArrayRef::push(const TypeRef& object) { Array *array = polystatic_cast(ref); if(!array || array->type == ARRAY) return; array->lock(); while(array->count() >= (array->size - 1)) { array->waitSignal(); } array->assign(array->tail, object.ref); if(++array->tail >= array->size) array->tail = 0; array->broadcast(); array->unlock(); } void ArrayRef::pull(TypeRef& object, timeout_t timeout) { object.clear(); Array *array = polystatic_cast(ref); if(!array || array->type == ARRAY) { return; } array->lock(); for(;;) { if(array->head != array->tail) { Counted *value = NULL; switch(array->type) { case STACK: if(array->tail == 0) array->tail = array->size; --array->tail; value = array->remove(array->tail); break; case FALLBACK: if(array->count() == 1) { value = array->get(array->head); break; } case QUEUE: value = array->remove(array->head); if(++array->head == array->size) array->head = 0; break; default: break; } if(value) { array->signal(); array->unlock(); object.ref = value; return; } } if(!array->waitBroadcast(timeout)) { array->unlock(); object.clear(); return; } } } void ArrayRef::pull(TypeRef& object) { object.clear(); Array *array = polystatic_cast(ref); if(!array || array->type == ARRAY) { return; } array->lock(); for(;;) { if(array->head != array->tail) { Counted *value = NULL; switch(array->type) { case STACK: if(array->tail == 0) array->tail = array->size; --array->tail; value = array->remove(array->tail); break; case FALLBACK: if(array->count() == 1) { value = array->get(array->head); break; } case QUEUE: value = array->remove(array->head); if(++array->head == array->size) array->head = 0; break; default: break; } if(value) { array->signal(); array->unlock(); object.ref = value; return; } } array->waitBroadcast(); } } void ArrayRef::assign(size_t index, TypeRef& t) { Array *array = polystatic_cast(ref); if(!array || index >= array->size) return; assert(array->type == ARRAY); Counted *obj = t.ref; array->lock(); index += array->head; if(index >= array->size) index -= array->size; array->assign(index, obj); array->unlock(); } void ArrayRef::resize(size_t size) { Array *current = polystatic_cast(ref); size_t index = 0; if(current) { Array *array = create(current->type, size); current->lock(); switch(array->type) { case ARRAY: while(index < size && index < current->size) { array->assign(index, current->get(index)); ++index; } array->tail = size; break; default: array->head = array->tail = 0; break; } current->unlock(); TypeRef::set(array); } } void ArrayRef::realloc(size_t size) { Array *current = polystatic_cast(ref); if(current) TypeRef::set(create(current->type, size)); } bool ArrayRef::is(size_t index) { if(get(index)) return true; return false; } TypeRef::Counted *ArrayRef::get(size_t index) { Array *array = polystatic_cast(ref); if(!array) return NULL; if(index >= array->size || array->head == array->tail) { return NULL; } array->lock(); index += array->head; if(array->head <= array->tail && index >= array->tail) { array->unlock(); return NULL; } if(index >= array->size) index -= array->size; if(index >= array->tail) { array->unlock(); return NULL; } Counted *object = array->get(index); array->unlock(); return object; } } // namespace commoncpp-7.0.1/corelib/atomic.cpp000066400000000000000000000243401411242573100171140ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 #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 commoncpp-7.0.1/corelib/condition.cpp000066400000000000000000000317241411242573100176320ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/counter.cpp000066400000000000000000000036221411242573100173170ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/cpr.cpp000066400000000000000000000141741411242573100164300ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/datetime.cpp000066400000000000000000000452571411242573100174460ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/fsys.cpp000066400000000000000000001065411411242573100166300ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/keydata.cpp000066400000000000000000000244761411242573100172740ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/linked.cpp000066400000000000000000000436551411242573100171200ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 { LinkedObject::LinkedObject(LinkedObject **root) { assert(root != nullptr); enlist(root); } LinkedObject::~LinkedObject() { } void LinkedObject::purge(LinkedObject *root) { LinkedObject *after; assert(root != nullptr); while(root) { after = root->Next; root->release(); root = after; } } bool LinkedObject::is_member(LinkedObject *list) const { assert(list != nullptr); while(list) { if(list == this) return true; list = list->Next; } return false; } void LinkedObject::enlist(LinkedObject **root) { assert(root != nullptr); Next = *root; *root = this; } void LinkedObject::delist(LinkedObject **root) { assert(root != nullptr); LinkedObject *prior = nullptr, *node = *root; while(node && node != this) { prior = node; node = node->Next; } if(!node) return; if(!prior) *root = Next; else prior->Next = Next; } void ReusableObject::release(void) { Next = nullptr; } NamedObject::NamedObject() : OrderedObject() { Id = nullptr; } NamedObject::NamedObject(OrderedIndex *root, char *nid) : OrderedObject() { assert(root != nullptr); assert(nid != nullptr && *nid != 0); NamedObject *node = static_cast(root->head), *prior = nullptr; while(node) { if(node->equal(nid)) { if(prior) prior->Next = node->getNext(); else root->head = node->getNext(); node->release(); break; } prior = node; node = node->getNext(); } Next = nullptr; Id = nid; if(!root->head) root->head = this; if(!root->tail) root->tail = this; else root->tail->Next = this; } // One thing to watch out for is that the id is freed in the destructor. // This means that you should use a dup'd string for your nid. Otherwise // you will need to set it to NULL before destroying the object. NamedObject::NamedObject(NamedObject **root, char *nid, unsigned max) : OrderedObject() { assert(root != nullptr); assert(nid != nullptr && *nid != 0); assert(max > 0); Id = nullptr; add(root, nid, max); } void NamedObject::add(NamedObject **root, char *nid, unsigned max) { assert(root != nullptr); assert(nid != nullptr && *nid != 0); assert(max > 0); clearId(); NamedObject *node, *prior = nullptr; if(max < 2) max = 0; else max = keyindex(nid, max); node = root[max]; while(node) { if(node && node->equal(nid)) { if(prior) { prior->Next = this; Next = node->Next; } else root[max] = node->getNext(); node->release(); break; } prior = node; node = node->getNext(); } if(!node) { Next = root[max]; root[max] = this; } Id = nid; } void NamedObject::clearId(void) { if(Id) { free(Id); Id = nullptr; } } NamedObject::~NamedObject() { // this assumes the id is a malloc'd or strdup'd string. // maybe overridden if virtual... clearId(); } // Linked objects are assumed to be freeable if they are released. The retain // simply marks it into a self reference state which can never otherwise happen // naturally. This is used to mark avoid freeing during release. void LinkedObject::retain(void) { Next = this; } void LinkedObject::release(void) { if(Next != this) { Next = this; delete this; } } LinkedObject *LinkedObject::getIndexed(LinkedObject *root, unsigned index) { while(index-- && root != nullptr) root = root->Next; return root; } unsigned LinkedObject::count(const LinkedObject *root) { assert(root != nullptr); unsigned c = 0; while(root) { ++c; root = root->Next; } return c; } unsigned NamedObject::keyindex(const char *id, unsigned max) { assert(id != nullptr && *id != 0); assert(max > 1); unsigned val = 0; while(*id) val = (val << 1) ^ (*(id++) & 0x1f); return val % max; } int NamedObject::compare(const char *cid) const { assert(cid != nullptr && *cid != 0); #ifdef HAVE_STRCOLL return strcoll(Id, cid); #else return strcmp(Id, cid); #endif } extern "C" { static int ncompare(const void *o1, const void *o2) { assert(o1 != nullptr); assert(o2 != nullptr); const NamedObject * const *n1 = static_cast(o1); const NamedObject * const*n2 = static_cast(o2); return ((*n1)->compare((*n2)->getId())); } } NamedObject **NamedObject::sort(NamedObject **list, size_t size) { assert(list != nullptr); if(!size) { while(list[size]) ++size; } qsort(static_cast(list), size, sizeof(NamedObject *), &ncompare); return list; } NamedObject **NamedObject::index(NamedObject **idx, unsigned max) { assert(idx != nullptr); assert(max > 0); NamedObject **op = new NamedObject *[count(idx, max) + 1]; unsigned pos = 0; NamedObject *node = skip(idx, nullptr, max); while(node) { op[pos++] = node; node = skip(idx, node, max); } op[pos] = nullptr; return op; } NamedObject *NamedObject::skip(NamedObject **idx, NamedObject *rec, unsigned max) { assert(idx != nullptr); assert(max > 0); unsigned key = 0; if(rec && !rec->Next) key = keyindex(rec->Id, max) + 1; if(!rec || !rec->Next) { while(key < max && !idx[key]) ++key; if(key >= max) return nullptr; return idx[key]; } return rec->getNext(); } void NamedObject::purge(NamedObject **idx, unsigned max) { assert(idx != nullptr); assert(max > 0); LinkedObject *root; if(max < 2) max = 0; while(max--) { root = idx[max]; LinkedObject::purge(root); } } unsigned NamedObject::count(NamedObject **idx, unsigned max) { assert(idx != nullptr); assert(max > 0); unsigned count = 0; LinkedObject *node; if(max < 2) max = 1; while(max--) { node = idx[max]; while(node) { ++count; node = node->Next; } } return count; } NamedObject *NamedObject::remove(NamedObject **idx, const char *id, unsigned max) { assert(idx != nullptr); assert(id != nullptr && *id != 0); assert(max > 0); if(max < 2) return remove(idx, id); return remove(&idx[keyindex(id, max)], id); } NamedObject *NamedObject::map(NamedObject **idx, const char *id, unsigned max) { assert(idx != nullptr); assert(id != nullptr && *id != 0); assert(max > 0); if(max < 2) return find(*idx, id); return find(idx[keyindex(id, max)], id); } NamedObject *NamedObject::find(NamedObject *root, const char *id) { assert(id != nullptr && *id != 0); while(root) { if(root->equal(id)) break; root = root->getNext(); } return root; } NamedObject *NamedObject::remove(NamedObject **root, const char *id) { assert(id != nullptr && *id != 0); assert(root != nullptr); NamedObject *prior = nullptr; NamedObject *node = *root; while(node) { if(node->equal(id)) break; prior = node; node = node->getNext(); } if(!node) return nullptr; if(prior == nullptr) *root = node->getNext(); else prior->Next = node->getNext(); return node; } // Like in NamedObject, the nid that is used will be deleted by the // destructor through calling purge. Hence it should be passed from // a malloc'd or strdup'd string. NamedTree::NamedTree(char *nid) : NamedObject(), Child() { Id = nid; Parent = nullptr; } NamedTree::NamedTree(const NamedTree& source) { Id = source.Id; Parent = nullptr; Child = source.Child; } NamedTree::NamedTree(NamedTree *p, char *nid) : NamedObject(), Child() { assert(p != nullptr); assert(nid != nullptr && *nid != 0); enlistTail(&p->Child); Id = nid; Parent = p; } NamedTree::~NamedTree() { Id = nullptr; purge(); } NamedTree *NamedTree::getChild(const char *tid) const { assert(tid != nullptr && *tid != 0); linked_pointer node = Child.begin(); while(node) { if(eq(node->Id, tid)) return *node; node.next(); } return nullptr; } void NamedTree::relistTail(NamedTree *trunk) { // if moving to same place, just return... if(Parent == trunk) return; if(Parent) delist(&Parent->Child); Parent = trunk; if(Parent) enlistTail(&Parent->Child); } void NamedTree::relistHead(NamedTree *trunk) { if(Parent == trunk) return; if(Parent) delist(&Parent->Child); Parent = trunk; if(Parent) enlistHead(&Parent->Child); } NamedTree *NamedTree::path(const char *tid) const { assert(tid != nullptr && *tid != 0); const char *np; char buf[65]; char *ep; NamedTree *node = const_cast(this); if(!tid || !*tid) return const_cast(this); while(*tid == '.') { if(!node->Parent) return nullptr; node = node->Parent; ++tid; } while(tid && *tid && node) { String::set(buf, sizeof(buf), tid); ep = strchr(buf, '.'); if(ep) *ep = 0; np = strchr(tid, '.'); if(np) tid = ++np; else tid = nullptr; node = node->getChild(buf); } return node; } NamedTree *NamedTree::getLeaf(const char *tid) const { assert(tid != nullptr && *tid != 0); linked_pointer node = Child.begin(); while(node) { if(node->is_leaf() && eq(node->Id, tid)) return *node; node.next(); } return nullptr; } NamedTree *NamedTree::leaf(const char *tid) const { assert(tid != nullptr && *tid != 0); linked_pointer node = Child.begin(); NamedTree *obj; while(node) { if(node->is_leaf() && eq(node->Id, tid)) return *node; obj = nullptr; if(!node->is_leaf()) obj = node->leaf(tid); if(obj) return obj; node.next(); } return nullptr; } NamedTree *NamedTree::find(const char *tid) const { assert(tid != nullptr && *tid != 0); linked_pointer node = Child.begin(); NamedTree *obj; while(node) { if(!node->is_leaf()) { if(eq(node->Id, tid)) return *node; obj = node->find(tid); if(obj) return obj; } node.next(); } return nullptr; } void NamedTree::setId(char *nid) { assert(nid != nullptr && *nid != 0); Id = nid; } // If you remove the tree node, the id is NULL'd also. This keeps the // destructor from freeing it. void NamedTree::remove(void) { if(Parent) delist(&Parent->Child); Id = nullptr; } void NamedTree::purge(void) { linked_pointer node = Child.begin(); NamedTree *obj; if(Parent) delist(&Parent->Child); while(node) { obj = *node; if (!obj) break; obj->Parent = nullptr; // save processing node = obj->getNext(); delete obj; } // this assumes the object id is a malloc'd/strdup string. // may be overridden if virtual... clearId(); } LinkedObject::LinkedObject() { Next = nullptr; } LinkedObject::LinkedObject(const LinkedObject& from) { Next = nullptr; } OrderedObject::OrderedObject() : LinkedObject() { } OrderedObject::OrderedObject(const OrderedObject& from) : LinkedObject() { } OrderedObject::OrderedObject(OrderedIndex *root) : LinkedObject() { assert(root != nullptr); Next = nullptr; enlistTail(root); } void OrderedObject::delist(OrderedIndex *root) { assert(root != nullptr); OrderedObject *prior = nullptr, *node; node = root->head; while(node && node != this) { prior = node; node = node->getNext(); } if(!node) return; if(!prior) root->head = getNext(); else prior->Next = Next; if(this == root->tail) root->tail = prior; } void OrderedObject::enlist(OrderedIndex *root) { assert(root != nullptr); Next = nullptr; enlistTail(root); } void OrderedObject::enlistTail(OrderedIndex *root) { assert(root != nullptr); if(root->head == nullptr) root->head = this; else if(root->tail) root->tail->Next = this; root->tail = this; } void OrderedObject::enlistHead(OrderedIndex *root) { assert(root != nullptr); Next = nullptr; if(root->tail == nullptr) root->tail = this; else if(root->head) Next = root->head; root->head = this; } DLinkedObject::DLinkedObject() { Root = nullptr; Prev = nullptr; Next = nullptr; } DLinkedObject::DLinkedObject(const DLinkedObject& from) { Root = nullptr; Prev = nullptr; Next = nullptr; } DLinkedObject::DLinkedObject(OrderedIndex *r) { Root = nullptr; Next = Prev = nullptr; if(r) enlist(r); } void DLinkedObject::enlist(OrderedIndex *r) { assert(r != nullptr); enlistTail(r); } void DLinkedObject::insert(DLinkedObject *o) { assert(o != nullptr); insertTail(o); } void DLinkedObject::insertHead(DLinkedObject *o) { assert(o != nullptr); if(o->Root) o->delist(); if(Prev) { o->Next = this; o->Prev = Prev; } else { Root->head = o; o->Prev = nullptr; } o->Root = Root; o->Next = this; Prev = o; } void DLinkedObject::insertTail(DLinkedObject *o) { assert(o != nullptr); if(o->Root) o->delist(); if(Next) { o->Prev = this; o->Next = Next; } else { Root->tail = o; o->Next = nullptr; } o->Root = Root; o->Prev = this; Next = o; } void DLinkedObject::enlistHead(OrderedIndex *r) { assert(r != nullptr); if(Root) delist(); Root = r; Prev = nullptr; Next = nullptr; if(!Root->tail) { Root->tail = Root->head = static_cast(this); return; } Next = static_cast(Root->head); ((DLinkedObject*)Next)->Prev = this; Root->head = static_cast(this); } void DLinkedObject::enlistTail(OrderedIndex *r) { assert(r != nullptr); if(Root) delist(); Root = r; Next = Prev = nullptr; if(!Root->head) { Root->head = Root->tail = static_cast(this); return; } Prev = static_cast(Root->tail); Prev->Next = this; Root->tail = static_cast(this); } void DLinkedObject::delist(void) { if(!Root) return; if(Prev) Prev->Next = Next; else if(Root->head == static_cast(this)) Root->head = static_cast(Next); if(Next) (static_cast(Next))->Prev = Prev; else if(Root->tail == static_cast(this)) Root->tail = static_cast(Prev); Root = nullptr; Next = Prev = nullptr; } DLinkedObject::~DLinkedObject() { delist(); } OrderedIndex::OrderedIndex() { head = tail = nullptr; } OrderedIndex::~OrderedIndex() { head = tail = nullptr; } void OrderedIndex::copy(const OrderedIndex& source) { head = source.head; tail = source.tail; } void OrderedIndex::operator*=(OrderedObject *object) { assert(object != nullptr); object->enlist(this); } void OrderedIndex::add(OrderedObject *object) { assert(object != nullptr); object->enlist(this); } LinkedObject *OrderedIndex::get(void) { LinkedObject *node; if(!head) return nullptr; node = head; head = static_cast(node->getNext()); if(!head) tail = nullptr; return static_cast(node); } void OrderedIndex::purge(void) { if(head) { LinkedObject::purge((LinkedObject *)head); head = tail = nullptr; } } void OrderedIndex::reset(void) { head = tail = nullptr; } void OrderedIndex::lock_index(void) { } void OrderedIndex::unlock_index(void) { } LinkedObject **OrderedIndex::index(void) const { LinkedObject **op = new LinkedObject *[count() + 1]; LinkedObject *node; unsigned idx = 0; node = head; while(node) { op[idx++] = node; node = node->Next; } op[idx] = nullptr; return op; } LinkedObject *OrderedIndex::find(unsigned index) const { unsigned count = 0; LinkedObject *node; node = head; while(node && ++count < index) node = node->Next; return node; } unsigned OrderedIndex::count(void) const { unsigned count = 0; LinkedObject *node; node = head; while(node) { node = node->Next; ++count; } return count; } } // namespace ucommon commoncpp-7.0.1/corelib/mapped.cpp000066400000000000000000000313241411242573100171060ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/mapref.cpp000066400000000000000000000200071411242573100171060ustar00rootroot00000000000000// Copyright (C) 2015-2020 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 { MapRef::Index::Index() : LinkedObject() { key = value = NULL; } MapRef::Index::Index(LinkedObject **origin) : LinkedObject(origin) { key = value = NULL; } MapRef::Map::Map(void *addr, size_t indexes, size_t paging) : Counted(addr, indexes), pool(paging) { size_t index = 0; LinkedObject **list = get(); free = last = NULL; count = alloc = 0; while(index < indexes) { list[index++] = NULL; } } MapRef::Index *MapRef::Map::create(size_t key) { LinkedObject **list = get(); caddr_t p = (caddr_t)(free); if(free) free = free->getNext(); else { ++alloc; p = (caddr_t)pool.alloc(sizeof(Index)); } ++count; return new(p) Index(&list[key % size]); } MapRef::Index *MapRef::Map::append() { LinkedObject **list = get(); caddr_t p = (caddr_t)(free); if(free) free = free->getNext(); else { ++alloc; p = (caddr_t)pool.alloc(sizeof(Index)); } ++count; Index *ip = new(p) Index(); if(last) { Index *lp = static_cast(last); lp->Next = ip; } else list[0] = ip; last = ip; ip->Next = NULL; return ip; } void MapRef::Map::remove(Index *index, size_t path) { if(!index) return; if(index->key) index->key->release(); if(index->value) index->value->release(); LinkedObject **root = get(); root = &root[path % size]; --count; if(last && index == last) { last = *(root); if(last == index) last = NULL; else { while(last && last->getNext() != index) { last = last->getNext(); } } } index->delist(root); index->enlist(&free); } LinkedObject *MapRef::Map::access(size_t key) { lock.access(); return (get())[key % size]; } LinkedObject *MapRef::Map::modify(size_t key) { lock.modify(); return (get())[key % size]; } void MapRef::Map::dealloc() { size_t index = 0; LinkedObject **list = get(); linked_pointer ip; if(!size) return; while(index < size) { ip = list[index]; while(ip) { if(ip->key) ip->key->release(); if(ip->value) ip->value->release(); ip.next(); } ++index; } size = 0; free = last = NULL; pool.purge(); Counted::dealloc(); } MapRef::Instance::Instance(Map *vmap) { if(!vmap) return; map = vmap; map->retain(); map->lock.access(); rewind(); } MapRef::Instance::Instance(MapRef& from) { map = static_cast(from.ref); if(!map) return; map->retain(); map->lock.access(); rewind(); } MapRef::Instance::Instance() { map = NULL; index = NULL; path = 0; } MapRef::Instance::Instance(const Instance& copy) { map = copy.map; index = copy.index; path = copy.path; if(!map) return; map->retain(); map->lock.access(); } MapRef::Instance::~Instance() { drop(); } void MapRef::Instance::drop() { if(!map) return; map->lock.release(); map->release(); map = NULL; index = NULL; path = 0; } void MapRef::Instance::assign(const Instance& copy) { drop(); map = copy.map; index = copy.index; path = copy.path; if(!map) return; map->retain(); map->lock.access(); } void MapRef::Instance::assign(MapRef& from) { drop(); map = static_cast(from.ref); if(!map) return; map->retain(); map->lock.access(); rewind(); } void MapRef::Instance::rewind() { if(!map) return; path = 0; index = (map->get())[0]; if(!index) next(); } bool MapRef::Instance::top() { if(!map) return false; if(path > 0) return false; if(index != (map->get())[0]) return false; return true; } TypeRef::Counted *MapRef::Instance::key() { if(!index) return NULL; return (static_cast(index))->key; } TypeRef::Counted *MapRef::Instance::value() { if(!index) return NULL; return (static_cast(index))->value; } bool MapRef::Instance::eol() { if(!map) return false; if(path < map->size) return false; return true; } bool MapRef::Instance::next() { if(!map) return false; if(index) index = index->getNext(); if(index) return true; while(++path < map->size) { index = (map->get())[path]; if(index) return true; } return false; } MapRef::MapRef() : TypeRef() { } MapRef::MapRef(const MapRef& copy) : TypeRef(copy) { } MapRef::MapRef(size_t indexes, size_t paging) : TypeRef(create(indexes, paging)) { } size_t MapRef::used() { Map *m = polydynamic_cast(ref); if(!m) return 0; return m->alloc; } size_t MapRef::count() { Map *m = polydynamic_cast(ref); if(!m) return 0; return m->count; } void MapRef::remove(Index *ind, size_t path) { Map *m = polydynamic_cast(ref); if(!m) return; m->remove(ind, path); } MapRef::Map *MapRef::create(size_t indexes, size_t paging) { if(!indexes) return NULL; size_t s = sizeof(Map) + (indexes * sizeof(Index *)); caddr_t p = auto_release.allocate(s); return new(mem(p)) Map(p, indexes, paging); } void MapRef::update(Index *ind, TypeRef& value) { if(!ind) return; if(ind->value) ind->value->release(); ind->value = value.ref; if(ind->value) ind->value->retain(); } void MapRef::append(TypeRef& value) { Map *m = polydynamic_cast(ref); if(!m || !m->size) return; m->lock.modify(); Index *ind = m->append(); if(!ind) { m->lock.commit(); return; } ind->key = NULL; ind->value = value.ref; if(ind->value) ind->value->retain(); m->lock.commit(); } void MapRef::add(size_t keypath, TypeRef& key, TypeRef& value) { Map *m = polydynamic_cast(ref); if(!m || !m->size) return; Index *ind = m->create(keypath); if(!ind) { return; } ind->key = key.ref; ind->value = value.ref; if(ind->key) ind->key->retain(); if(ind->value) ind->value->retain(); } linked_pointer MapRef::access(size_t key) { linked_pointer ip; Map *m = polydynamic_cast(ref); if(!m || !m->size) return ip; m->retain(); ip = m->access(key); return ip; } linked_pointer MapRef::modify(size_t key) { linked_pointer ip; Map *m = polydynamic_cast(ref); if(!m || !m->size) return ip; m->retain(); ip = m->modify(key); return ip; } void MapRef::commit() { Map *m = polydynamic_cast(ref); if(!m || !m->size) return; m->lock.commit(); m->release(); } void MapRef::release() { Map *m = polydynamic_cast(ref); if(!m || !m->size) return; m->lock.release(); m->release(); } size_t MapRef::index(size_t& key, const uint8_t *addr, size_t len) { while(len-- && addr) { key ^= (key << 3) ^ *addr; ++addr; } return key; } } // namespace commoncpp-7.0.1/corelib/memory.cpp000066400000000000000000000430061411242573100171500ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 #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 commoncpp-7.0.1/corelib/numbers.cpp000066400000000000000000000064561411242573100173230ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/object.cpp000066400000000000000000000057701411242573100171140ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/protocols.cpp000066400000000000000000000101161411242573100176600ustar00rootroot00000000000000// Copyright (C) 1999-2005 Open Source Telecom Corporation. // Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/regex.cpp000066400000000000000000000121611411242573100167500ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/reuse.cpp000066400000000000000000000106031411242573100167600ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/shared.cpp000066400000000000000000000056011411242573100171050ustar00rootroot00000000000000// Copyright (C) 2015-2020 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 commoncpp-7.0.1/corelib/shell.cpp000066400000000000000000001560371411242573100167600ustar00rootroot00000000000000// Copyright (C) 2006-2014 David Sugar, Tycho Softworks. // Copyright (C) 2015-2020 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