32 Commits
Author SHA1 Message Date
Spine 4a5687b607 redesign announce jitter to better spread the load after startup 2024-02-11 15:39:22 +01:00
Spine f80f37c025 Merge branch 'torrent-info' into 'master'
output user report and info_torrent as JSON

See merge request tracker/ocelot!7
2024-02-10 15:26:59 +00:00
Spine 51c5f64a8e output user report and info_torrent as JSON 2024-01-28 12:38:25 +01:00
Spider 59a91200fa Update docker base image 2023-10-14 20:57:34 +02:00
sheepish 665e8b7a24 track queue sizes in stats 2023-10-14 20:25:15 +02:00
sheepish 7efb98654a sleep if api returns error 2023-10-14 20:25:15 +02:00
sheepish c4153d7585 fix queue worker threads getting stuck if connection fails 2023-10-14 20:25:15 +02:00
sheepish f42c7cdf47 add grafana dashboard 2023-10-14 20:19:50 +02:00
sheepish e5d20d7851 add prometheus-compatible stats reporting 2023-10-14 20:19:46 +02:00
itismadness cd1b031d4f Add curl to Dockerfile for downstream health checks
(cherry picked from commit fac0fd1686)
2023-10-14 20:19:32 +02:00
itismadness d2bae2622a Ignore build output files for docker
(cherry picked from commit 23e5b92b2a)
2023-10-14 20:19:29 +02:00
itismadness ad9fb66efa add image.source label to Dockerfile
(cherry picked from commit fc56c7a35a)
2023-10-14 20:19:25 +02:00
itismadness b248a4c766 improve dev workflow
(cherry picked from commit 50a08a2b66)
2023-10-14 20:19:14 +02:00
undertheironbridge e04b30366e Small CMakeLists.txt cleanup (#19)
Co-authored-by: strangeways <[email protected]>
(cherry picked from commit 5412bee85a)
2023-10-14 20:18:46 +02:00
itismadness 38ac1af7a2 use chrono to sleep in threads
(cherry picked from commit 3a430a9a1c)
2023-10-14 20:16:58 +02:00
Spine 9c2051ef71 change xbt_snatched insert to allow a primary key to be added 2020-04-22 01:24:02 +01:00
itismadness febde1daf7 use string empty method for checking empty strings 2020-04-22 01:23:52 +01:00
itismadness 465c23ad5d should have been 2.0.0 release 2019-10-22 23:43:11 +01:00
itismadness 023b33c5a5 1.2.0 release 2019-10-22 23:34:58 +01:00
Spine 8964322da5 write activity into leech stats tables (#2) 2019-10-20 10:12:42 +00:00
itismadness 4268d19188 Commit CMakeLists.txt and renamed CMake find files 2019-06-16 23:09:37 -01:00
itismadness 99f58dc0d9 Add site_service config option to allow setting gazelle port 2019-06-14 07:19:43 +08:00
Hierra Strunger 6d8f859455 Create ocelot.service (#14)
Systemd init file for ocelot to put on /lib/systemd/system/
2019-06-03 07:25:07 -04:00
itismadness 861ccf7eae Add changelog line for 1.2, update README 2019-05-26 17:11:21 -04:00
itismadness 3b2d8253fb Remove Vagrantfile in favor of Dockerfile 2019-05-26 17:02:53 -04:00
itismadness a7d8e5744f Migrate ocelot to build using cmake, add support for jemalloc 2019-05-26 17:00:53 -04:00
SebbaGerra d1a88b1ae1 Some changes to build on FreeBSD (#12)
* Update events.h

* Update ocelot.h

* Update schedule.h

* Update README.md
2018-11-24 08:44:28 -05:00
itismadness 8ed24eb529 Update for v1.1 2018-11-05 20:35:10 -05:00
it is madness 269d395c70 Update README.md 2018-04-10 12:41:40 +00:00
itismadness ea91e111a1 finally get around to pushing fixes for typos and compile errors 2018-03-01 09:08:34 -05:00
itismadness 07da713209 add logging (console and file) and a daemon mode 2017-11-02 20:15:38 -04:00
itismadness 7f577b53a4 Reorganize Ocelot source code into src/ directory 2017-10-30 23:41:32 -04:00
109 changed files with 15820 additions and 16651 deletions

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
.vscode/
build/
/ocelot
+20
View File
@@ -1 +1,21 @@
.idea/
.vscode/
.vagrant/
*.tar.*
MakeFile.in
/configure
/config.*
cmake-build-debug/
autom4te.cache/
*.o
Makefile
.deps/
src/ocelot
/ocelot.conf
build/
/ocelot
CMakeFiles/
CMakeCache.txt
cmake_install.cmake
*.cbp
.DS_Store
+39
View File
@@ -1,3 +1,42 @@
-- 2.1.0 (2024-02-11)
FEATURES
* announce jitter is now a uniform distribution and can be modified on the fly
-- 2.0.1 (2024-02-10)
BREAKING
* API torrent endpoint output changed to JSON
* API user endpoint shows more information about a user in JSON format
FEATURES
* Mysql port may be specified in configuration file
* API stats report contains Ocelot version
* Queue sizes are reported in stats
* Sleep if Gazelle API is down
* Handle DB connection problems gracefully
* Add Prometheus and Grafana support
BUILD
* Docker image based on Bookworm
-- 2.0.0 (2019-10-22)
BREAKING
* Write leech stats into their own dedicated tables (users_leech_stats, torrents_leech_stats)
* Move to CMake for building project instead of autotools
FEATURES
* Add support for building against jemalloc (http://jemalloc.net/)
* Add systemd service file for ocelot (thanks @HierraStrunger)
Add site_service config option to set the service/port ocelot runs on (defaults to "http")
BUGFIXES
* Fix FreeBSD support (thanks @HierraStrunger)
BUILD
* Drop Vagranfile in favor of only supporting the Dockerfile
-- 1.1 (2018-10-29)
Move to spdlog (https://github.com/gabime/spdlog)to handle logging instead of cout
spdlog is vendored under src/, currently using v0.13.0
Add logging directive to config to configure how Ocelot logs and where it logs
Add daemon switch (--daemon, -d) to run Ocelot as a daemon
Move source code into src/ directory
Add Vagrantfile and Dockerfile for running Ocelot
-- 1.0 (2015-01-26)
NOTE: This version requires the following database change:
ALTER TABLE xbt_files_users DROP PRIMARY KEY, ADD PRIMARY KEY (peer_id,fid,uid)
+48
View File
@@ -0,0 +1,48 @@
# From: https://raw.githubusercontent.com/STEllAR-GROUP/hpx/master/cmake/FindJemalloc.cmake
# Copyright (c) 2014 Thomas Heller
# Copyright (c) 2007-2012 Hartmut Kaiser
# Copyright (c) 2010-2011 Matt Anderson
# Copyright (c) 2011 Bryce Lelbach
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
find_package(PkgConfig)
pkg_check_modules(PC_JEMALLOC QUIET libjemalloc)
find_path(JEMALLOC_INCLUDE_DIR jemalloc/jemalloc.h
HINTS
${JEMALLOC_ROOT} ENV JEMALLOC_ROOT
${PC_JEMALLOC_MINIMAL_INCLUDEDIR}
${PC_JEMALLOC_MINIMAL_INCLUDE_DIRS}
${PC_JEMALLOC_INCLUDEDIR}
${PC_JEMALLOC_INCLUDE_DIRS}
PATH_SUFFIXES include)
find_library(JEMALLOC_LIBRARY NAMES jemalloc libjemalloc
HINTS
${JEMALLOC_ROOT} ENV JEMALLOC_ROOT
${PC_JEMALLOC_MINIMAL_LIBDIR}
${PC_JEMALLOC_MINIMAL_LIBRARY_DIRS}
${PC_JEMALLOC_LIBDIR}
${PC_JEMALLOC_LIBRARY_DIRS}
PATH_SUFFIXES lib lib64)
if(JEMALLOC_LIBRARY AND JEMALLOC_INCLUDE_DIR)
set(JEMALLOC_FOUND TRUE)
message(STATUS "Found jemalloc: ${JEMALLOC_LIBRARY}")
find_package_handle_standard_args(Jemalloc DEFAULT_MSG
JEMALLOC_LIBRARY JEMALLOC_INCLUDE_DIR)
get_property(_type CACHE JEMALLOC_ROOT PROPERTY TYPE)
if(_type)
set_property(CACHE JEMALLOC_ROOT PROPERTY ADVANCED 1)
if("x${_type}" STREQUAL "xUNINITIALIZED")
set_property(CACHE JEMALLOC_ROOT PROPERTY TYPE PATH)
endif()
endif()
else()
set(JEMALLOC_FOUND FALSE)
endif()
mark_as_advanced(JEMALLOC_ROOT JEMALLOC_LIBRARY JEMALLOC_INCLUDE_DIR)
+38
View File
@@ -0,0 +1,38 @@
# - Try to find libev
# Once done this will define
# LIBEV_FOUND - System has libev
# LIBEV_INCLUDE_DIRS - The libev include directories
# LIBEV_LIBRARIES - The libraries needed to use libev
find_path(LIBEV_INCLUDE_DIR
NAMES ev.h
)
find_library(LIBEV_LIBRARY
NAMES ev
)
if(LIBEV_INCLUDE_DIR)
file(STRINGS "${LIBEV_INCLUDE_DIR}/ev.h"
LIBEV_VERSION_MAJOR REGEX "^#define[ \t]+EV_VERSION_MAJOR[ \t]+[0-9]+")
file(STRINGS "${LIBEV_INCLUDE_DIR}/ev.h"
LIBEV_VERSION_MINOR REGEX "^#define[ \t]+EV_VERSION_MINOR[ \t]+[0-9]+")
string(REGEX REPLACE "[^0-9]+" "" LIBEV_VERSION_MAJOR "${LIBEV_VERSION_MAJOR}")
string(REGEX REPLACE "[^0-9]+" "" LIBEV_VERSION_MINOR "${LIBEV_VERSION_MINOR}")
set(LIBEV_VERSION "${LIBEV_VERSION_MAJOR}.${LIBEV_VERSION_MINOR}")
unset(LIBEV_VERSION_MINOR)
unset(LIBEV_VERSION_MAJOR)
endif()
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBEV_FOUND to TRUE
# if all listed variables are TRUE and the requested version matches.
find_package_handle_standard_args(Libev REQUIRED_VARS
LIBEV_LIBRARY LIBEV_INCLUDE_DIR
VERSION_VAR LIBEV_VERSION)
if(LIBEV_FOUND)
set(LIBEV_LIBRARIES ${LIBEV_LIBRARY})
set(LIBEV_INCLUDE_DIRS ${LIBEV_INCLUDE_DIR})
endif()
mark_as_advanced(LIBEV_INCLUDE_DIR LIBEV_LIBRARY)
+113
View File
@@ -0,0 +1,113 @@
#--------------------------------------------------------
# Copyright (C) 1995-2007 MySQL AB
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# There are special exceptions to the terms and conditions of the GPL
# as it is applied to this software. View the full text of the exception
# in file LICENSE.exceptions in the top-level directory of this software
# distribution.
#
# 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
#
# The MySQL Connector/ODBC is licensed under the terms of the
# GPL, like most MySQL Connectors. There are special exceptions
# to the terms and conditions of the GPL as it is applied to
# this software, see the FLOSS License Exception available on
# mysql.com.
##########################################################################
#-------------- FIND MYSQL_INCLUDE_DIR ------------------
FIND_PATH(MYSQL_INCLUDE_DIR mysql.h
/usr/include/mysql
/usr/local/include/mysql
/opt/mysql/mysql/include
/opt/mysql/mysql/include/mysql
/opt/mysql/include
/opt/local/include/mysql5
/usr/local/mysql/include
/usr/local/mysql/include/mysql
$ENV{ProgramFiles}/MySQL/*/include
$ENV{SystemDrive}/MySQL/*/include)
#----------------- FIND MYSQL_LIB_DIR -------------------
IF (WIN32)
# Set lib path suffixes
# dist = for mysql binary distributions
# build = for custom built tree
IF (CMAKE_BUILD_TYPE STREQUAL Debug)
SET(libsuffixDist debug)
SET(libsuffixBuild Debug)
ELSE (CMAKE_BUILD_TYPE STREQUAL Debug)
SET(libsuffixDist opt)
SET(libsuffixBuild Release)
ADD_DEFINITIONS(-DDBUG_OFF)
ENDIF (CMAKE_BUILD_TYPE STREQUAL Debug)
FIND_LIBRARY(MYSQL_LIB NAMES mysqlclient
PATHS
$ENV{MYSQL_DIR}/lib/${libsuffixDist}
$ENV{MYSQL_DIR}/libmysql
$ENV{MYSQL_DIR}/libmysql/${libsuffixBuild}
$ENV{MYSQL_DIR}/client/${libsuffixBuild}
$ENV{MYSQL_DIR}/libmysql/${libsuffixBuild}
$ENV{ProgramFiles}/MySQL/*/lib/${libsuffixDist}
$ENV{SystemDrive}/MySQL/*/lib/${libsuffixDist})
ELSE (WIN32)
FIND_LIBRARY(MYSQL_LIB NAMES mysqlclient_r mysqlclient
PATHS
/usr/lib/mysql
/usr/local/lib/mysql
/usr/local/mysql/lib
/usr/local/mysql/lib/mysql
/opt/local/mysql5/lib
/opt/local/lib/mysql5/mysql
/opt/mysql/mysql/lib/mysql
/opt/mysql/lib/mysql)
ENDIF (WIN32)
IF(MYSQL_LIB)
GET_FILENAME_COMPONENT(MYSQL_LIB_DIR ${MYSQL_LIB} PATH)
ENDIF(MYSQL_LIB)
IF (MYSQL_INCLUDE_DIR AND MYSQL_LIB_DIR)
SET(MYSQL_FOUND TRUE)
INCLUDE_DIRECTORIES(${MYSQL_INCLUDE_DIR})
LINK_DIRECTORIES(${MYSQL_LIB_DIR})
FIND_LIBRARY(MYSQL_ZLIB zlib PATHS ${MYSQL_LIB_DIR})
FIND_LIBRARY(MYSQL_TAOCRYPT taocrypt PATHS ${MYSQL_LIB_DIR})
IF (MYSQL_LIB)
SET(MYSQL_CLIENT_LIBS ${MYSQL_LIB})
ELSE()
SET(MYSQL_CLIENT_LIBS mysqlclient_r)
ENDIF()
IF (MYSQL_ZLIB)
SET(MYSQL_CLIENT_LIBS ${MYSQL_CLIENT_LIBS} zlib)
ENDIF (MYSQL_ZLIB)
IF (MYSQL_TAOCRYPT)
SET(MYSQL_CLIENT_LIBS ${MYSQL_CLIENT_LIBS} taocrypt)
ENDIF (MYSQL_TAOCRYPT)
# Added needed mysqlclient dependencies on Windows
IF (WIN32)
SET(MYSQL_CLIENT_LIBS ${MYSQL_CLIENT_LIBS} ws2_32)
ENDIF (WIN32)
MESSAGE(STATUS "MySQL Include dir: ${MYSQL_INCLUDE_DIR} library dir: ${MYSQL_LIB_DIR}")
MESSAGE(STATUS "MySQL client libraries: ${MYSQL_CLIENT_LIBS}")
ELSEIF (MySQL_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Cannot find MySQL. Include dir: ${MYSQL_INCLUDE_DIR} library dir: ${MYSQL_LIB_DIR}")
ENDIF (MYSQL_INCLUDE_DIR AND MYSQL_LIB_DIR)
+33
View File
@@ -0,0 +1,33 @@
# - Find MySQL++
# Find the MySQL++ includes and client library
# This module defines
# MYSQLPP_INCLUDE_DIR, where to find mysql.h
# MYSQLPP_LIBRARY, the libraries needed to use MySQL.
# MYSQLPP_FOUND, If false, do not try to use MySQL.
FIND_PATH(MYSQLPP_INCLUDE_DIR mysql++.h
/usr/include/mysql++
/usr/local/include/mysql++
/opt/mysql++/include/mysql++
/opt/mysqlpp/include/mysql++
/opt/mysqlpp/include/
)
FIND_LIBRARY(MYSQLPP_LIBRARY mysqlpp
PATHS
/usr/lib
/usr/local/lib
/opt/mysql++
/opt/mysqlpp
/opt/mysqlpp/lib
)
if(MYSQLPP_INCLUDE_DIR AND MYSQLPP_LIBRARY)
set(MYSQLPP_FOUND TRUE)
message(STATUS "Found MySQL++: ${MYSQLPP_INCLUDE_DIR}, ${MYSQLPP_LIBRARY}")
else()
set(MYSQLPP_FOUND FALSE)
message(STATUS "MySQL++ was not found.")
endif()
mark_as_advanced(MYSQLPP_INCLUDE_DIR MYSQLPP_LIBRARY)
+42
View File
@@ -0,0 +1,42 @@
# - Find Tcmalloc
# Find the native Tcmalloc includes and library
#
# TCMALLOC_INCLUDE_DIR - where to find Tcmalloc.h, etc.
# TCMALLOC_LIBRARIES - List of libraries when using Tcmalloc.
# TCMALLOC_FOUND - True if Tcmalloc found.
find_path(TCMALLOC_INCLUDE_DIR google/tcmalloc.h
NO_DEFAULT_PATH
PATHS
/usr/include
/usr/local/include
/opt/local/include
)
set(TCMALLOC_NAMES tcmalloc_minimal tcmalloc)
find_library(TCMALLOC_LIBRARY NO_DEFAULT_PATH
NAMES ${TCMALLOC_NAMES}
PATHS
/lib
/usr/lib
/usr/local/lib
/opt/local/lib
)
if(TCMALLOC_INCLUDE_DIR AND TCMALLOC_LIBRARY)
set(TCMALLOC_FOUND TRUE)
else()
set(TCMALLOC_FOUND FALSE)
endif()
if(TCMALLOC_FOUND)
message(STATUS "Found Tcmalloc: ${TCMALLOC_LIBRARY}")
else()
message(STATUS "Could not find tcmalloc")
endif()
mark_as_advanced(
TCMALLOC_LIBRARY
TCMALLOC_INCLUDE_DIR
)
+78
View File
@@ -0,0 +1,78 @@
cmake_minimum_required(VERSION 3.1)
project(ocelot
VERSION 2.0.0
)
# Make a subdirectory, and run cmake there (mkdir build; cd build; cmake ..)
if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)
message(FATAL_ERROR "Source and build directories cannot be the same.")
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden -Wall -Wfatal-errors")
message(STATUS "CMAKE_MODULE_PATH='${CMAKE_MODULE_PATH}'")
find_package(Jemalloc)
find_package(Tcmalloc)
if(JEMALLOC_FOUND)
option(USE_JEMALLOC "Use jemalloc instead of system-provided malloc" ON)
if(TCMALLOC_FOUND)
option(USE_TCMALLOC "Use tcmalloc (Google's thread-cacheing malloc) instead of system-provided malloc" OFF)
else()
set(USE_TCMALLOC OFF)
endif()
else()
set(USE_JEMALLOC OFF)
if(TCMALLOC_FOUND)
option(USE_TCMALLOC "Use tcmalloc (Google's thread-cacheing malloc) instead of system-provided malloc" ON)
else()
set(USE_TCMALLOC OFF)
endif()
endif()
#AM_LDFLAGS = -Wl,-O1 -Wl,--as-needed
find_package(Boost COMPONENTS system iostreams REQUIRED)
message(STATUS "Boost_INCLUDE_DIRS='${Boost_INCLUDE_DIRS}'")
message(STATUS "Boost_LIBRARIES='${Boost_LIBRARIES}'")
include_directories(${Boost_INCLUDE_DIRS})
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(MYSQL REQUIRED)
find_package(MYSQLPP REQUIRED)
find_package(LibEv REQUIRED)
include_directories(${LIBEV_INCLUDE_DIR})
include_directories(${CMAKE_SOURCE_DIR}/libs)
file(GLOB HEADERS src/*.h)
file(GLOB SOURCES src/*.cpp)
add_executable(ocelot ${HEADERS} ${SOURCES})
SET(LINK_LIBRARIES
${Boost_SYSTEM_LIBRARY}
${Boost_IOSTREAMS_LIBRARY}
${LIBEV_LIBRARY}
${MYSQLPP_LIBRARY}
Threads::Threads
)
if (USE_JEMALLOC)
message(STATUS "Build with jemalloc")
list(APPEND LINK_LIBRARIES ${JEMALLOC_LIBRARY})
elseif (USE_TCMALLOC)
message(STATUS "Build with tcmalloc")
list(APPEND LINK_LIBRARIES ${TCMALLOC_LIBRARY})
endif()
target_link_libraries(
ocelot
${LINK_LIBRARIES}
)
+36
View File
@@ -0,0 +1,36 @@
FROM debian:bookworm-slim
LABEL org.opencontainers.image.source=https://github.com/OPSnet/Ocelot
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
build-essential \
cmake \
default-libmysqlclient-dev \
libboost-iostreams-dev \
libboost-system-dev \
libev-dev \
libjemalloc-dev \
libmysql++-dev \
netcat-traditional \
pkg-config \
&& rm -rf /var/lib/apt/lists/*
COPY . /srv
WORKDIR /srv
RUN cmake -Wno-dev -S /srv -B /srv/build \
&& make -C build \
&& apt-get purge -y \
build-essential \
cmake \
pkg-config \
&& apt-get autoremove -y \
&& apt-get clean -y \
&& mv /srv/build/ocelot /srv/ocelot \
&& mv /srv/ocelot.conf.dist /srv/ocelot.conf
# default listen_port value in ocelot.conf
EXPOSE 34000
CMD ["/srv/ocelot"]
-14
View File
@@ -1,14 +0,0 @@
ACLOCAL_AMFLAGS = -I m4
bin_PROGRAMS = ocelot
ocelot_SOURCES = config.cpp config.h db.cpp db.h events.cpp events.h misc_functions.cpp misc_functions.h \
ocelot.cpp ocelot.h report.cpp report.h response.cpp response.h \
schedule.cpp schedule.h site_comm.cpp site_comm.h user.cpp user.h worker.cpp worker.h
AM_CXXFLAGS = -std=c++11 -march=native -O2 -fvisibility=hidden -fvisibility-inlines-hidden -fomit-frame-pointer -fno-ident -Wall -Wfatal-errors $(PTHREAD_CFLAGS) $(BOOST_CPPFLAGS)
ocelot_LDADD = $(PTHREAD_LIBS) $(BOOST_IOSTREAMS_LIB) $(BOOST_SYSTEM_LIB)
AM_LDFLAGS = -Wl,-O1 -Wl,--as-needed
EXTRA_DIST = CHANGES LICENSE README.md ocelot.conf.dist
dist-hook:
touch ${distdir}/configure
patch -p2 -d ${distdir} --no-backup-if-mismatch < ../dist.patch
-808
View File
@@ -1,808 +0,0 @@
# Makefile.in generated by automake 1.15 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
bin_PROGRAMS = ocelot$(EXEEXT)
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_boost_base.m4 \
$(top_srcdir)/m4/ax_boost_iostreams.m4 \
$(top_srcdir)/m4/ax_boost_system.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
$(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/ev++.m4 \
$(top_srcdir)/m4/mysql++.m4 $(top_srcdir)/m4/mysql_loc.m4 \
$(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
$(am__configure_deps) $(am__DIST_COMMON)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno config.status.lineno
mkinstalldirs = $(install_sh) -d
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS)
am_ocelot_OBJECTS = config.$(OBJEXT) db.$(OBJEXT) events.$(OBJEXT) \
misc_functions.$(OBJEXT) ocelot.$(OBJEXT) report.$(OBJEXT) \
response.$(OBJEXT) schedule.$(OBJEXT) site_comm.$(OBJEXT) \
user.$(OBJEXT) worker.$(OBJEXT)
ocelot_OBJECTS = $(am_ocelot_OBJECTS)
am__DEPENDENCIES_1 =
ocelot_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_CXX = $(am__v_CXX_@AM_V@)
am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
am__v_CXX_0 = @echo " CXX " $@;
am__v_CXX_1 =
CXXLD = $(CXX)
CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
-o $@
AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
am__v_CXXLD_0 = @echo " CXXLD " $@;
am__v_CXXLD_1 =
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(ocelot_SOURCES)
DIST_SOURCES = $(ocelot_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
CSCOPE = cscope
AM_RECURSIVE_TARGETS = cscope
am__DIST_COMMON = $(srcdir)/Makefile.in compile config.guess \
config.sub depcomp install-sh missing
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
am__remove_distdir = \
if test -d "$(distdir)"; then \
find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
&& rm -rf "$(distdir)" \
|| { sleep 5 && rm -rf "$(distdir)"; }; \
else :; fi
am__post_remove_distdir = $(am__remove_distdir)
DIST_ARCHIVES = $(distdir).tar.gz
GZIP_ENV = --best
DIST_TARGETS = dist-gzip
distuninstallcheck_listfiles = find . -type f -print
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
BOOST_IOSTREAMS_LIB = @BOOST_IOSTREAMS_LIB@
BOOST_LDFLAGS = @BOOST_LDFLAGS@
BOOST_SYSTEM_LIB = @BOOST_SYSTEM_LIB@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EV_INC_DIR = @EV_INC_DIR@
EV_LIB_DIR = @EV_LIB_DIR@
EXEEXT = @EXEEXT@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
MYSQLPP_INC_DIR = @MYSQLPP_INC_DIR@
MYSQLPP_LIB_DIR = @MYSQLPP_LIB_DIR@
MYSQL_C_INC_DIR = @MYSQL_C_INC_DIR@
MYSQL_C_LIB_DIR = @MYSQL_C_LIB_DIR@
MYSQL_C_LIB_NAME = @MYSQL_C_LIB_NAME@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PTHREAD_CC = @PTHREAD_CC@
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
PTHREAD_LIBS = @PTHREAD_LIBS@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
ax_pthread_config = @ax_pthread_config@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
ACLOCAL_AMFLAGS = -I m4
ocelot_SOURCES = config.cpp config.h db.cpp db.h events.cpp events.h misc_functions.cpp misc_functions.h \
ocelot.cpp ocelot.h report.cpp report.h response.cpp response.h \
schedule.cpp schedule.h site_comm.cpp site_comm.h user.cpp user.h worker.cpp worker.h
AM_CXXFLAGS = -std=c++11 -march=native -O2 -fvisibility=hidden -fvisibility-inlines-hidden -fomit-frame-pointer -fno-ident -Wall -Wfatal-errors $(PTHREAD_CFLAGS) $(BOOST_CPPFLAGS)
ocelot_LDADD = $(PTHREAD_LIBS) $(BOOST_IOSTREAMS_LIB) $(BOOST_SYSTEM_LIB)
AM_LDFLAGS = -Wl,-O1 -Wl,--as-needed
EXTRA_DIST = CHANGES LICENSE README.md ocelot.conf.dist
all: all-am
.SUFFIXES:
.SUFFIXES: .cpp .o .obj
am--refresh: Makefile
@:
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
$(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
echo ' $(SHELL) ./config.status'; \
$(SHELL) ./config.status;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck
$(top_srcdir)/configure: $(am__configure_deps)
$(am__cd) $(srcdir) && $(AUTOCONF)
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
$(am__aclocal_m4_deps):
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
$(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p \
; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' \
-e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
} \
; done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' \
`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(bindir)" && rm -f $$files
clean-binPROGRAMS:
-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
ocelot$(EXEEXT): $(ocelot_OBJECTS) $(ocelot_DEPENDENCIES) $(EXTRA_ocelot_DEPENDENCIES)
@rm -f ocelot$(EXEEXT)
$(AM_V_CXXLD)$(CXXLINK) $(ocelot_OBJECTS) $(ocelot_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/db.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/events.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc_functions.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocelot.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/report.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/response.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/schedule.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/site_comm.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/user.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/worker.Po@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
.cpp.obj:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscope: cscope.files
test ! -s cscope.files \
|| $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
clean-cscope:
-rm -f cscope.files
cscope.files: clean-cscope cscopelist
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
distdir: $(DISTFILES)
$(am__remove_distdir)
test -d "$(distdir)" || mkdir "$(distdir)"
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
$(MAKE) $(AM_MAKEFLAGS) \
top_distdir="$(top_distdir)" distdir="$(distdir)" \
dist-hook
-test -n "$(am__skip_mode_fix)" \
|| find "$(distdir)" -type d ! -perm -755 \
-exec chmod u+rwx,go+rx {} \; -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|| chmod -R a+r "$(distdir)"
dist-gzip: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
$(am__post_remove_distdir)
dist-bzip2: distdir
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
$(am__post_remove_distdir)
dist-lzip: distdir
tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
$(am__post_remove_distdir)
dist-xz: distdir
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
$(am__post_remove_distdir)
dist-tarZ: distdir
@echo WARNING: "Support for distribution archives compressed with" \
"legacy program 'compress' is deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
$(am__post_remove_distdir)
dist-shar: distdir
@echo WARNING: "Support for shar distribution archives is" \
"deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
$(am__post_remove_distdir)
dist-zip: distdir
-rm -f $(distdir).zip
zip -rq $(distdir).zip $(distdir)
$(am__post_remove_distdir)
dist dist-all:
$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
$(am__post_remove_distdir)
# This target untars the dist file and tries a VPATH configuration. Then
# it guarantees that the distribution is self-contained by making another
# tarfile.
distcheck: dist
case '$(DIST_ARCHIVES)' in \
*.tar.gz*) \
GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.lz*) \
lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
*.tar.xz*) \
xz -dc $(distdir).tar.xz | $(am__untar) ;;\
*.tar.Z*) \
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
*.shar.gz*) \
GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
esac
chmod -R a-w $(distdir)
chmod u+w $(distdir)
mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
chmod a-w $(distdir)
test -d $(distdir)/_build || exit 0; \
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
&& am__cwd=`pwd` \
&& $(am__cd) $(distdir)/_build/sub \
&& ../../configure \
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
$(DISTCHECK_CONFIGURE_FLAGS) \
--srcdir=../.. --prefix="$$dc_install_base" \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
&& $(MAKE) $(AM_MAKEFLAGS) check \
&& $(MAKE) $(AM_MAKEFLAGS) install \
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
distuninstallcheck \
&& chmod -R a-w "$$dc_install_base" \
&& ({ \
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
} || { rm -rf "$$dc_destdir"; exit 1; }) \
&& rm -rf "$$dc_destdir" \
&& $(MAKE) $(AM_MAKEFLAGS) dist \
&& rm -rf $(DIST_ARCHIVES) \
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
&& cd "$$am__cwd" \
|| exit 1
$(am__post_remove_distdir)
@(echo "$(distdir) archives ready for distribution: "; \
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
distuninstallcheck:
@test -n '$(distuninstallcheck_dir)' || { \
echo 'ERROR: trying to run $@ with an empty' \
'$$(distuninstallcheck_dir)' >&2; \
exit 1; \
}; \
$(am__cd) '$(distuninstallcheck_dir)' || { \
echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
exit 1; \
}; \
test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
|| { echo "ERROR: files left after uninstall:" ; \
if test -n "$(DESTDIR)"; then \
echo " (check DESTDIR support)"; \
fi ; \
$(distuninstallcheck_listfiles) ; \
exit 1; } >&2
distcleancheck: distclean
@if test '$(srcdir)' = . ; then \
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
exit 1 ; \
fi
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|| { echo "ERROR: files left in build directory after distclean:" ; \
$(distcleancheck_listfiles) ; \
exit 1; } >&2
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS)
installdirs:
for dir in "$(DESTDIR)$(bindir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
distclean: distclean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-binPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf $(top_srcdir)/autom4te.cache
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-binPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-am clean \
clean-binPROGRAMS clean-cscope clean-generic cscope \
cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
dist-gzip dist-hook dist-lzip dist-shar dist-tarZ dist-xz \
dist-zip distcheck distclean distclean-compile \
distclean-generic distclean-tags distcleancheck distdir \
distuninstallcheck dvi dvi-am html html-am info info-am \
install install-am install-binPROGRAMS install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-pdf install-pdf-am \
install-ps install-ps-am install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
uninstall-am uninstall-binPROGRAMS
.PRECIOUS: Makefile
dist-hook:
touch ${distdir}/configure
patch -p2 -d ${distdir} --no-backup-if-mismatch < ../dist.patch
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
+37 -7
View File
@@ -1,24 +1,56 @@
# Ocelot
Ocelot is a BitTorrent tracker written in C++ for the [Gazelle](http://whatcd.github.io/Gazelle/) project. It supports requests over TCP and can only track IPv4 peers.
Ocelot is a BitTorrent tracker written in C++ for the [Gazelle](http://github.com/OPSnet/Gazelle) project.
It supports requests over TCP and can only track IPv4 peers.
## Ocelot Compile-time Dependencies
* [GCC/G++](http://gcc.gnu.org/) (4.7+ required; 4.8.1+ recommended)
* [Boost](http://www.boost.org/) (1.55.0+ required)
* [GCC/G++](http://gcc.gnu.org/) (11+ required; 11.4.0+ recommended)
* [Boost](http://www.boost.org/) (1.74.0+ required)
* [libev](http://software.schmorp.de/pkg/libev.html) (required)
* [MySQL++](http://tangentsoft.net/mysql++/) (3.2.0+ required)
* [TCMalloc](http://goog-perftools.sourceforge.net/doc/tcmalloc.html) (optional, but strongly recommended)
* [jemalloc](http://jemalloc.net/) (optional, but strongly recommended)
* [TCMalloc](http://goog-perftools.sourceforge.net/doc/tcmalloc.html) (optional)
## Installation
### Debian Bookworm
```bash
sudo apt-get install \
build-essential \
cmake \
default-libmysqlclient-dev \
libboost-iostreams-dev \
libboost-system-dev \
libev-dev \
libjemalloc-dev \
libmysql++-dev \
netcat-traditional \
pkg-config
cmake -Wno-dev . -B build
make -C build
```
The [Gazelle installation guides](https://github.com/WhatCD/Gazelle/wiki/Gazelle-installation) include instructions for installing Ocelot as a part of the Gazelle project.
### Docker
```bash
docker build . -t ocelot
docker run -v $(pwd)/ocelot.conf:/srv/ocelot.conf ocelot
```
### Standalone Installation
* Prepare the build environment. (This must be re-executed when new source files are added).
cmake -Wno-dev . -B build
* Create the following tables according to the [Gazelle database schema](https://raw.githubusercontent.com/WhatCD/Gazelle/master/gazelle.sql):
- `torrents`
- `torrents_leech_stats`
- `users_freeleeches`
- `users_leech_stats`
- `users_main`
- `xbt_client_whitelist`
- `xbt_files_users`
@@ -28,9 +60,7 @@ The [Gazelle installation guides](https://github.com/WhatCD/Gazelle/wiki/Gazelle
* Build Ocelot:
./configure
make
make install
make -C build
## Running Ocelot
Vendored
-1161
View File
File diff suppressed because it is too large. Load diff
-347
View File
@@ -1,347 +0,0 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2012-10-14.11; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# Written by Tom Tromey <[email protected]>.
#
# 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, 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 <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <[email protected]> or send patches to
# <[email protected]>.
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
func_file_conv "$1"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
}
# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
lib=$1
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
lib=$dir/$lib.dll.lib
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
lib=$dir/$lib.lib
break
fi
if test -f "$dir/lib$lib.a"; then
found=yes
lib=$dir/lib$lib.a
break
fi
done
IFS=$save_IFS
if test "$found" != yes; then
lib=$lib.lib
fi
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I)
eat=1
func_file_conv "$2" mingw
set x "$@" -I"$file"
shift
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l)
eat=1
func_cl_dashl "$2"
set x "$@" "$lib"
shift
;;
-l*)
func_cl_dashl "${1#-l}"
set x "$@" "$lib"
shift
;;
-L)
eat=1
func_cl_dashL "$2"
;;
-L*)
func_cl_dashL "${1#-L}"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to <[email protected]>.
EOF
exit $?
;;
-v | --v*)
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
-1431
View File
File diff suppressed because it is too large. Load diff
Vendored
-1811
View File
File diff suppressed because it is too large. Load diff
Vendored
-7919
View File
File diff suppressed because it is too large. Load diff
-18
View File
@@ -1,18 +0,0 @@
AC_INIT(ocelot, 1.0)
AM_INIT_AUTOMAKE([1.11 no-define foreign])
AC_PROG_CXX
AC_CONFIG_FILES([Makefile])
AC_LANG_PUSH([C++])
AX_CHECK_COMPILE_FLAG([-std=c++11], [], [AC_MSG_ERROR([Compiler does not support -std=c++11])])
AX_CHECK_COMPILE_FLAG([-fstack-protector-strong], [CXXFLAGS="-fstack-protector-strong $CXXFLAGS"])
AC_LANG_POP([C++])
AX_BOOST_BASE([1.37], [], [AC_MSG_ERROR(Need boost >= 1.37)])
AX_BOOST_IOSTREAMS
AX_BOOST_SYSTEM
AX_PTHREAD([], AC_MSG_FAILURE([pthread library is required]))
EV_DEVEL
MYSQL_C_API_LOCATION
MYSQLPP_DEVEL
TCMALLOC
AC_OUTPUT
File diff suppressed because it is too large. Load diff
-791
View File
@@ -1,791 +0,0 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2013-05-30.07; # UTC
# Copyright (C) 1999-2013 Free Software Foundation, 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, 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 <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <[email protected]>.
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <[email protected]>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
# Get the directory component of the given path, and save it in the
# global variables '$dir'. Note that this directory component will
# be either empty or ending with a '/' character. This is deliberate.
set_dir_from ()
{
case $1 in
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
*) dir=;;
esac
}
# Get the suffix-stripped basename of the given path, and save it the
# global variable '$base'.
set_base_from ()
{
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
}
# If no dependency file was actually created by the compiler invocation,
# we still have to create a dummy depfile, to avoid errors with the
# Makefile "include basename.Plo" scheme.
make_dummy_depfile ()
{
echo "#dummy" > "$depfile"
}
# Factor out some common post-processing of the generated depfile.
# Requires the auxiliary global variable '$tmpdepfile' to be set.
aix_post_process_depfile ()
{
# If the compiler actually managed to produce a dependency file,
# post-process it.
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependency.h'.
# Do two passes, one to just change these to
# $object: dependency.h
# and one to simply output
# dependency.h:
# which is needed to avoid the deleted-header problem.
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
} > "$depfile"
rm -f "$tmpdepfile"
else
make_dummy_depfile
fi
}
# A tabulation character.
tab=' '
# A newline character.
nl='
'
# Character ranges might be problematic outside the C locale.
# These definitions help.
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower=abcdefghijklmnopqrstuvwxyz
digits=0123456789
alpha=${upper}${lower}
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Avoid interferences from the environment.
gccflag= dashmflag=
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
## (see the conditional assignment to $gccflag above).
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say). Also, it might not be
## supported by the other compilers which use the 'gcc' depmode.
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The second -e expression handles DOS-style file names with drive
# letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
| tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
aix_post_process_depfile
;;
tcc)
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
# FIXME: That version still under development at the moment of writing.
# Make that this statement remains true also for stable, released
# versions.
# It will wrap lines (doesn't matter whether long or short) with a
# trailing '\', as in:
#
# foo.o : \
# foo.c \
# foo.h \
#
# It will put a trailing '\' even on the last line, and will use leading
# spaces rather than leading tabs (at least since its commit 0394caf7
# "Emit spaces for -MD").
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
# We have to change lines of the first kind to '$object: \'.
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
# And for each line of the second kind, we have to emit a 'dep.h:'
# dummy dependency, to avoid the deleted-header problem.
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
## The order of this option in the case statement is important, since the
## shell code in configure will try each of these formats in the order
## listed in this file. A plain '-MD' option would be understood by many
## compilers, so we must ensure this comes after the gcc and icc options.
pgcc)
# Portland's C compiler understands '-MD'.
# Will always output deps to 'file.d' where file is the root name of the
# source file under compilation, even if file resides in a subdirectory.
# The object file name does not affect the name of the '.d' file.
# pgcc 10.2 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\' :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
set_dir_from "$object"
# Use the source, not the object, to determine the base name, since
# that's sadly what pgcc will do too.
set_base_from "$source"
tmpdepfile=$base.d
# For projects that build the same source file twice into different object
# files, the pgcc approach of using the *source* file root name can cause
# problems in parallel builds. Use a locking strategy to avoid stomping on
# the same $tmpdepfile.
lockdir=$base.d-lock
trap "
echo '$0: caught signal, cleaning up...' >&2
rmdir '$lockdir'
exit 1
" 1 2 13 15
numtries=100
i=$numtries
while test $i -gt 0; do
# mkdir is a portable test-and-set.
if mkdir "$lockdir" 2>/dev/null; then
# This process acquired the lock.
"$@" -MD
stat=$?
# Release the lock.
rmdir "$lockdir"
break
else
# If the lock is being held by a different process, wait
# until the winning process is done or we timeout.
while test -d "$lockdir" && test $i -gt 0; do
sleep 1
i=`expr $i - 1`
done
fi
i=`expr $i - 1`
done
trap - 1 2 13 15
if test $i -le 0; then
echo "$0: failed to acquire lock after $numtries attempts" >&2
echo "$0: check lockdir '$lockdir'" >&2
exit 1
fi
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
# Libtool generates 2 separate objects for the 2 libraries. These
# two compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir$base.o.d # libtool 1.5
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
# Same post-processing that is required for AIX mode.
aix_post_process_depfile
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this sed invocation
# correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process the last invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed '1,2d' "$tmpdepfile" \
| tr ' ' "$nl" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E \
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
| sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
+176
View File
@@ -0,0 +1,176 @@
SET FOREIGN_KEY_CHECKS = 0;
CREATE DATABASE gazelle CHARACTER SET utf8 COLLATE utf8_swedish_ci;
USE gazelle;
CREATE TABLE `torrents` (
`ID` int(10) NOT NULL AUTO_INCREMENT,
`GroupID` int(10) NOT NULL,
`UserID` int(10) DEFAULT NULL,
`Media` varchar(20) DEFAULT NULL,
`Format` varchar(10) DEFAULT NULL,
`Encoding` varchar(15) DEFAULT NULL,
`Remastered` enum('0','1') NOT NULL DEFAULT '0',
`RemasterYear` int(4) DEFAULT NULL,
`RemasterTitle` varchar(80) NOT NULL DEFAULT '',
`RemasterCatalogueNumber` varchar(80) NOT NULL DEFAULT '',
`RemasterRecordLabel` varchar(80) NOT NULL DEFAULT '',
`Scene` enum('0','1') NOT NULL DEFAULT '0',
`HasLog` enum('0','1') NOT NULL DEFAULT '0',
`HasCue` enum('0','1') NOT NULL DEFAULT '0',
`HasLogDB` enum('0','1') NOT NULL DEFAULT '0',
`LogScore` int(6) NOT NULL DEFAULT '0',
`LogChecksum` enum('0','1') NOT NULL DEFAULT '1',
`info_hash` blob NOT NULL,
`FileCount` int(6) NOT NULL,
`FileList` mediumtext NOT NULL,
`FilePath` varchar(255) NOT NULL DEFAULT '',
`Size` bigint(12) NOT NULL,
`Leechers` int(6) NOT NULL DEFAULT '0',
`Seeders` int(6) NOT NULL DEFAULT '0',
`last_action` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`FreeTorrent` enum('0','1','2') NOT NULL DEFAULT '0',
`FreeLeechType` enum('0','1','2','3','4','5','6','7') NOT NULL DEFAULT '0',
`Time` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`Description` text,
`Snatched` int(10) unsigned NOT NULL DEFAULT '0',
`balance` bigint(20) NOT NULL DEFAULT '0',
`LastReseedRequest` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`TranscodedFrom` int(10) NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`),
UNIQUE KEY `InfoHash` (`info_hash`(40)),
KEY `GroupID` (`GroupID`),
KEY `UserID` (`UserID`),
KEY `Media` (`Media`),
KEY `Format` (`Format`),
KEY `Encoding` (`Encoding`),
KEY `Year` (`RemasterYear`),
KEY `FileCount` (`FileCount`),
KEY `Size` (`Size`),
KEY `Seeders` (`Seeders`),
KEY `Leechers` (`Leechers`),
KEY `Snatched` (`Snatched`),
KEY `last_action` (`last_action`),
KEY `Time` (`Time`),
KEY `FreeTorrent` (`FreeTorrent`)
) ENGINE=InnoDB CHARSET utf8;
CREATE TABLE `users_freeleeches` (
`UserID` int(10) NOT NULL,
`TorrentID` int(10) NOT NULL,
`Time` datetime NOT NULL,
`Expired` tinyint(1) NOT NULL DEFAULT '0',
`Downloaded` bigint(20) NOT NULL DEFAULT '0',
`Uses` int(10) NOT NULL DEFAULT '1',
PRIMARY KEY (`UserID`,`TorrentID`),
KEY `Time` (`Time`),
KEY `Expired_Time` (`Expired`,`Time`)
) ENGINE=InnoDB CHARSET utf8;
CREATE TABLE `users_geodistribution` (
`Code` varchar(2) NOT NULL,
`Users` int(10) NOT NULL
) ENGINE=InnoDB CHARSET utf8;
CREATE TABLE `users_history_emails` (
`UserID` int(10) NOT NULL,
`Email` varchar(255) DEFAULT NULL,
`Time` datetime DEFAULT NULL,
`IP` varchar(15) DEFAULT NULL,
KEY `UserID` (`UserID`)
) ENGINE=InnoDB CHARSET utf8;
CREATE TABLE `users_main` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Username` varchar(20) NOT NULL,
`Email` varchar(255) NOT NULL,
`PassHash` varchar(60) NOT NULL,
`Secret` char(32) NOT NULL,
`IRCKey` char(32) DEFAULT NULL,
`LastLogin` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`LastAccess` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`IP` varchar(15) NOT NULL DEFAULT '0.0.0.0',
`Class` tinyint(2) NOT NULL DEFAULT '5',
`Uploaded` bigint(20) unsigned NOT NULL DEFAULT '0',
`Downloaded` bigint(20) unsigned NOT NULL DEFAULT '0',
`BonusPoints` float(20, 5) NOT NULL DEFAULT '0',
`Title` text NOT NULL,
`Enabled` enum('0','1','2') NOT NULL DEFAULT '0',
`Paranoia` text,
`Visible` enum('1','0') NOT NULL DEFAULT '1',
`Invites` int(10) unsigned NOT NULL DEFAULT '0',
`PermissionID` int(10) unsigned NOT NULL,
`CustomPermissions` text,
`can_leech` tinyint(4) NOT NULL DEFAULT '1',
`torrent_pass` char(32) NOT NULL,
`RequiredRatio` double(10,8) NOT NULL DEFAULT '0.00000000',
`RequiredRatioWork` double(10,8) NOT NULL DEFAULT '0.00000000',
`ipcc` varchar(2) NOT NULL DEFAULT '',
`FLTokens` int(10) NOT NULL DEFAULT '0',
`FLT_Given` int(10) NOT NULL DEFAULT '0',
`Invites_Given` int(10) NOT NULL DEFAULT '0',
`2FA_Key` VARCHAR(16),
`Recovery` text,
PRIMARY KEY (`ID`),
UNIQUE KEY `Username` (`Username`),
KEY `Email` (`Email`),
KEY `PassHash` (`PassHash`),
KEY `LastAccess` (`LastAccess`),
KEY `IP` (`IP`),
KEY `Class` (`Class`),
KEY `Uploaded` (`Uploaded`),
KEY `Downloaded` (`Downloaded`),
KEY `Enabled` (`Enabled`),
KEY `Invites` (`Invites`),
KEY `torrent_pass` (`torrent_pass`),
KEY `RequiredRatio` (`RequiredRatio`),
KEY `cc_index` (`ipcc`),
KEY `PermissionID` (`PermissionID`)
) ENGINE=InnoDB CHARSET utf8;
CREATE TABLE `xbt_client_whitelist` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`peer_id` varchar(20) DEFAULT NULL,
`vstring` varchar(200) DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `peer_id` (`peer_id`)
) ENGINE=InnoDB CHARSET utf8;
CREATE TABLE `xbt_files_users` (
`uid` int(11) NOT NULL,
`active` tinyint(1) NOT NULL DEFAULT '1',
`announced` int(11) NOT NULL DEFAULT '0',
`completed` tinyint(1) NOT NULL DEFAULT '0',
`downloaded` bigint(20) NOT NULL DEFAULT '0',
`remaining` bigint(20) NOT NULL DEFAULT '0',
`uploaded` bigint(20) NOT NULL DEFAULT '0',
`upspeed` int(10) unsigned NOT NULL DEFAULT '0',
`downspeed` int(10) unsigned NOT NULL DEFAULT '0',
`corrupt` bigint(20) NOT NULL DEFAULT '0',
`timespent` int(10) unsigned NOT NULL DEFAULT '0',
`useragent` varchar(51) NOT NULL DEFAULT '',
`connectable` tinyint(4) NOT NULL DEFAULT '1',
`peer_id` binary(20) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
`fid` int(11) NOT NULL,
`mtime` int(11) NOT NULL DEFAULT '0',
`ip` varchar(15) NOT NULL DEFAULT '',
PRIMARY KEY (`peer_id`,`fid`,`uid`),
KEY `remaining_idx` (`remaining`),
KEY `fid_idx` (`fid`),
KEY `mtime_idx` (`mtime`),
KEY `uid_active` (`uid`,`active`)
) ENGINE=InnoDB CHARSET utf8;
CREATE TABLE `xbt_snatched` (
`uid` int(11) NOT NULL DEFAULT '0',
`tstamp` int(11) NOT NULL,
`fid` int(11) NOT NULL,
`IP` varchar(15) NOT NULL,
`seedtime` int(11) NOT NULL DEFAULT '0',
KEY `fid` (`fid`),
KEY `tstamp` (`tstamp`),
KEY `uid_tstamp` (`uid`,`tstamp`)
) ENGINE=InnoDB CHARSET utf8;
SET FOREIGN_KEY_CHECKS = 1;
-527
View File
@@ -1,527 +0,0 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2011-11-20.07; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# 'make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
nl='
'
IFS=" "" $nl"
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_glob='?'
initialize_posix_glob='
test "$posix_glob" != "?" || {
if (set -f) 2>/dev/null; then
posix_glob=
else
posix_glob=:
fi
}
'
posix_mkdir=
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
no_target_directory=
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t) dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) no_target_directory=true;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for 'test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
eval "$initialize_posix_glob"
oIFS=$IFS
IFS=/
$posix_glob set -f
set fnord $dstdir
shift
$posix_glob set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
eval "$initialize_posix_glob" &&
$posix_glob set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
$posix_glob set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
+87
View File
@@ -0,0 +1,87 @@
//
// Copyright(c) 2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// Async logging using global thread pool
// All loggers created here share same global thread pool.
// Each log message is pushed to a queue along withe a shared pointer to the
// logger.
// If a logger deleted while having pending messages in the queue, it's actual
// destruction will defer
// until all its messages are processed by the thread pool.
// This is because each message in the queue holds a shared_ptr to the
// originating logger.
#include "spdlog/async_logger.h"
#include "spdlog/details/registry.h"
#include "spdlog/details/thread_pool.h"
#include <memory>
#include <mutex>
namespace spdlog {
namespace details {
static const size_t default_async_q_size = 8192;
}
// async logger factory - creates async loggers backed with thread pool.
// if a global thread pool doesn't already exist, create it with default queue
// size of 8192 items and single thread.
template<async_overflow_policy OverflowPolicy = async_overflow_policy::block>
struct async_factory_impl
{
template<typename Sink, typename... SinkArgs>
static std::shared_ptr<async_logger> create(const std::string &logger_name, SinkArgs &&... args)
{
auto &registry_inst = details::registry::instance();
// create global thread pool if not already exists..
std::lock_guard<std::recursive_mutex> tp_lock(registry_inst.tp_mutex());
auto tp = registry_inst.get_tp();
if (tp == nullptr)
{
tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1);
registry_inst.set_tp(tp);
}
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
auto new_logger = std::make_shared<async_logger>(logger_name, std::move(sink), std::move(tp), OverflowPolicy);
registry_inst.register_and_init(new_logger);
return new_logger;
}
};
using async_factory = async_factory_impl<async_overflow_policy::block>;
using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;
template<typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create_async(const std::string &logger_name, SinkArgs &&... sink_args)
{
return async_factory::create<Sink>(logger_name, std::forward<SinkArgs>(sink_args)...);
}
template<typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create_async_nb(const std::string &logger_name, SinkArgs &&... sink_args)
{
return async_factory_nonblock::create<Sink>(logger_name, std::forward<SinkArgs>(sink_args)...);
}
// set global thread pool.
inline void init_thread_pool(size_t q_size, size_t thread_count)
{
auto tp = std::make_shared<details::thread_pool>(q_size, thread_count);
details::registry::instance().set_tp(std::move(tp));
}
// get the global thread pool.
inline std::shared_ptr<spdlog::details::thread_pool> thread_pool()
{
return details::registry::instance().get_tp();
}
} // namespace spdlog
+73
View File
@@ -0,0 +1,73 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Very fast asynchronous logger (millions of logs per second on an average
// desktop)
// Uses pre allocated lockfree queue for maximum throughput even under large
// number of threads.
// Creates a single back thread to pop messages from the queue and log them.
//
// Upon each log write the logger:
// 1. Checks if its log level is enough to log the message
// 2. Push a new copy of the message to a queue (or block the caller until
// space is available in the queue)
// 3. will throw spdlog_ex upon log exceptions
// Upon destruction, logs all remaining messages in the queue before
// destructing..
#include "spdlog/common.h"
#include "spdlog/logger.h"
#include <chrono>
#include <memory>
#include <string>
namespace spdlog {
// Async overflow policy - block by default.
enum class async_overflow_policy
{
block, // Block until message can be enqueued
overrun_oldest // Discard oldest message in the queue if full when trying to
// add new item.
};
namespace details {
class thread_pool;
}
class async_logger final : public std::enable_shared_from_this<async_logger>, public logger
{
friend class details::thread_pool;
public:
template<typename It>
async_logger(std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block);
async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block);
async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block);
std::shared_ptr<logger> clone(std::string new_name) override;
protected:
void sink_it_(details::log_msg &msg) override;
void flush_() override;
void backend_log_(const details::log_msg &incoming_log_msg);
void backend_flush_();
private:
std::weak_ptr<details::thread_pool> thread_pool_;
async_overflow_policy overflow_policy_;
};
} // namespace spdlog
#include "spdlog/details/async_logger_impl.h"
+186
View File
@@ -0,0 +1,186 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/tweakme.h"
#include <atomic>
#include <chrono>
#include <functional>
#include <initializer_list>
#include <memory>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <unordered_map>
#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
#include <codecvt>
#include <locale>
#endif
#include "spdlog/details/null_mutex.h"
// visual studio upto 2013 does not support noexcept nor constexpr
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define SPDLOG_NOEXCEPT throw()
#define SPDLOG_CONSTEXPR
#else
#define SPDLOG_NOEXCEPT noexcept
#define SPDLOG_CONSTEXPR constexpr
#endif
#if defined(__GNUC__) || defined(__clang__)
#define SPDLOG_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define SPDLOG_DEPRECATED __declspec(deprecated)
#else
#define SPDLOG_DEPRECATED
#endif
#include "spdlog/fmt/fmt.h"
namespace spdlog {
class formatter;
namespace sinks {
class sink;
}
using log_clock = std::chrono::system_clock;
using sink_ptr = std::shared_ptr<sinks::sink>;
using sinks_init_list = std::initializer_list<sink_ptr>;
using log_err_handler = std::function<void(const std::string &err_msg)>;
#if defined(SPDLOG_NO_ATOMIC_LEVELS)
using level_t = details::null_atomic_int;
#else
using level_t = std::atomic<int>;
#endif
// Log level enum
namespace level {
enum level_enum
{
trace = 0,
debug = 1,
info = 2,
warn = 3,
err = 4,
critical = 5,
off = 6
};
#if !defined(SPDLOG_LEVEL_NAMES)
#define SPDLOG_LEVEL_NAMES \
{ \
"trace", "debug", "info", "warning", "error", "critical", "off" \
}
#endif
static const char *level_names[] SPDLOG_LEVEL_NAMES;
static const char *short_level_names[]{"T", "D", "I", "W", "E", "C", "O"};
inline const char *to_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
{
return level_names[l];
}
inline const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
{
return short_level_names[l];
}
inline spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT
{
static std::unordered_map<std::string, level_enum> name_to_level = // map string->level
{{level_names[0], level::trace}, // trace
{level_names[1], level::debug}, // debug
{level_names[2], level::info}, // info
{level_names[3], level::warn}, // warn
{level_names[4], level::err}, // err
{level_names[5], level::critical}, // critical
{level_names[6], level::off}}; // off
auto lvl_it = name_to_level.find(name);
return lvl_it != name_to_level.end() ? lvl_it->second : level::off;
}
using level_hasher = std::hash<int>;
} // namespace level
//
// Pattern time - specific time getting to use for pattern_formatter.
// local time by default
//
enum class pattern_time_type
{
local, // log localtime
utc // log utc
};
//
// Log exception
//
class spdlog_ex : public std::exception
{
public:
explicit spdlog_ex(std::string msg)
: msg_(std::move(msg))
{
}
spdlog_ex(const std::string &msg, int last_errno)
{
fmt::memory_buffer outbuf;
fmt::format_system_error(outbuf, last_errno, msg);
msg_ = fmt::to_string(outbuf);
}
const char *what() const SPDLOG_NOEXCEPT override
{
return msg_.c_str();
}
private:
std::string msg_;
};
//
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
//
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
using filename_t = std::wstring;
#else
using filename_t = std::string;
#endif
#define SPDLOG_CATCH_AND_HANDLE \
catch (const std::exception &ex) \
{ \
err_handler_(ex.what()); \
} \
catch (...) \
{ \
err_handler_("Unknown exeption in logger"); \
}
namespace details {
// make_unique support for pre c++14
#if __cplusplus >= 201402L // C++14 and beyond
using std::make_unique;
#else
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args &&... args)
{
static_assert(!std::is_array<T>::value, "arrays not supported");
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
#endif
} // namespace details
} // namespace spdlog
+110
View File
@@ -0,0 +1,110 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// async logger implementation
// uses a thread pool to perform the actual logging
#include "spdlog/details/thread_pool.h"
#include <chrono>
#include <memory>
#include <string>
template<typename It>
inline spdlog::async_logger::async_logger(
std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
: logger(std::move(logger_name), begin, end)
, thread_pool_(tp)
, overflow_policy_(overflow_policy)
{
}
inline spdlog::async_logger::async_logger(
std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
: async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), tp, overflow_policy)
{
}
inline spdlog::async_logger::async_logger(
std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
: async_logger(std::move(logger_name), {single_sink}, tp, overflow_policy)
{
}
// send the log message to the thread pool
inline void spdlog::async_logger::sink_it_(details::log_msg &msg)
{
#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)
incr_msg_counter_(msg);
#endif
if (auto pool_ptr = thread_pool_.lock())
{
pool_ptr->post_log(shared_from_this(), std::move(msg), overflow_policy_);
}
else
{
throw spdlog_ex("async log: thread pool doesn't exist anymore");
}
}
// send flush request to the thread pool
inline void spdlog::async_logger::flush_()
{
if (auto pool_ptr = thread_pool_.lock())
{
pool_ptr->post_flush(shared_from_this(), overflow_policy_);
}
else
{
throw spdlog_ex("async flush: thread pool doesn't exist anymore");
}
}
//
// backend functions - called from the thread pool to do the actual job
//
inline void spdlog::async_logger::backend_log_(const details::log_msg &incoming_log_msg)
{
try
{
for (auto &s : sinks_)
{
if (s->should_log(incoming_log_msg.level))
{
s->log(incoming_log_msg);
}
}
}
SPDLOG_CATCH_AND_HANDLE
if (should_flush_(incoming_log_msg))
{
backend_flush_();
}
}
inline void spdlog::async_logger::backend_flush_()
{
try
{
for (auto &sink : sinks_)
{
sink->flush();
}
}
SPDLOG_CATCH_AND_HANDLE
}
inline std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name)
{
auto cloned = std::make_shared<spdlog::async_logger>(std::move(new_name), sinks_.begin(), sinks_.end(), thread_pool_, overflow_policy_);
cloned->set_level(this->level());
cloned->flush_on(this->flush_level());
cloned->set_error_handler(this->error_handler());
return std::move(cloned);
}
+72
View File
@@ -0,0 +1,72 @@
//
// Copyright(c) 2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
// cirucal q view of std::vector.
#pragma once
#include <vector>
namespace spdlog {
namespace details {
template<typename T>
class circular_q
{
public:
using item_type = T;
explicit circular_q(size_t max_items)
: max_items_(max_items + 1) // one item is reserved as marker for full q
, v_(max_items_)
{
}
// push back, overrun (oldest) item if no room left
void push_back(T &&item)
{
v_[tail_] = std::move(item);
tail_ = (tail_ + 1) % max_items_;
if (tail_ == head_) // overrun last item if full
{
head_ = (head_ + 1) % max_items_;
++overrun_counter_;
}
}
// Pop item from front.
// If there are no elements in the container, the behavior is undefined.
void pop_front(T &popped_item)
{
popped_item = std::move(v_[head_]);
head_ = (head_ + 1) % max_items_;
}
bool empty()
{
return tail_ == head_;
}
bool full()
{
// head is ahead of the tail by 1
return ((tail_ + 1) % max_items_) == head_;
}
size_t overrun_counter() const
{
return overrun_counter_;
}
private:
size_t max_items_;
typename std::vector<T>::size_type head_ = 0;
typename std::vector<T>::size_type tail_ = 0;
std::vector<T> v_;
size_t overrun_counter_ = 0;
};
} // namespace details
} // namespace spdlog
+74
View File
@@ -0,0 +1,74 @@
#pragma once
//
// Copyright(c) 2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#include "spdlog/details/null_mutex.h"
#include <cstdio>
#include <mutex>
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX // prevent windows redefining min/max
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif
namespace spdlog {
namespace details {
struct console_stdout
{
static std::FILE *stream()
{
return stdout;
}
#ifdef _WIN32
static HANDLE handle()
{
return ::GetStdHandle(STD_OUTPUT_HANDLE);
}
#endif
};
struct console_stderr
{
static std::FILE *stream()
{
return stderr;
}
#ifdef _WIN32
static HANDLE handle()
{
return ::GetStdHandle(STD_ERROR_HANDLE);
}
#endif
};
struct console_mutex
{
using mutex_t = std::mutex;
static mutex_t &mutex()
{
static mutex_t s_mutex;
return s_mutex;
}
};
struct console_nullmutex
{
using mutex_t = null_mutex;
static mutex_t &mutex()
{
static mutex_t s_mutex;
return s_mutex;
}
};
} // namespace details
} // namespace spdlog
+152
View File
@@ -0,0 +1,152 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Helper class for file sinks.
// When failing to open a file, retry several times(5) with a delay interval(10 ms).
// Throw spdlog_ex exception on errors.
#include "spdlog/details/log_msg.h"
#include "spdlog/details/os.h"
#include <cerrno>
#include <chrono>
#include <cstdio>
#include <string>
#include <thread>
#include <tuple>
namespace spdlog {
namespace details {
class file_helper
{
public:
const int open_tries = 5;
const int open_interval = 10;
explicit file_helper() = default;
file_helper(const file_helper &) = delete;
file_helper &operator=(const file_helper &) = delete;
~file_helper()
{
close();
}
void open(const filename_t &fname, bool truncate = false)
{
close();
auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab");
_filename = fname;
for (int tries = 0; tries < open_tries; ++tries)
{
if (!os::fopen_s(&fd_, fname, mode))
{
return;
}
details::os::sleep_for_millis(open_interval);
}
throw spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno);
}
void reopen(bool truncate)
{
if (_filename.empty())
{
throw spdlog_ex("Failed re opening file - was not opened before");
}
open(_filename, truncate);
}
void flush()
{
std::fflush(fd_);
}
void close()
{
if (fd_ != nullptr)
{
std::fclose(fd_);
fd_ = nullptr;
}
}
void write(const fmt::memory_buffer &buf)
{
size_t msg_size = buf.size();
auto data = buf.data();
if (std::fwrite(data, 1, msg_size, fd_) != msg_size)
{
throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno);
}
}
size_t size() const
{
if (fd_ == nullptr)
{
throw spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename));
}
return os::filesize(fd_);
}
const filename_t &filename() const
{
return _filename;
}
static bool file_exists(const filename_t &fname)
{
return os::file_exists(fname);
}
//
// return file path and its extension:
//
// "mylog.txt" => ("mylog", ".txt")
// "mylog" => ("mylog", "")
// "mylog." => ("mylog.", "")
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
//
// the starting dot in filenames is ignored (hidden files):
//
// ".mylog" => (".mylog". "")
// "my_folder/.mylog" => ("my_folder/.mylog", "")
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
static std::tuple<filename_t, filename_t> split_by_extenstion(const spdlog::filename_t &fname)
{
auto ext_index = fname.rfind('.');
// no valid extension found - return whole path and empty string as
// extension
if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1)
{
return std::make_tuple(fname, spdlog::filename_t());
}
// treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
auto folder_index = fname.rfind(details::os::folder_sep);
if (folder_index != filename_t::npos && folder_index >= ext_index - 1)
{
return std::make_tuple(fname, spdlog::filename_t());
}
// finally - return a valid base and extension tuple
return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
}
private:
std::FILE *fd_{nullptr};
filename_t _filename;
};
} // namespace details
} // namespace spdlog
+127
View File
@@ -0,0 +1,127 @@
//
// Created by gabi on 6/15/18.
//
#pragma once
#include "chrono"
#include "spdlog/fmt/fmt.h"
// Some fmt helpers to efficiently format and pad ints and strings
namespace spdlog {
namespace details {
namespace fmt_helper {
template<size_t Buffer_Size>
inline void append_str(const std::string &str, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
{
auto *str_ptr = str.data();
dest.append(str_ptr, str_ptr + str.size());
}
template<size_t Buffer_Size>
inline void append_c_str(const char *c_str, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
{
auto len = std::char_traits<char>::length(c_str);
dest.append(c_str, c_str + len);
}
template<size_t Buffer_Size1, size_t Buffer_Size2>
inline void append_buf(const fmt::basic_memory_buffer<char, Buffer_Size1> &buf, fmt::basic_memory_buffer<char, Buffer_Size2> &dest)
{
auto *buf_ptr = buf.data();
dest.append(buf_ptr, buf_ptr + buf.size());
}
template<typename T, size_t Buffer_Size>
inline void append_int(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
{
fmt::format_int i(n);
dest.append(i.data(), i.data() + i.size());
}
template<size_t Buffer_Size>
inline void pad2(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
{
if (n > 99)
{
append_int(n, dest);
return;
}
if (n > 9) // 10-99
{
dest.push_back(static_cast<char>('0' + n / 10));
dest.push_back(static_cast<char>('0' + n % 10));
return;
}
if (n >= 0) // 0-9
{
dest.push_back('0');
dest.push_back(static_cast<char>('0' + n));
return;
}
// negatives (unlikely, but just in case, let fmt deal with it)
fmt::format_to(dest, "{:02}", n);
}
template<size_t Buffer_Size>
inline void pad3(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
{
if (n > 999)
{
append_int(n, dest);
return;
}
if (n > 99) // 100-999
{
dest.push_back(static_cast<char>('0' + n / 100));
pad2(n % 100, dest);
return;
}
if (n > 9) // 10-99
{
dest.push_back('0');
dest.push_back(static_cast<char>('0' + n / 10));
dest.push_back(static_cast<char>('0' + n % 10));
return;
}
if (n >= 0)
{
dest.push_back('0');
dest.push_back('0');
dest.push_back(static_cast<char>('0' + n));
return;
}
// negatives (unlikely, but just in case let fmt deal with it)
fmt::format_to(dest, "{:03}", n);
}
template<size_t Buffer_Size>
inline void pad6(size_t n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
{
if (n > 99999)
{
append_int(n, dest);
return;
}
pad3(static_cast<int>(n / 1000), dest);
pad3(static_cast<int>(n % 1000), dest);
}
// return fraction of a second of the given time_point.
// e.g.
// fraction<std::milliseconds>(tp) -> will return the millis part of the second
template<typename ToDuration>
inline ToDuration time_fraction(const log_clock::time_point &tp)
{
using std::chrono::duration_cast;
using std::chrono::seconds;
auto duration = tp.time_since_epoch();
auto secs = duration_cast<seconds>(duration);
return duration_cast<ToDuration>(duration) - duration_cast<ToDuration>(secs);
}
} // namespace fmt_helper
} // namespace details
} // namespace spdlog
+49
View File
@@ -0,0 +1,49 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/common.h"
#include "spdlog/details/os.h"
#include <string>
#include <utility>
namespace spdlog {
namespace details {
struct log_msg
{
log_msg() = default;
log_msg(const std::string *loggers_name, level::level_enum lvl)
: logger_name(loggers_name)
, level(lvl)
#ifndef SPDLOG_NO_DATETIME
, time(os::now())
#endif
#ifndef SPDLOG_NO_THREAD_ID
, thread_id(os::thread_id())
#endif
{
}
log_msg(const log_msg &other) = delete;
log_msg(log_msg &&other) = delete;
log_msg &operator=(log_msg &&other) = delete;
const std::string *logger_name{nullptr};
level::level_enum level;
log_clock::time_point time;
size_t thread_id;
fmt::memory_buffer raw;
size_t msg_id;
// info about wrapping the formatted text with color (updated by pattern_formatter).
mutable size_t color_range_start{0};
mutable size_t color_range_end{0};
};
} // namespace details
} // namespace spdlog
+383
View File
@@ -0,0 +1,383 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/fmt_helper.h"
#include <memory>
#include <string>
// create logger with given name, sinks and the default pattern formatter
// all other ctors will call this one
template<typename It>
inline spdlog::logger::logger(std::string logger_name, It begin, It end)
: name_(std::move(logger_name))
, sinks_(begin, end)
, level_(level::info)
, flush_level_(level::off)
, last_err_time_(0)
, msg_counter_(1) // message counter will start from 1. 0-message id will be
// reserved for controll messages
{
err_handler_ = [this](const std::string &msg) { this->default_err_handler_(msg); };
}
// ctor with sinks as init list
inline spdlog::logger::logger(std::string logger_name, sinks_init_list sinks_list)
: logger(std::move(logger_name), sinks_list.begin(), sinks_list.end())
{
}
// ctor with single sink
inline spdlog::logger::logger(std::string logger_name, spdlog::sink_ptr single_sink)
: logger(std::move(logger_name), {std::move(single_sink)})
{
}
inline spdlog::logger::~logger() = default;
inline void spdlog::logger::set_formatter(std::unique_ptr<spdlog::formatter> f)
{
for (auto &sink : sinks_)
{
sink->set_formatter(f->clone());
}
}
inline void spdlog::logger::set_pattern(std::string pattern, pattern_time_type time_type)
{
auto new_formatter = details::make_unique<spdlog::pattern_formatter>(std::move(pattern), time_type);
set_formatter(std::move(new_formatter));
}
template<typename... Args>
inline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Args &... args)
{
if (!should_log(lvl))
{
return;
}
try
{
details::log_msg log_msg(&name_, lvl);
fmt::format_to(log_msg.raw, fmt, args...);
sink_it_(log_msg);
}
SPDLOG_CATCH_AND_HANDLE
}
template<typename... Args>
inline void spdlog::logger::log(level::level_enum lvl, const char *msg)
{
if (!should_log(lvl))
{
return;
}
try
{
details::log_msg log_msg(&name_, lvl);
details::fmt_helper::append_c_str(msg, log_msg.raw);
sink_it_(log_msg);
}
SPDLOG_CATCH_AND_HANDLE
}
template<typename T>
inline void spdlog::logger::log(level::level_enum lvl, const T &msg)
{
if (!should_log(lvl))
{
return;
}
try
{
details::log_msg log_msg(&name_, lvl);
fmt::format_to(log_msg.raw, "{}", msg);
sink_it_(log_msg);
}
SPDLOG_CATCH_AND_HANDLE
}
template<typename... Args>
inline void spdlog::logger::trace(const char *fmt, const Args &... args)
{
log(level::trace, fmt, args...);
}
template<typename... Args>
inline void spdlog::logger::debug(const char *fmt, const Args &... args)
{
log(level::debug, fmt, args...);
}
template<typename... Args>
inline void spdlog::logger::info(const char *fmt, const Args &... args)
{
log(level::info, fmt, args...);
}
template<typename... Args>
inline void spdlog::logger::warn(const char *fmt, const Args &... args)
{
log(level::warn, fmt, args...);
}
template<typename... Args>
inline void spdlog::logger::error(const char *fmt, const Args &... args)
{
log(level::err, fmt, args...);
}
template<typename... Args>
inline void spdlog::logger::critical(const char *fmt, const Args &... args)
{
log(level::critical, fmt, args...);
}
template<typename T>
inline void spdlog::logger::trace(const T &msg)
{
log(level::trace, msg);
}
template<typename T>
inline void spdlog::logger::debug(const T &msg)
{
log(level::debug, msg);
}
template<typename T>
inline void spdlog::logger::info(const T &msg)
{
log(level::info, msg);
}
template<typename T>
inline void spdlog::logger::warn(const T &msg)
{
log(level::warn, msg);
}
template<typename T>
inline void spdlog::logger::error(const T &msg)
{
log(level::err, msg);
}
template<typename T>
inline void spdlog::logger::critical(const T &msg)
{
log(level::critical, msg);
}
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
inline void wbuf_to_utf8buf(const fmt::wmemory_buffer &wbuf, fmt::memory_buffer &target)
{
int wbuf_size = static_cast<int>(wbuf.size());
if (wbuf_size == 0)
{
return;
}
auto result_size = ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, NULL, 0, NULL, NULL);
if (result_size > 0)
{
target.resize(result_size);
::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, &target.data()[0], result_size, NULL, NULL);
}
else
{
throw spdlog::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
}
}
template<typename... Args>
inline void spdlog::logger::log(level::level_enum lvl, const wchar_t *fmt, const Args &... args)
{
if (!should_log(lvl))
{
return;
}
try
{
// format to wmemory_buffer and convert to utf8
details::log_msg log_msg(&name_, lvl);
fmt::wmemory_buffer wbuf;
fmt::format_to(wbuf, fmt, args...);
wbuf_to_utf8buf(wbuf, log_msg.raw);
sink_it_(log_msg);
}
SPDLOG_CATCH_AND_HANDLE
}
template<typename... Args>
inline void spdlog::logger::trace(const wchar_t *fmt, const Args &... args)
{
log(level::trace, fmt, args...);
}
template<typename... Args>
inline void spdlog::logger::debug(const wchar_t *fmt, const Args &... args)
{
log(level::debug, fmt, args...);
}
template<typename... Args>
inline void spdlog::logger::info(const wchar_t *fmt, const Args &... args)
{
log(level::info, fmt, args...);
}
template<typename... Args>
inline void spdlog::logger::warn(const wchar_t *fmt, const Args &... args)
{
log(level::warn, fmt, args...);
}
template<typename... Args>
inline void spdlog::logger::error(const wchar_t *fmt, const Args &... args)
{
log(level::err, fmt, args...);
}
template<typename... Args>
inline void spdlog::logger::critical(const wchar_t *fmt, const Args &... args)
{
log(level::critical, fmt, args...);
}
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
//
// name and level
//
inline const std::string &spdlog::logger::name() const
{
return name_;
}
inline void spdlog::logger::set_level(spdlog::level::level_enum log_level)
{
level_.store(log_level);
}
inline void spdlog::logger::set_error_handler(spdlog::log_err_handler err_handler)
{
err_handler_ = std::move(err_handler);
}
inline spdlog::log_err_handler spdlog::logger::error_handler()
{
return err_handler_;
}
inline void spdlog::logger::flush()
{
try
{
flush_();
}
SPDLOG_CATCH_AND_HANDLE
}
inline void spdlog::logger::flush_on(level::level_enum log_level)
{
flush_level_.store(log_level);
}
inline spdlog::level::level_enum spdlog::logger::flush_level() const
{
return static_cast<spdlog::level::level_enum>(flush_level_.load(std::memory_order_relaxed));
}
inline bool spdlog::logger::should_flush_(const details::log_msg &msg)
{
auto flush_level = flush_level_.load(std::memory_order_relaxed);
return (msg.level >= flush_level) && (msg.level != level::off);
}
inline spdlog::level::level_enum spdlog::logger::level() const
{
return static_cast<spdlog::level::level_enum>(level_.load(std::memory_order_relaxed));
}
inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const
{
return msg_level >= level_.load(std::memory_order_relaxed);
}
//
// protected virtual called at end of each user log call (if enabled) by the
// line_logger
//
inline void spdlog::logger::sink_it_(details::log_msg &msg)
{
#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)
incr_msg_counter_(msg);
#endif
for (auto &sink : sinks_)
{
if (sink->should_log(msg.level))
{
sink->log(msg);
}
}
if (should_flush_(msg))
{
flush();
}
}
inline void spdlog::logger::flush_()
{
for (auto &sink : sinks_)
{
sink->flush();
}
}
inline void spdlog::logger::default_err_handler_(const std::string &msg)
{
auto now = time(nullptr);
if (now - last_err_time_ < 60)
{
return;
}
last_err_time_ = now;
auto tm_time = details::os::localtime(now);
char date_buf[100];
std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time);
fmt::print(stderr, "[*** LOG ERROR ***] [{}] [{}] {}\n", date_buf, name(), msg);
}
inline void spdlog::logger::incr_msg_counter_(details::log_msg &msg)
{
msg.msg_id = msg_counter_.fetch_add(1, std::memory_order_relaxed);
}
inline const std::vector<spdlog::sink_ptr> &spdlog::logger::sinks() const
{
return sinks_;
}
inline std::vector<spdlog::sink_ptr> &spdlog::logger::sinks()
{
return sinks_;
}
inline std::shared_ptr<spdlog::logger> spdlog::logger::clone(std::string logger_name)
{
auto cloned = std::make_shared<spdlog::logger>(std::move(logger_name), sinks_.begin(), sinks_.end());
cloned->set_level(this->level());
cloned->flush_on(this->flush_level());
cloned->set_error_handler(this->error_handler());
return cloned;
}
+121
View File
@@ -0,0 +1,121 @@
#pragma once
//
// Copyright(c) 2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
// multi producer-multi consumer blocking queue.
// enqueue(..) - will block until room found to put the new message.
// enqueue_nowait(..) - will return immediately with false if no room left in
// the queue.
// dequeue_for(..) - will block until the queue is not empty or timeout have
// passed.
#include "spdlog/details/circular_q.h"
#include <condition_variable>
#include <mutex>
namespace spdlog {
namespace details {
template<typename T>
class mpmc_blocking_queue
{
public:
using item_type = T;
explicit mpmc_blocking_queue(size_t max_items)
: q_(max_items)
{
}
#ifndef __MINGW32__
// try to enqueue and block if no room left
void enqueue(T &&item)
{
{
std::unique_lock<std::mutex> lock(queue_mutex_);
pop_cv_.wait(lock, [this] { return !this->q_.full(); });
q_.push_back(std::move(item));
}
push_cv_.notify_one();
}
// enqueue immediately. overrun oldest message in the queue if no room left.
void enqueue_nowait(T &&item)
{
{
std::unique_lock<std::mutex> lock(queue_mutex_);
q_.push_back(std::move(item));
}
push_cv_.notify_one();
}
// try to dequeue item. if no item found. wait upto timeout and try again
// Return true, if succeeded dequeue item, false otherwise
bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration)
{
{
std::unique_lock<std::mutex> lock(queue_mutex_);
if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); }))
{
return false;
}
q_.pop_front(popped_item);
}
pop_cv_.notify_one();
return true;
}
#else
// apparently mingw deadlocks if the mutex is released before cv.notify_one(),
// so release the mutex at the very end each function.
// try to enqueue and block if no room left
void enqueue(T &&item)
{
std::unique_lock<std::mutex> lock(queue_mutex_);
pop_cv_.wait(lock, [this] { return !this->q_.full(); });
q_.push_back(std::move(item));
push_cv_.notify_one();
}
// enqueue immediately. overrun oldest message in the queue if no room left.
void enqueue_nowait(T &&item)
{
std::unique_lock<std::mutex> lock(queue_mutex_);
q_.push_back(std::move(item));
push_cv_.notify_one();
}
// try to dequeue item. if no item found. wait upto timeout and try again
// Return true, if succeeded dequeue item, false otherwise
bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration)
{
std::unique_lock<std::mutex> lock(queue_mutex_);
if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); }))
{
return false;
}
q_.pop_front(popped_item);
pop_cv_.notify_one();
return true;
}
#endif
size_t overrun_counter()
{
std::unique_lock<std::mutex> lock(queue_mutex_);
return q_.overrun_counter();
}
private:
std::mutex queue_mutex_;
std::condition_variable push_cv_;
std::condition_variable pop_cv_;
spdlog::details::circular_q<T> q_;
};
} // namespace details
} // namespace spdlog
+45
View File
@@ -0,0 +1,45 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <atomic>
// null, no cost dummy "mutex" and dummy "atomic" int
namespace spdlog {
namespace details {
struct null_mutex
{
void lock() {}
void unlock() {}
bool try_lock()
{
return true;
}
};
struct null_atomic_int
{
int value;
null_atomic_int() = default;
explicit null_atomic_int(int val)
: value(val)
{
}
int load(std::memory_order) const
{
return value;
}
void store(int val)
{
value = val;
}
};
} // namespace details
} // namespace spdlog
+422
View File
@@ -0,0 +1,422 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/common.h"
#include <algorithm>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <functional>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <thread>
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX // prevent windows redefining min/max
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <io.h> // _get_osfhandle and _isatty support
#include <process.h> // _get_pid support
#include <windows.h>
#ifdef __MINGW32__
#include <share.h>
#endif
#else // unix
#include <fcntl.h>
#include <unistd.h>
#ifdef __linux__
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
#elif __FreeBSD__
#include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id
#endif
#endif // unix
#ifndef __has_feature // Clang - feature checking macros.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
namespace spdlog {
namespace details {
namespace os {
inline spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT
{
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
timespec ts;
::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
return std::chrono::time_point<log_clock, typename log_clock::duration>(
std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
#else
return log_clock::now();
#endif
}
inline std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
{
#ifdef _WIN32
std::tm tm;
localtime_s(&tm, &time_tt);
#else
std::tm tm;
localtime_r(&time_tt, &tm);
#endif
return tm;
}
inline std::tm localtime() SPDLOG_NOEXCEPT
{
std::time_t now_t = time(nullptr);
return localtime(now_t);
}
inline std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
{
#ifdef _WIN32
std::tm tm;
gmtime_s(&tm, &time_tt);
#else
std::tm tm;
gmtime_r(&time_tt, &tm);
#endif
return tm;
}
inline std::tm gmtime() SPDLOG_NOEXCEPT
{
std::time_t now_t = time(nullptr);
return gmtime(now_t);
}
// eol definition
#if !defined(SPDLOG_EOL)
#ifdef _WIN32
#define SPDLOG_EOL "\r\n"
#else
#define SPDLOG_EOL "\n"
#endif
#endif
SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL;
// folder separator
#ifdef _WIN32
SPDLOG_CONSTEXPR static const char folder_sep = '\\';
#else
SPDLOG_CONSTEXPR static const char folder_sep = '/';
#endif
inline void prevent_child_fd(FILE *f)
{
#ifdef _WIN32
#if !defined(__cplusplus_winrt)
auto file_handle = (HANDLE)_get_osfhandle(_fileno(f));
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
throw spdlog_ex("SetHandleInformation failed", errno);
#endif
#else
auto fd = fileno(f);
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
{
throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno);
}
#endif
}
// fopen_s on non windows for writing
inline bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
{
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
*fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
#else
*fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
#endif
#else // unix
*fp = fopen((filename.c_str()), mode.c_str());
#endif
#ifdef SPDLOG_PREVENT_CHILD_FD
if (*fp != nullptr)
{
prevent_child_fd(*fp);
}
#endif
return *fp == nullptr;
}
inline int remove(const filename_t &filename) SPDLOG_NOEXCEPT
{
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return _wremove(filename.c_str());
#else
return std::remove(filename.c_str());
#endif
}
inline int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT
{
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return _wrename(filename1.c_str(), filename2.c_str());
#else
return std::rename(filename1.c_str(), filename2.c_str());
#endif
}
// Return if file exists
inline bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT
{
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
auto attribs = GetFileAttributesW(filename.c_str());
#else
auto attribs = GetFileAttributesA(filename.c_str());
#endif
return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
#else // common linux/unix all have the stat system call
struct stat buffer;
return (stat(filename.c_str(), &buffer) == 0);
#endif
}
// Return file size according to open FILE* object
inline size_t filesize(FILE *f)
{
if (f == nullptr)
{
throw spdlog_ex("Failed getting file size. fd is null");
}
#if defined(_WIN32) && !defined(__CYGWIN__)
int fd = _fileno(f);
#if _WIN64 // 64 bits
struct _stat64 st;
if (_fstat64(fd, &st) == 0)
{
return st.st_size;
}
#else // windows 32 bits
long ret = _filelength(fd);
if (ret >= 0)
{
return static_cast<size_t>(ret);
}
#endif
#else // unix
int fd = fileno(f);
// 64 bits(but not in osx or cygwin, where fstat64 is deprecated)
#if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__)
struct stat64 st;
if (fstat64(fd, &st) == 0)
{
return static_cast<size_t>(st.st_size);
}
#else // unix 32 bits or cygwin
struct stat st;
if (fstat(fd, &st) == 0)
{
return static_cast<size_t>(st.st_size);
}
#endif
#endif
throw spdlog_ex("Failed getting file size from fd", errno);
}
// Return utc offset in minutes or throw spdlog_ex on failure
inline int utc_minutes_offset(const std::tm &tm = details::os::localtime())
{
#ifdef _WIN32
#if _WIN32_WINNT < _WIN32_WINNT_WS08
TIME_ZONE_INFORMATION tzinfo;
auto rv = GetTimeZoneInformation(&tzinfo);
#else
DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
auto rv = GetDynamicTimeZoneInformation(&tzinfo);
#endif
if (rv == TIME_ZONE_ID_INVALID)
throw spdlog::spdlog_ex("Failed getting timezone info. ", errno);
int offset = -tzinfo.Bias;
if (tm.tm_isdst)
{
offset -= tzinfo.DaylightBias;
}
else
{
offset -= tzinfo.StandardBias;
}
return offset;
#else
#if defined(sun) || defined(__sun) || defined(_AIX)
// 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
struct helper
{
static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime())
{
int local_year = localtm.tm_year + (1900 - 1);
int gmt_year = gmtm.tm_year + (1900 - 1);
long int days = (
// difference in day of year
localtm.tm_yday -
gmtm.tm_yday
// + intervening leap days
+ ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +
((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
// + difference in years * 365 */
+ (long int)(local_year - gmt_year) * 365);
long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);
return secs;
}
};
auto offset_seconds = helper::calculate_gmt_offset(tm);
#else
auto offset_seconds = tm.tm_gmtoff;
#endif
return static_cast<int>(offset_seconds / 60);
#endif
}
// Return current thread id as size_t
// It exists because the std::this_thread::get_id() is much slower(especially
// under VS 2013)
inline size_t _thread_id() SPDLOG_NOEXCEPT
{
#ifdef _WIN32
return static_cast<size_t>(::GetCurrentThreadId());
#elif __linux__
#if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
#define SYS_gettid __NR_gettid
#endif
return static_cast<size_t>(syscall(SYS_gettid));
#elif __FreeBSD__
long tid;
thr_self(&tid);
return static_cast<size_t>(tid);
#elif __APPLE__
uint64_t tid;
pthread_threadid_np(nullptr, &tid);
return static_cast<size_t>(tid);
#else // Default to standard C++11 (other Unix)
return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
#endif
}
// Return current thread id as size_t (from thread local storage)
inline size_t thread_id() SPDLOG_NOEXCEPT
{
#if defined(SPDLOG_DISABLE_TID_CACHING) || (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt) || \
(defined(__clang__) && !__has_feature(cxx_thread_local))
return _thread_id();
#else // cache thread id in tls
static thread_local const size_t tid = _thread_id();
return tid;
#endif
}
// This is avoid msvc issue in sleep_for that happens if the clock changes.
// See https://github.com/gabime/spdlog/issues/609
inline void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT
{
#if defined(_WIN32)
::Sleep(milliseconds);
#else
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
#endif
}
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
#define SPDLOG_FILENAME_T(s) L##s
inline std::string filename_to_str(const filename_t &filename)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c;
return c.to_bytes(filename);
}
#else
#define SPDLOG_FILENAME_T(s) s
inline std::string filename_to_str(const filename_t &filename)
{
return filename;
}
#endif
inline int pid()
{
#ifdef _WIN32
return static_cast<int>(::GetCurrentProcessId());
#else
return static_cast<int>(::getpid());
#endif
}
// Determine if the terminal supports colors
// Source: https://github.com/agauniyal/rang/
inline bool is_color_terminal() SPDLOG_NOEXCEPT
{
#ifdef _WIN32
return true;
#else
static constexpr const char *Terms[] = {
"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"};
const char *env_p = std::getenv("TERM");
if (env_p == nullptr)
{
return false;
}
static const bool result =
std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; });
return result;
#endif
}
// Detrmine if the terminal attached
// Source: https://github.com/agauniyal/rang/
inline bool in_terminal(FILE *file) SPDLOG_NOEXCEPT
{
#ifdef _WIN32
return _isatty(_fileno(file)) != 0;
#else
return isatty(fileno(file)) != 0;
#endif
}
} // namespace os
} // namespace details
} // namespace spdlog
+774
View File
@@ -0,0 +1,774 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/fmt_helper.h"
#include "spdlog/details/log_msg.h"
#include "spdlog/details/os.h"
#include "spdlog/fmt/fmt.h"
#include "spdlog/formatter.h"
#include <array>
#include <chrono>
#include <ctime>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <utility>
#include <vector>
namespace spdlog {
namespace details {
class flag_formatter
{
public:
virtual ~flag_formatter() = default;
virtual void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) = 0;
};
///////////////////////////////////////////////////////////////////////
// name & level pattern appenders
///////////////////////////////////////////////////////////////////////
class name_formatter : public flag_formatter
{
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
fmt_helper::append_str(*msg.logger_name, dest);
}
};
// log level appender
class level_formatter : public flag_formatter
{
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
fmt_helper::append_c_str(level::to_c_str(msg.level), dest);
}
};
// short log level appender
class short_level_formatter : public flag_formatter
{
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
fmt_helper::append_c_str(level::to_short_c_str(msg.level), dest);
}
};
///////////////////////////////////////////////////////////////////////
// Date time pattern appenders
///////////////////////////////////////////////////////////////////////
static const char *ampm(const tm &t)
{
return t.tm_hour >= 12 ? "PM" : "AM";
}
static int to12h(const tm &t)
{
return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour;
}
// Abbreviated weekday name
static const char *days[]{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
class a_formatter : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::append_c_str(days[tm_time.tm_wday], dest);
}
};
// Full weekday name
static const char *full_days[]{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
class A_formatter : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::append_c_str(full_days[tm_time.tm_wday], dest);
}
};
// Abbreviated month
static const char *months[]{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"};
class b_formatter : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::append_c_str(months[tm_time.tm_mon], dest);
}
};
// Full month name
static const char *full_months[]{
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
class B_formatter : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::append_c_str(full_months[tm_time.tm_mon], dest);
}
};
// Date and time representation (Thu Aug 23 15:35:46 2014)
class c_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
// fmt::format_to(dest, "{} {} {} ", days[tm_time.tm_wday],
// months[tm_time.tm_mon], tm_time.tm_mday);
// date
fmt_helper::append_str(days[tm_time.tm_wday], dest);
dest.push_back(' ');
fmt_helper::append_str(months[tm_time.tm_mon], dest);
dest.push_back(' ');
fmt_helper::append_int(tm_time.tm_mday, dest);
dest.push_back(' ');
// time
fmt_helper::pad2(tm_time.tm_hour, dest);
dest.push_back(':');
fmt_helper::pad2(tm_time.tm_min, dest);
dest.push_back(':');
fmt_helper::pad2(tm_time.tm_sec, dest);
dest.push_back(' ');
fmt_helper::append_int(tm_time.tm_year + 1900, dest);
}
};
// year - 2 digit
class C_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::pad2(tm_time.tm_year % 100, dest);
}
};
// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01
class D_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::pad2(tm_time.tm_mon + 1, dest);
dest.push_back('/');
fmt_helper::pad2(tm_time.tm_mday, dest);
dest.push_back('/');
fmt_helper::pad2(tm_time.tm_year % 100, dest);
}
};
// year - 4 digit
class Y_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::append_int(tm_time.tm_year + 1900, dest);
}
};
// month 1-12
class m_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::pad2(tm_time.tm_mon + 1, dest);
}
};
// day of month 1-31
class d_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::pad2(tm_time.tm_mday, dest);
}
};
// hours in 24 format 0-23
class H_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::pad2(tm_time.tm_hour, dest);
}
};
// hours in 12 format 1-12
class I_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::pad2(to12h(tm_time), dest);
}
};
// minutes 0-59
class M_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::pad2(tm_time.tm_min, dest);
}
};
// seconds 0-59
class S_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::pad2(tm_time.tm_sec, dest);
}
};
// milliseconds
class e_formatter final : public flag_formatter
{
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
auto millis = fmt_helper::time_fraction<std::chrono::milliseconds>(msg.time);
fmt_helper::pad3(static_cast<int>(millis.count()), dest);
}
};
// microseconds
class f_formatter final : public flag_formatter
{
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
auto micros = fmt_helper::time_fraction<std::chrono::microseconds>(msg.time);
fmt_helper::pad6(static_cast<size_t>(micros.count()), dest);
}
};
// nanoseconds
class F_formatter final : public flag_formatter
{
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
auto ns = fmt_helper::time_fraction<std::chrono::nanoseconds>(msg.time);
fmt::format_to(dest, "{:09}", ns.count());
}
};
// seconds since epoch
class E_formatter final : public flag_formatter
{
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
auto duration = msg.time.time_since_epoch();
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
fmt_helper::append_int(seconds, dest);
}
};
// AM/PM
class p_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::append_c_str(ampm(tm_time), dest);
}
};
// 12 hour clock 02:55:02 pm
class r_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::pad2(to12h(tm_time), dest);
dest.push_back(':');
fmt_helper::pad2(tm_time.tm_min, dest);
dest.push_back(':');
fmt_helper::pad2(tm_time.tm_sec, dest);
dest.push_back(' ');
fmt_helper::append_c_str(ampm(tm_time), dest);
}
};
// 24-hour HH:MM time, equivalent to %H:%M
class R_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
fmt_helper::pad2(tm_time.tm_hour, dest);
dest.push_back(':');
fmt_helper::pad2(tm_time.tm_min, dest);
}
};
// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S
class T_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
// fmt::format_to(dest, "{:02}:{:02}:{:02}", tm_time.tm_hour,
// tm_time.tm_min, tm_time.tm_sec);
fmt_helper::pad2(tm_time.tm_hour, dest);
dest.push_back(':');
fmt_helper::pad2(tm_time.tm_min, dest);
dest.push_back(':');
fmt_helper::pad2(tm_time.tm_sec, dest);
}
};
// ISO 8601 offset from UTC in timezone (+-HH:MM)
class z_formatter final : public flag_formatter
{
public:
const std::chrono::seconds cache_refresh = std::chrono::seconds(5);
z_formatter() = default;
z_formatter(const z_formatter &) = delete;
z_formatter &operator=(const z_formatter &) = delete;
void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
#ifdef _WIN32
int total_minutes = get_cached_offset(msg, tm_time);
#else
// No need to chache under gcc,
// it is very fast (already stored in tm.tm_gmtoff)
(void)(msg);
int total_minutes = os::utc_minutes_offset(tm_time);
#endif
bool is_negative = total_minutes < 0;
if (is_negative)
{
total_minutes = -total_minutes;
dest.push_back('-');
}
else
{
dest.push_back('+');
}
fmt_helper::pad2(total_minutes / 60, dest); // hours
dest.push_back(':');
fmt_helper::pad2(total_minutes % 60, dest); // minutes
}
private:
log_clock::time_point last_update_{std::chrono::seconds(0)};
#ifdef _WIN32
int offset_minutes_{0};
int get_cached_offset(const log_msg &msg, const std::tm &tm_time)
{
if (msg.time - last_update_ >= cache_refresh)
{
offset_minutes_ = os::utc_minutes_offset(tm_time);
last_update_ = msg.time;
}
return offset_minutes_;
}
#endif
};
// Thread id
class t_formatter final : public flag_formatter
{
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
fmt_helper::pad6(msg.thread_id, dest);
}
};
// Current pid
class pid_formatter final : public flag_formatter
{
void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override
{
fmt_helper::append_int(details::os::pid(), dest);
}
};
// message counter formatter
class i_formatter final : public flag_formatter
{
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
fmt_helper::pad6(msg.msg_id, dest);
}
};
class v_formatter final : public flag_formatter
{
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
fmt_helper::append_buf(msg.raw, dest);
}
};
class ch_formatter final : public flag_formatter
{
public:
explicit ch_formatter(char ch)
: ch_(ch)
{
}
void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override
{
dest.push_back(ch_);
}
private:
char ch_;
};
// aggregate user chars to display as is
class aggregate_formatter final : public flag_formatter
{
public:
aggregate_formatter() = default;
void add_ch(char ch)
{
str_ += ch;
}
void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override
{
fmt_helper::append_str(str_, dest);
}
private:
std::string str_;
};
// mark the color range. expect it to be in the form of "%^colored text%$"
class color_start_formatter final : public flag_formatter
{
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
msg.color_range_start = dest.size();
}
};
class color_stop_formatter final : public flag_formatter
{
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
msg.color_range_end = dest.size();
}
};
// Full info formatter
// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
class full_formatter final : public flag_formatter
{
void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
using std::chrono::duration_cast;
using std::chrono::milliseconds;
using std::chrono::seconds;
#ifndef SPDLOG_NO_DATETIME
// cache the date/time part for the next second.
auto duration = msg.time.time_since_epoch();
auto secs = duration_cast<seconds>(duration);
if (cache_timestamp_ != secs || cached_datetime_.size() == 0)
{
cached_datetime_.clear();
cached_datetime_.push_back('[');
fmt_helper::append_int(tm_time.tm_year + 1900, cached_datetime_);
cached_datetime_.push_back('-');
fmt_helper::pad2(tm_time.tm_mon + 1, cached_datetime_);
cached_datetime_.push_back('-');
fmt_helper::pad2(tm_time.tm_mday, cached_datetime_);
cached_datetime_.push_back(' ');
fmt_helper::pad2(tm_time.tm_hour, cached_datetime_);
cached_datetime_.push_back(':');
fmt_helper::pad2(tm_time.tm_min, cached_datetime_);
cached_datetime_.push_back(':');
fmt_helper::pad2(tm_time.tm_sec, cached_datetime_);
cached_datetime_.push_back('.');
cache_timestamp_ = secs;
}
fmt_helper::append_buf(cached_datetime_, dest);
auto millis = fmt_helper::time_fraction<milliseconds>(msg.time);
fmt_helper::pad3(static_cast<int>(millis.count()), dest);
dest.push_back(']');
dest.push_back(' ');
#else // no datetime needed
(void)tm_time;
#endif
#ifndef SPDLOG_NO_NAME
dest.push_back('[');
fmt_helper::append_str(*msg.logger_name, dest);
dest.push_back(']');
dest.push_back(' ');
#endif
dest.push_back('[');
// wrap the level name with color
msg.color_range_start = dest.size();
fmt_helper::append_c_str(level::to_c_str(msg.level), dest);
msg.color_range_end = dest.size();
dest.push_back(']');
dest.push_back(' ');
fmt_helper::append_buf(msg.raw, dest);
}
private:
std::chrono::seconds cache_timestamp_{0};
fmt::basic_memory_buffer<char, 128> cached_datetime_;
};
} // namespace details
class pattern_formatter final : public formatter
{
public:
explicit pattern_formatter(
std::string pattern, pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol)
: pattern_(std::move(pattern))
, eol_(std::move(eol))
, pattern_time_type_(time_type)
, last_log_secs_(0)
{
std::memset(&cached_tm_, 0, sizeof(cached_tm_));
compile_pattern_(pattern_);
}
pattern_formatter(const pattern_formatter &other) = delete;
pattern_formatter &operator=(const pattern_formatter &other) = delete;
std::unique_ptr<formatter> clone() const override
{
return details::make_unique<pattern_formatter>(pattern_, pattern_time_type_, eol_);
}
void format(const details::log_msg &msg, fmt::memory_buffer &dest) override
{
#ifndef SPDLOG_NO_DATETIME
auto secs = std::chrono::duration_cast<std::chrono::seconds>(msg.time.time_since_epoch());
if (secs != last_log_secs_)
{
cached_tm_ = get_time_(msg);
last_log_secs_ = secs;
}
#endif
for (auto &f : formatters_)
{
f->format(msg, cached_tm_, dest);
}
// write eol
details::fmt_helper::append_str(eol_, dest);
}
private:
std::string pattern_;
std::string eol_;
pattern_time_type pattern_time_type_;
std::tm cached_tm_;
std::chrono::seconds last_log_secs_;
std::vector<std::unique_ptr<details::flag_formatter>> formatters_;
std::tm get_time_(const details::log_msg &msg)
{
if (pattern_time_type_ == pattern_time_type::local)
{
return details::os::localtime(log_clock::to_time_t(msg.time));
}
return details::os::gmtime(log_clock::to_time_t(msg.time));
}
void handle_flag_(char flag)
{
switch (flag)
{
// logger name
case 'n':
formatters_.push_back(details::make_unique<details::name_formatter>());
break;
case 'l':
formatters_.push_back(details::make_unique<details::level_formatter>());
break;
case 'L':
formatters_.push_back(details::make_unique<details::short_level_formatter>());
break;
case ('t'):
formatters_.push_back(details::make_unique<details::t_formatter>());
break;
case ('v'):
formatters_.push_back(details::make_unique<details::v_formatter>());
break;
case ('a'):
formatters_.push_back(details::make_unique<details::a_formatter>());
break;
case ('A'):
formatters_.push_back(details::make_unique<details::A_formatter>());
break;
case ('b'):
case ('h'):
formatters_.push_back(details::make_unique<details::b_formatter>());
break;
case ('B'):
formatters_.push_back(details::make_unique<details::B_formatter>());
break;
case ('c'):
formatters_.push_back(details::make_unique<details::c_formatter>());
break;
case ('C'):
formatters_.push_back(details::make_unique<details::C_formatter>());
break;
case ('Y'):
formatters_.push_back(details::make_unique<details::Y_formatter>());
break;
case ('D'):
case ('x'):
formatters_.push_back(details::make_unique<details::D_formatter>());
break;
case ('m'):
formatters_.push_back(details::make_unique<details::m_formatter>());
break;
case ('d'):
formatters_.push_back(details::make_unique<details::d_formatter>());
break;
case ('H'):
formatters_.push_back(details::make_unique<details::H_formatter>());
break;
case ('I'):
formatters_.push_back(details::make_unique<details::I_formatter>());
break;
case ('M'):
formatters_.push_back(details::make_unique<details::M_formatter>());
break;
case ('S'):
formatters_.push_back(details::make_unique<details::S_formatter>());
break;
case ('e'):
formatters_.push_back(details::make_unique<details::e_formatter>());
break;
case ('f'):
formatters_.push_back(details::make_unique<details::f_formatter>());
break;
case ('F'):
formatters_.push_back(details::make_unique<details::F_formatter>());
break;
case ('E'):
formatters_.push_back(details::make_unique<details::E_formatter>());
break;
case ('p'):
formatters_.push_back(details::make_unique<details::p_formatter>());
break;
case ('r'):
formatters_.push_back(details::make_unique<details::r_formatter>());
break;
case ('R'):
formatters_.push_back(details::make_unique<details::R_formatter>());
break;
case ('T'):
case ('X'):
formatters_.push_back(details::make_unique<details::T_formatter>());
break;
case ('z'):
formatters_.push_back(details::make_unique<details::z_formatter>());
break;
case ('+'):
formatters_.push_back(details::make_unique<details::full_formatter>());
break;
case ('P'):
formatters_.push_back(details::make_unique<details::pid_formatter>());
break;
#ifdef SPDLOG_ENABLE_MESSAGE_COUNTER
case ('i'):
formatters_.push_back(details::make_unique<details::i_formatter>());
break;
#endif
case ('^'):
formatters_.push_back(details::make_unique<details::color_start_formatter>());
break;
case ('$'):
formatters_.push_back(details::make_unique<details::color_stop_formatter>());
break;
default: // Unknown flag appears as is
formatters_.push_back(details::make_unique<details::ch_formatter>('%'));
formatters_.push_back(details::make_unique<details::ch_formatter>(flag));
break;
}
}
void compile_pattern_(const std::string &pattern)
{
auto end = pattern.end();
std::unique_ptr<details::aggregate_formatter> user_chars;
formatters_.clear();
for (auto it = pattern.begin(); it != end; ++it)
{
if (*it == '%')
{
if (user_chars) // append user chars found so far
{
formatters_.push_back(std::move(user_chars));
}
if (++it != end)
{
handle_flag_(*it);
}
else
{
break;
}
}
else // chars not following the % sign should be displayed as is
{
if (!user_chars)
{
user_chars = details::make_unique<details::aggregate_formatter>();
}
user_chars->add_ch(*it);
}
}
if (user_chars) // append raw chars found so far
{
formatters_.push_back(std::move(user_chars));
}
}
};
} // namespace spdlog
+71
View File
@@ -0,0 +1,71 @@
//
// Copyright(c) 2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// periodic worker thread - periodically executes the given callback function.
//
// RAII over the owned thread:
// creates the thread on construction.
// stops and joins the thread on destruction.
#include <chrono>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
namespace spdlog {
namespace details {
class periodic_worker
{
public:
periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval)
{
active_ = (interval > std::chrono::seconds::zero());
if (!active_)
{
return;
}
worker_thread_ = std::thread([this, callback_fun, interval]() {
for (;;)
{
std::unique_lock<std::mutex> lock(this->mutex_);
if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; }))
{
return; // active_ == false, so exit this thread
}
callback_fun();
}
});
}
periodic_worker(const periodic_worker &) = delete;
periodic_worker &operator=(const periodic_worker &) = delete;
// stop the worker thread and join it
~periodic_worker()
{
if (worker_thread_.joinable())
{
{
std::lock_guard<std::mutex> lock(mutex_);
active_ = false;
}
cv_.notify_one();
worker_thread_.join();
}
}
private:
bool active_;
std::thread worker_thread_;
std::mutex mutex_;
std::condition_variable cv_;
};
} // namespace details
} // namespace spdlog
+214
View File
@@ -0,0 +1,214 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Loggers registy of unique name->logger pointer
// An attempt to create a logger with an already existing name will be ignored
// If user requests a non existing logger, nullptr will be returned
// This class is thread safe
#include "spdlog/common.h"
#include "spdlog/details/periodic_worker.h"
#include "spdlog/logger.h"
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
namespace spdlog {
namespace details {
class thread_pool;
class registry
{
public:
registry(const registry &) = delete;
registry &operator=(const registry &) = delete;
void register_logger(std::shared_ptr<logger> new_logger)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
auto logger_name = new_logger->name();
throw_if_exists_(logger_name);
loggers_[logger_name] = std::move(new_logger);
}
void register_and_init(std::shared_ptr<logger> new_logger)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
auto logger_name = new_logger->name();
throw_if_exists_(logger_name);
// set the global formatter pattern
new_logger->set_formatter(formatter_->clone());
if (err_handler_)
{
new_logger->set_error_handler(err_handler_);
}
new_logger->set_level(level_);
new_logger->flush_on(flush_level_);
// add to registry
loggers_[logger_name] = std::move(new_logger);
}
std::shared_ptr<logger> get(const std::string &logger_name)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
auto found = loggers_.find(logger_name);
return found == loggers_.end() ? nullptr : found->second;
}
void set_tp(std::shared_ptr<thread_pool> tp)
{
std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
tp_ = std::move(tp);
}
std::shared_ptr<thread_pool> get_tp()
{
std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
return tp_;
}
// Set global formatter. Each sink in each logger will get a clone of this object
void set_formatter(std::unique_ptr<formatter> formatter)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
formatter_ = std::move(formatter);
for (auto &l : loggers_)
{
l.second->set_formatter(formatter_->clone());
}
}
void set_level(level::level_enum log_level)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
for (auto &l : loggers_)
{
l.second->set_level(log_level);
}
level_ = log_level;
}
void flush_on(level::level_enum log_level)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
for (auto &l : loggers_)
{
l.second->flush_on(log_level);
}
flush_level_ = log_level;
}
void flush_every(std::chrono::seconds interval)
{
std::lock_guard<std::mutex> lock(flusher_mutex_);
std::function<void()> clbk = std::bind(&registry::flush_all, this);
periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval);
}
void set_error_handler(log_err_handler handler)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
for (auto &l : loggers_)
{
l.second->set_error_handler(handler);
}
err_handler_ = handler;
}
void apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
for (auto &l : loggers_)
{
fun(l.second);
}
}
void flush_all()
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
for (auto &l : loggers_)
{
l.second->flush();
}
}
void drop(const std::string &logger_name)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
loggers_.erase(logger_name);
}
void drop_all()
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
loggers_.clear();
}
// clean all reasources and threads started by the registry
void shutdown()
{
{
std::lock_guard<std::mutex> lock(flusher_mutex_);
periodic_flusher_.reset();
}
drop_all();
{
std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
tp_.reset();
}
}
std::recursive_mutex &tp_mutex()
{
return tp_mutex_;
}
static registry &instance()
{
static registry s_instance;
return s_instance;
}
private:
registry()
: formatter_(new pattern_formatter("%+"))
{
}
~registry() = default;
void throw_if_exists_(const std::string &logger_name)
{
if (loggers_.find(logger_name) != loggers_.end())
{
throw spdlog_ex("logger with name '" + logger_name + "' already exists");
}
}
std::mutex logger_map_mutex_, flusher_mutex_;
std::recursive_mutex tp_mutex_;
std::unordered_map<std::string, std::shared_ptr<logger>> loggers_;
std::unique_ptr<formatter> formatter_;
level::level_enum level_ = level::info;
level::level_enum flush_level_ = level::off;
log_err_handler err_handler_;
std::shared_ptr<thread_pool> tp_;
std::unique_ptr<periodic_worker> periodic_flusher_;
};
} // namespace details
} // namespace spdlog
+228
View File
@@ -0,0 +1,228 @@
#pragma once
#include "spdlog/details/log_msg.h"
#include "spdlog/details/mpmc_blocking_q.h"
#include "spdlog/details/os.h"
#include <chrono>
#include <memory>
#include <thread>
#include <vector>
namespace spdlog {
namespace details {
using async_logger_ptr = std::shared_ptr<spdlog::async_logger>;
enum class async_msg_type
{
log,
flush,
terminate
};
// Async msg to move to/from the queue
// Movable only. should never be copied
struct async_msg
{
async_msg_type msg_type;
level::level_enum level;
log_clock::time_point time;
size_t thread_id;
fmt::basic_memory_buffer<char, 176> raw;
size_t msg_id;
async_logger_ptr worker_ptr;
async_msg() = default;
~async_msg() = default;
// should only be moved in or out of the queue..
async_msg(const async_msg &) = delete;
// support for vs2013 move
#if defined(_MSC_VER) && _MSC_VER <= 1800
async_msg(async_msg &&other) SPDLOG_NOEXCEPT : msg_type(other.msg_type),
level(other.level),
time(other.time),
thread_id(other.thread_id),
raw(move(other.raw)),
msg_id(other.msg_id),
worker_ptr(std::move(other.worker_ptr))
{
}
async_msg &operator=(async_msg &&other) SPDLOG_NOEXCEPT
{
msg_type = other.msg_type;
level = other.level;
time = other.time;
thread_id = other.thread_id;
raw = std::move(other.raw);
msg_id = other.msg_id;
worker_ptr = std::move(other.worker_ptr);
return *this;
}
#else // (_MSC_VER) && _MSC_VER <= 1800
async_msg(async_msg &&) = default;
async_msg &operator=(async_msg &&) = default;
#endif
// construct from log_msg with given type
async_msg(async_logger_ptr &&worker, async_msg_type the_type, details::log_msg &&m)
: msg_type(the_type)
, level(m.level)
, time(m.time)
, thread_id(m.thread_id)
, msg_id(m.msg_id)
, worker_ptr(std::move(worker))
{
fmt_helper::append_buf(m.raw, raw);
}
async_msg(async_logger_ptr &&worker, async_msg_type the_type)
: async_msg(std::move(worker), the_type, details::log_msg())
{
}
explicit async_msg(async_msg_type the_type)
: async_msg(nullptr, the_type, details::log_msg())
{
}
// copy into log_msg
void to_log_msg(log_msg &msg)
{
msg.logger_name = &worker_ptr->name();
msg.level = level;
msg.time = time;
msg.thread_id = thread_id;
fmt_helper::append_buf(raw, msg.raw);
msg.msg_id = msg_id;
msg.color_range_start = 0;
msg.color_range_end = 0;
}
};
class thread_pool
{
public:
using item_type = async_msg;
using q_type = details::mpmc_blocking_queue<item_type>;
thread_pool(size_t q_max_items, size_t threads_n)
: q_(q_max_items)
{
// std::cout << "thread_pool() q_size_bytes: " << q_size_bytes <<
// "\tthreads_n: " << threads_n << std::endl;
if (threads_n == 0 || threads_n > 1000)
{
throw spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid "
"range is 1-1000)");
}
for (size_t i = 0; i < threads_n; i++)
{
threads_.emplace_back(&thread_pool::worker_loop_, this);
}
}
// message all threads to terminate gracefully join them
~thread_pool()
{
try
{
for (size_t i = 0; i < threads_.size(); i++)
{
post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block);
}
for (auto &t : threads_)
{
t.join();
}
}
catch (...)
{
}
}
thread_pool(const thread_pool &) = delete;
thread_pool &operator=(thread_pool &&) = delete;
void post_log(async_logger_ptr &&worker_ptr, details::log_msg &&msg, async_overflow_policy overflow_policy)
{
async_msg async_m(std::move(worker_ptr), async_msg_type::log, std::move(msg));
post_async_msg_(std::move(async_m), overflow_policy);
}
void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy)
{
post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy);
}
size_t overrun_counter()
{
return q_.overrun_counter();
}
private:
q_type q_;
std::vector<std::thread> threads_;
void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy)
{
if (overflow_policy == async_overflow_policy::block)
{
q_.enqueue(std::move(new_msg));
}
else
{
q_.enqueue_nowait(std::move(new_msg));
}
}
void worker_loop_()
{
while (process_next_msg_()) {};
}
// process next message in the queue
// return true if this thread should still be active (while no terminate msg
// was received)
bool process_next_msg_()
{
async_msg incoming_async_msg;
bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10));
if (!dequeued)
{
return true;
}
switch (incoming_async_msg.msg_type)
{
case async_msg_type::log:
{
log_msg msg;
incoming_async_msg.to_log_msg(msg);
incoming_async_msg.worker_ptr->backend_log_(msg);
return true;
}
case async_msg_type::flush:
{
incoming_async_msg.worker_ptr->backend_flush_();
return true;
}
case async_msg_type::terminate:
{
return false;
}
}
assert(false && "Unexpected async_msg_type");
return true;
}
};
} // namespace details
} // namespace spdlog
+172
View File
@@ -0,0 +1,172 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// Support for logging binary data as hex
// format flags:
// {:X} - print in uppercase.
// {:s} - don't separate each byte with space.
// {:p} - don't print the position on each line start.
// {:n} - don't split the output to lines.
//
// Examples:
//
// std::vector<char> v(200, 0x0b);
// logger->info("Some buffer {}", spdlog::to_hex(v));
// char buf[128];
// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf)));
namespace spdlog {
namespace details {
template<typename It>
class bytes_range
{
public:
bytes_range(It range_begin, It range_end)
: begin_(range_begin)
, end_(range_end)
{
}
It begin() const
{
return begin_;
}
It end() const
{
return end_;
}
private:
It begin_, end_;
};
} // namespace details
// create a bytes_range that wraps the given container
template<typename Container>
inline details::bytes_range<typename Container::const_iterator> to_hex(const Container &container)
{
static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1");
using Iter = typename Container::const_iterator;
return details::bytes_range<Iter>(std::begin(container), std::end(container));
}
// create bytes_range from ranges
template<typename It>
inline details::bytes_range<It> to_hex(const It range_begin, const It range_end)
{
return details::bytes_range<It>(range_begin, range_end);
}
} // namespace spdlog
namespace fmt {
template<typename T>
struct formatter<spdlog::details::bytes_range<T>>
{
const std::size_t line_size = 100;
const char delimiter = ' ';
bool put_newlines = true;
bool put_delimiters = true;
bool use_uppercase = false;
bool put_positions = true; // position on start of each line
// parse the format string flags
template<typename ParseContext>
auto parse(ParseContext &ctx) -> decltype(ctx.begin())
{
auto it = ctx.begin();
while (*it && *it != '}')
{
switch (*it)
{
case 'X':
use_uppercase = true;
break;
case 's':
put_delimiters = false;
break;
case 'p':
put_positions = false;
break;
case 'n':
put_newlines = false;
break;
}
++it;
}
return it;
}
// format the given bytes range as hex
template<typename FormatContext, typename Container>
auto format(const spdlog::details::bytes_range<Container> &the_range, FormatContext &ctx) -> decltype(ctx.out())
{
constexpr const char *hex_upper = "0123456789ABCDEF";
constexpr const char *hex_lower = "0123456789abcdef";
const char *hex_chars = use_uppercase ? hex_upper : hex_lower;
std::size_t pos = 0;
std::size_t column = line_size;
auto inserter = ctx.begin();
for (auto &item : the_range)
{
auto ch = static_cast<unsigned char>(item);
pos++;
if (put_newlines && column >= line_size)
{
column = put_newline(inserter, pos);
// put first byte without delimiter in front of it
*inserter++ = hex_chars[(ch >> 4) & 0x0f];
*inserter++ = hex_chars[ch & 0x0f];
column += 2;
continue;
}
if (put_delimiters)
{
*inserter++ = delimiter;
++column;
}
*inserter++ = hex_chars[(ch >> 4) & 0x0f];
*inserter++ = hex_chars[ch & 0x0f];
column += 2;
}
return inserter;
}
// put newline(and position header)
// return the next column
template<typename It>
std::size_t put_newline(It inserter, std::size_t pos)
{
#ifdef _WIN32
*inserter++ = '\r';
#endif
*inserter++ = '\n';
if (put_positions)
{
fmt::format_to(inserter, "{:<04X}: ", pos - 1);
return 7;
}
else
{
return 1;
}
}
};
} // namespace fmt
+23
View File
@@ -0,0 +1,23 @@
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+257
View File
@@ -0,0 +1,257 @@
// Formatting library for C++ - the core API
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
//
// Copyright (c) 2018 - present, Remotion (Igor Schulz)
// All Rights Reserved
// {fmt} support for rgb color output.
#ifndef FMT_COLORS_H_
#define FMT_COLORS_H_
#include "format.h"
FMT_BEGIN_NAMESPACE
// rgb is a struct for red, green and blue colors.
// We use rgb as name because some editors will show it as color direct in the
// editor.
struct rgb
{
FMT_CONSTEXPR_DECL rgb()
: r(0)
, g(0)
, b(0)
{
}
FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_)
: r(r_)
, g(g_)
, b(b_)
{
}
FMT_CONSTEXPR_DECL rgb(uint32_t hex)
: r((hex >> 16) & 0xFF)
, g((hex >> 8) & 0xFF)
, b((hex)&0xFF)
{
}
uint8_t r;
uint8_t g;
uint8_t b;
};
namespace internal {
FMT_CONSTEXPR inline void to_esc(uint8_t c, char out[], int offset)
{
out[offset + 0] = static_cast<char>('0' + c / 100);
out[offset + 1] = static_cast<char>('0' + c / 10 % 10);
out[offset + 2] = static_cast<char>('0' + c % 10);
}
} // namespace internal
FMT_FUNC void vprint_rgb(rgb fd, string_view format, format_args args)
{
char escape_fd[] = "\x1b[38;2;000;000;000m";
static FMT_CONSTEXPR_DECL const char RESET_COLOR[] = "\x1b[0m";
internal::to_esc(fd.r, escape_fd, 7);
internal::to_esc(fd.g, escape_fd, 11);
internal::to_esc(fd.b, escape_fd, 15);
std::fputs(escape_fd, stdout);
vprint(format, args);
std::fputs(RESET_COLOR, stdout);
}
FMT_FUNC void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args)
{
char escape_fd[] = "\x1b[38;2;000;000;000m"; // foreground color
char escape_bg[] = "\x1b[48;2;000;000;000m"; // background color
static FMT_CONSTEXPR_DECL const char RESET_COLOR[] = "\x1b[0m";
internal::to_esc(fd.r, escape_fd, 7);
internal::to_esc(fd.g, escape_fd, 11);
internal::to_esc(fd.b, escape_fd, 15);
internal::to_esc(bg.r, escape_bg, 7);
internal::to_esc(bg.g, escape_bg, 11);
internal::to_esc(bg.b, escape_bg, 15);
std::fputs(escape_fd, stdout);
std::fputs(escape_bg, stdout);
vprint(format, args);
std::fputs(RESET_COLOR, stdout);
}
template<typename... Args>
inline void print_rgb(rgb fd, string_view format_str, const Args &... args)
{
vprint_rgb(fd, format_str, make_format_args(args...));
}
// rgb foreground color
template<typename... Args>
inline void print(rgb fd, string_view format_str, const Args &... args)
{
vprint_rgb(fd, format_str, make_format_args(args...));
}
// rgb foreground color and background color
template<typename... Args>
inline void print(rgb fd, rgb bg, string_view format_str, const Args &... args)
{
vprint_rgb(fd, bg, format_str, make_format_args(args...));
}
enum class color : uint32_t
{
alice_blue = 0xF0F8FF, // rgb(240,248,255)
antique_white = 0xFAEBD7, // rgb(250,235,215)
aqua = 0x00FFFF, // rgb(0,255,255)
aquamarine = 0x7FFFD4, // rgb(127,255,212)
azure = 0xF0FFFF, // rgb(240,255,255)
beige = 0xF5F5DC, // rgb(245,245,220)
bisque = 0xFFE4C4, // rgb(255,228,196)
black = 0x000000, // rgb(0,0,0)
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
blue = 0x0000FF, // rgb(0,0,255)
blue_violet = 0x8A2BE2, // rgb(138,43,226)
brown = 0xA52A2A, // rgb(165,42,42)
burly_wood = 0xDEB887, // rgb(222,184,135)
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
chartreuse = 0x7FFF00, // rgb(127,255,0)
chocolate = 0xD2691E, // rgb(210,105,30)
coral = 0xFF7F50, // rgb(255,127,80)
cornflower_blue = 0x6495ED, // rgb(100,149,237)
cornsilk = 0xFFF8DC, // rgb(255,248,220)
crimson = 0xDC143C, // rgb(220,20,60)
cyan = 0x00FFFF, // rgb(0,255,255)
dark_blue = 0x00008B, // rgb(0,0,139)
dark_cyan = 0x008B8B, // rgb(0,139,139)
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
dark_gray = 0xA9A9A9, // rgb(169,169,169)
dark_green = 0x006400, // rgb(0,100,0)
dark_khaki = 0xBDB76B, // rgb(189,183,107)
dark_magenta = 0x8B008B, // rgb(139,0,139)
dark_olive_green = 0x556B2F, // rgb(85,107,47)
dark_orange = 0xFF8C00, // rgb(255,140,0)
dark_orchid = 0x9932CC, // rgb(153,50,204)
dark_red = 0x8B0000, // rgb(139,0,0)
dark_salmon = 0xE9967A, // rgb(233,150,122)
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
dark_turquoise = 0x00CED1, // rgb(0,206,209)
dark_violet = 0x9400D3, // rgb(148,0,211)
deep_pink = 0xFF1493, // rgb(255,20,147)
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
dim_gray = 0x696969, // rgb(105,105,105)
dodger_blue = 0x1E90FF, // rgb(30,144,255)
fire_brick = 0xB22222, // rgb(178,34,34)
floral_white = 0xFFFAF0, // rgb(255,250,240)
forest_green = 0x228B22, // rgb(34,139,34)
fuchsia = 0xFF00FF, // rgb(255,0,255)
gainsboro = 0xDCDCDC, // rgb(220,220,220)
ghost_white = 0xF8F8FF, // rgb(248,248,255)
gold = 0xFFD700, // rgb(255,215,0)
golden_rod = 0xDAA520, // rgb(218,165,32)
gray = 0x808080, // rgb(128,128,128)
green = 0x008000, // rgb(0,128,0)
green_yellow = 0xADFF2F, // rgb(173,255,47)
honey_dew = 0xF0FFF0, // rgb(240,255,240)
hot_pink = 0xFF69B4, // rgb(255,105,180)
indian_red = 0xCD5C5C, // rgb(205,92,92)
indigo = 0x4B0082, // rgb(75,0,130)
ivory = 0xFFFFF0, // rgb(255,255,240)
khaki = 0xF0E68C, // rgb(240,230,140)
lavender = 0xE6E6FA, // rgb(230,230,250)
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
lawn_green = 0x7CFC00, // rgb(124,252,0)
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
light_blue = 0xADD8E6, // rgb(173,216,230)
light_coral = 0xF08080, // rgb(240,128,128)
light_cyan = 0xE0FFFF, // rgb(224,255,255)
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
light_gray = 0xD3D3D3, // rgb(211,211,211)
light_green = 0x90EE90, // rgb(144,238,144)
light_pink = 0xFFB6C1, // rgb(255,182,193)
light_salmon = 0xFFA07A, // rgb(255,160,122)
light_sea_green = 0x20B2AA, // rgb(32,178,170)
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
light_slate_gray = 0x778899, // rgb(119,136,153)
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
light_yellow = 0xFFFFE0, // rgb(255,255,224)
lime = 0x00FF00, // rgb(0,255,0)
lime_green = 0x32CD32, // rgb(50,205,50)
linen = 0xFAF0E6, // rgb(250,240,230)
magenta = 0xFF00FF, // rgb(255,0,255)
maroon = 0x800000, // rgb(128,0,0)
medium_aqua_marine = 0x66CDAA, // rgb(102,205,170)
medium_blue = 0x0000CD, // rgb(0,0,205)
medium_orchid = 0xBA55D3, // rgb(186,85,211)
medium_purple = 0x9370DB, // rgb(147,112,219)
medium_sea_green = 0x3CB371, // rgb(60,179,113)
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
medium_violet_red = 0xC71585, // rgb(199,21,133)
midnight_blue = 0x191970, // rgb(25,25,112)
mint_cream = 0xF5FFFA, // rgb(245,255,250)
misty_rose = 0xFFE4E1, // rgb(255,228,225)
moccasin = 0xFFE4B5, // rgb(255,228,181)
navajo_white = 0xFFDEAD, // rgb(255,222,173)
navy = 0x000080, // rgb(0,0,128)
old_lace = 0xFDF5E6, // rgb(253,245,230)
olive = 0x808000, // rgb(128,128,0)
olive_drab = 0x6B8E23, // rgb(107,142,35)
orange = 0xFFA500, // rgb(255,165,0)
orange_red = 0xFF4500, // rgb(255,69,0)
orchid = 0xDA70D6, // rgb(218,112,214)
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
pale_green = 0x98FB98, // rgb(152,251,152)
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
pale_violet_red = 0xDB7093, // rgb(219,112,147)
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
peach_puff = 0xFFDAB9, // rgb(255,218,185)
peru = 0xCD853F, // rgb(205,133,63)
pink = 0xFFC0CB, // rgb(255,192,203)
plum = 0xDDA0DD, // rgb(221,160,221)
powder_blue = 0xB0E0E6, // rgb(176,224,230)
purple = 0x800080, // rgb(128,0,128)
rebecca_purple = 0x663399, // rgb(102,51,153)
red = 0xFF0000, // rgb(255,0,0)
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
royal_blue = 0x4169E1, // rgb(65,105,225)
saddle_brown = 0x8B4513, // rgb(139,69,19)
salmon = 0xFA8072, // rgb(250,128,114)
sandy_brown = 0xF4A460, // rgb(244,164,96)
sea_green = 0x2E8B57, // rgb(46,139,87)
sea_shell = 0xFFF5EE, // rgb(255,245,238)
sienna = 0xA0522D, // rgb(160,82,45)
silver = 0xC0C0C0, // rgb(192,192,192)
sky_blue = 0x87CEEB, // rgb(135,206,235)
slate_blue = 0x6A5ACD, // rgb(106,90,205)
slate_gray = 0x708090, // rgb(112,128,144)
snow = 0xFFFAFA, // rgb(255,250,250)
spring_green = 0x00FF7F, // rgb(0,255,127)
steel_blue = 0x4682B4, // rgb(70,130,180)
tan = 0xD2B48C, // rgb(210,180,140)
teal = 0x008080, // rgb(0,128,128)
thistle = 0xD8BFD8, // rgb(216,191,216)
tomato = 0xFF6347, // rgb(255,99,71)
turquoise = 0x40E0D0, // rgb(64,224,208)
violet = 0xEE82EE, // rgb(238,130,238)
wheat = 0xF5DEB3, // rgb(245,222,179)
white = 0xFFFFFF, // rgb(255,255,255)
white_smoke = 0xF5F5F5, // rgb(245,245,245)
yellow = 0xFFFF00, // rgb(255,255,0)
yellow_green = 0x9ACD32, // rgb(154,205,50)
}; // enum class colors
FMT_END_NAMESPACE
#endif // FMT_COLORS_H_
File diff suppressed because it is too large. Load diff
+866
View File
@@ -0,0 +1,866 @@
// Formatting library for C++
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_FORMAT_INL_H_
#define FMT_FORMAT_INL_H_
#include "format.h"
#include <string.h>
#include <cctype>
#include <cerrno>
#include <climits>
#include <cmath>
#include <cstdarg>
#include <cstddef> // for std::ptrdiff_t
#include <cstring> // for std::memmove
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
# include <locale>
#endif
#if FMT_USE_WINDOWS_H
# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# endif
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
# include <windows.h>
# else
# define NOMINMAX
# include <windows.h>
# undef NOMINMAX
# endif
#endif
#if FMT_EXCEPTIONS
# define FMT_TRY try
# define FMT_CATCH(x) catch (x)
#else
# define FMT_TRY if (true)
# define FMT_CATCH(x) if (false)
#endif
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4702) // unreachable code
// Disable deprecation warning for strerror. The latter is not called but
// MSVC fails to detect it.
# pragma warning(disable: 4996)
#endif
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
inline fmt::internal::null<> strerror_r(int, char *, ...) {
return fmt::internal::null<>();
}
inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) {
return fmt::internal::null<>();
}
FMT_BEGIN_NAMESPACE
namespace {
#ifndef _MSC_VER
# define FMT_SNPRINTF snprintf
#else // _MSC_VER
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
va_list args;
va_start(args, format);
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
va_end(args);
return result;
}
# define FMT_SNPRINTF fmt_snprintf
#endif // _MSC_VER
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
# define FMT_SWPRINTF snwprintf
#else
# define FMT_SWPRINTF swprintf
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
typedef void (*FormatFunc)(internal::buffer &, int, string_view);
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
// This can be either a pointer to a string stored in buffer,
// or a pointer to some static immutable string.
// Returns one of the following values:
// 0 - success
// ERANGE - buffer is not large enough to store the error message
// other - failure
// Buffer should be at least of size 1.
int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
class dispatcher {
private:
int error_code_;
char *&buffer_;
std::size_t buffer_size_;
// A noop assignment operator to avoid bogus warnings.
void operator=(const dispatcher &) {}
// Handle the result of XSI-compliant version of strerror_r.
int handle(int result) {
// glibc versions before 2.13 return result in errno.
return result == -1 ? errno : result;
}
// Handle the result of GNU-specific version of strerror_r.
int handle(char *message) {
// If the buffer is full then the message is probably truncated.
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
return ERANGE;
buffer_ = message;
return 0;
}
// Handle the case when strerror_r is not available.
int handle(internal::null<>) {
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
}
// Fallback to strerror_s when strerror_r is not available.
int fallback(int result) {
// If the buffer is full then the message is probably truncated.
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
ERANGE : result;
}
// Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::null<>) {
errno = 0;
buffer_ = strerror(error_code_);
return errno;
}
public:
dispatcher(int err_code, char *&buf, std::size_t buf_size)
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
int run() {
return handle(strerror_r(error_code_, buffer_, buffer_size_));
}
};
return dispatcher(error_code, buffer, buffer_size).run();
}
void format_error_code(internal::buffer &out, int error_code,
string_view message) FMT_NOEXCEPT {
// Report error code making sure that the output fits into
// inline_buffer_size to avoid dynamic memory allocation and potential
// bad_alloc.
out.resize(0);
static const char SEP[] = ": ";
static const char ERROR_STR[] = "error ";
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
typedef internal::int_traits<int>::main_type main_type;
main_type abs_value = static_cast<main_type>(error_code);
if (internal::is_negative(error_code)) {
abs_value = 0 - abs_value;
++error_code_size;
}
error_code_size += internal::count_digits(abs_value);
writer w(out);
if (message.size() <= inline_buffer_size - error_code_size) {
w.write(message);
w.write(SEP);
}
w.write(ERROR_STR);
w.write(error_code);
assert(out.size() <= inline_buffer_size);
}
void report_error(FormatFunc func, int error_code,
string_view message) FMT_NOEXCEPT {
memory_buffer full_message;
func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory
// allocation.
std::fwrite(full_message.data(), full_message.size(), 1, stderr);
std::fputc('\n', stderr);
}
} // namespace
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
class locale {
private:
std::locale locale_;
public:
explicit locale(std::locale loc = std::locale()) : locale_(loc) {}
std::locale get() { return locale_; }
};
FMT_FUNC size_t internal::count_code_points(u8string_view s) {
const char8_t *data = s.data();
int num_code_points = 0;
for (size_t i = 0, size = s.size(); i != size; ++i) {
if ((data[i].value & 0xc0) != 0x80)
++num_code_points;
}
return num_code_points;
}
template <typename Char>
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
std::locale loc = lp ? lp->locale().get() : std::locale();
return std::use_facet<std::numpunct<Char>>(loc).thousands_sep();
}
#else
template <typename Char>
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
return FMT_STATIC_THOUSANDS_SEPARATOR;
}
#endif
FMT_FUNC void system_error::init(
int err_code, string_view format_str, format_args args) {
error_code_ = err_code;
memory_buffer buffer;
format_system_error(buffer, err_code, vformat(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(to_string(buffer));
}
namespace internal {
template <typename T>
int char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format, int precision, T value) {
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, precision, value);
}
template <typename T>
int char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
T value) {
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
}
template <typename T>
const char basic_data<T>::DIGITS[] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
#define FMT_POWERS_OF_10(factor) \
factor * 10, \
factor * 100, \
factor * 1000, \
factor * 10000, \
factor * 100000, \
factor * 1000000, \
factor * 10000000, \
factor * 100000000, \
factor * 1000000000
template <typename T>
const uint32_t basic_data<T>::POWERS_OF_10_32[] = {
1, FMT_POWERS_OF_10(1)
};
template <typename T>
const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {
0, FMT_POWERS_OF_10(1)
};
template <typename T>
const uint64_t basic_data<T>::ZERO_OR_POWERS_OF_10_64[] = {
0,
FMT_POWERS_OF_10(1),
FMT_POWERS_OF_10(1000000000ull),
10000000000000000000ull
};
// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
// These are generated by support/compute-powers.py.
template <typename T>
const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76,
0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df,
0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c,
0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57,
0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7,
0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e,
0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126,
0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053,
0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f,
0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06,
0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb,
0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000,
0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068,
0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8,
0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758,
0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d,
0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25,
0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2,
0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410,
0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129,
0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85,
0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b,
};
// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
// to significands above.
template <typename T>
const int16_t basic_data<T>::POW10_EXPONENTS[] = {
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954,
-927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661,
-635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369,
-343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77,
-50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216,
242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508,
534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800,
827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066
};
template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
// A handmade floating-point number f * pow(2, e).
class fp {
private:
typedef uint64_t significand_type;
// All sizes are in bits.
static FMT_CONSTEXPR_DECL const int char_size =
std::numeric_limits<unsigned char>::digits;
// Subtract 1 to account for an implicit most significant bit in the
// normalized form.
static FMT_CONSTEXPR_DECL const int double_significand_size =
std::numeric_limits<double>::digits - 1;
static FMT_CONSTEXPR_DECL const uint64_t implicit_bit =
1ull << double_significand_size;
public:
significand_type f;
int e;
static FMT_CONSTEXPR_DECL const int significand_size =
sizeof(significand_type) * char_size;
fp(): f(0), e(0) {}
fp(uint64_t f, int e): f(f), e(e) {}
// Constructs fp from an IEEE754 double. It is a template to prevent compile
// errors on platforms where double is not IEEE754.
template <typename Double>
explicit fp(Double d) {
// Assume double is in the format [sign][exponent][significand].
typedef std::numeric_limits<Double> limits;
const int double_size = static_cast<int>(sizeof(Double) * char_size);
const int exponent_size =
double_size - double_significand_size - 1; // -1 for sign
const uint64_t significand_mask = implicit_bit - 1;
const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;
const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
auto u = bit_cast<uint64_t>(d);
auto biased_e = (u & exponent_mask) >> double_significand_size;
f = u & significand_mask;
if (biased_e != 0)
f += implicit_bit;
else
biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
e = static_cast<int>(biased_e - exponent_bias - double_significand_size);
}
// Normalizes the value converted from double and multiplied by (1 << SHIFT).
template <int SHIFT = 0>
void normalize() {
// Handle subnormals.
auto shifted_implicit_bit = implicit_bit << SHIFT;
while ((f & shifted_implicit_bit) == 0) {
f <<= 1;
--e;
}
// Subtract 1 to account for hidden bit.
auto offset = significand_size - double_significand_size - SHIFT - 1;
f <<= offset;
e -= offset;
}
// Compute lower and upper boundaries (m^- and m^+ in the Grisu paper), where
// a boundary is a value half way between the number and its predecessor
// (lower) or successor (upper). The upper boundary is normalized and lower
// has the same exponent but may be not normalized.
void compute_boundaries(fp &lower, fp &upper) const {
lower = f == implicit_bit ?
fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1);
upper = fp((f << 1) + 1, e - 1);
upper.normalize<1>(); // 1 is to account for the exponent shift above.
lower.f <<= lower.e - upper.e;
lower.e = upper.e;
}
};
// Returns an fp number representing x - y. Result may not be normalized.
inline fp operator-(fp x, fp y) {
FMT_ASSERT(x.f >= y.f && x.e == y.e, "invalid operands");
return fp(x.f - y.f, x.e);
}
// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest
// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized.
FMT_API fp operator*(fp x, fp y);
// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3.
FMT_API fp get_cached_power(int min_exponent, int &pow10_exponent);
FMT_FUNC fp operator*(fp x, fp y) {
// Multiply 32-bit parts of significands.
uint64_t mask = (1ULL << 32) - 1;
uint64_t a = x.f >> 32, b = x.f & mask;
uint64_t c = y.f >> 32, d = y.f & mask;
uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
// Compute mid 64-bit of result and round.
uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
}
FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
int index = static_cast<int>(std::ceil(
(min_exponent + fp::significand_size - 1) * one_over_log2_10));
// Decimal exponent of the first (smallest) cached power of 10.
const int first_dec_exp = -348;
// Difference between 2 consecutive decimal exponents in cached powers of 10.
const int dec_exp_step = 8;
index = (index - first_dec_exp - 1) / dec_exp_step + 1;
pow10_exponent = first_dec_exp + index * dec_exp_step;
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
}
// Generates output using Grisu2 digit-gen algorithm.
FMT_FUNC void grisu2_gen_digits(
const fp &scaled_value, const fp &scaled_upper, uint64_t delta,
char *buffer, size_t &size, int &dec_exp) {
internal::fp one(1ull << -scaled_upper.e, scaled_upper.e);
// hi (p1 in Grisu) contains the most significant digits of scaled_upper.
// hi = floor(scaled_upper / one).
uint32_t hi = static_cast<uint32_t>(scaled_upper.f >> -one.e);
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
// lo = scaled_upper mod 1.
uint64_t lo = scaled_upper.f & (one.f - 1);
size = 0;
auto exp = count_digits(hi); // kappa in Grisu.
while (exp > 0) {
uint32_t digit = 0;
// This optimization by miloyip reduces the number of integer divisions by
// one per iteration.
switch (exp) {
case 10: digit = hi / 1000000000; hi %= 1000000000; break;
case 9: digit = hi / 100000000; hi %= 100000000; break;
case 8: digit = hi / 10000000; hi %= 10000000; break;
case 7: digit = hi / 1000000; hi %= 1000000; break;
case 6: digit = hi / 100000; hi %= 100000; break;
case 5: digit = hi / 10000; hi %= 10000; break;
case 4: digit = hi / 1000; hi %= 1000; break;
case 3: digit = hi / 100; hi %= 100; break;
case 2: digit = hi / 10; hi %= 10; break;
case 1: digit = hi; hi = 0; break;
default:
FMT_ASSERT(false, "invalid number of digits");
}
if (digit != 0 || size != 0)
buffer[size++] = static_cast<char>('0' + digit);
--exp;
uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
if (remainder <= delta) {
dec_exp += exp;
// TODO: use scaled_value
(void)scaled_value;
return;
}
}
for (;;) {
lo *= 10;
delta *= 10;
char digit = static_cast<char>(lo >> -one.e);
if (digit != 0 || size != 0)
buffer[size++] = static_cast<char>('0' + digit);
lo &= one.f - 1;
--exp;
if (lo < delta) {
dec_exp += exp;
return;
}
}
}
FMT_FUNC void grisu2_format_positive(double value, char *buffer, size_t &size,
int &dec_exp) {
FMT_ASSERT(value > 0, "value is nonpositive");
fp fp_value(value);
fp lower, upper; // w^- and w^+ in the Grisu paper.
fp_value.compute_boundaries(lower, upper);
// Find a cached power of 10 close to 1 / upper.
const int min_exp = -60; // alpha in Grisu.
auto dec_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
min_exp - (upper.e + fp::significand_size), dec_exp);
dec_exp = -dec_exp;
fp_value.normalize();
fp scaled_value = fp_value * dec_pow;
fp scaled_lower = lower * dec_pow; // \tilde{M}^- in Grisu.
fp scaled_upper = upper * dec_pow; // \tilde{M}^+ in Grisu.
++scaled_lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
--scaled_upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
uint64_t delta = scaled_upper.f - scaled_lower.f;
grisu2_gen_digits(scaled_value, scaled_upper, delta, buffer, size, dec_exp);
}
FMT_FUNC void round(char *buffer, size_t &size, int &exp,
int digits_to_remove) {
size -= to_unsigned(digits_to_remove);
exp += digits_to_remove;
int digit = buffer[size] - '0';
// TODO: proper rounding and carry
if (digit > 5 || (digit == 5 && (digits_to_remove > 1 ||
(buffer[size - 1] - '0') % 2) != 0)) {
++buffer[size - 1];
}
}
// Writes the exponent exp in the form "[+-]d{1,3}" to buffer.
FMT_FUNC char *write_exponent(char *buffer, int exp) {
FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
if (exp < 0) {
*buffer++ = '-';
exp = -exp;
} else {
*buffer++ = '+';
}
if (exp >= 100) {
*buffer++ = static_cast<char>('0' + exp / 100);
exp %= 100;
const char *d = data::DIGITS + exp * 2;
*buffer++ = d[0];
*buffer++ = d[1];
} else {
const char *d = data::DIGITS + exp * 2;
*buffer++ = d[0];
*buffer++ = d[1];
}
return buffer;
}
FMT_FUNC void format_exp_notation(
char *buffer, size_t &size, int exp, int precision, bool upper) {
// Insert a decimal point after the first digit and add an exponent.
std::memmove(buffer + 2, buffer + 1, size - 1);
buffer[1] = '.';
exp += static_cast<int>(size) - 1;
int num_digits = precision - static_cast<int>(size) + 1;
if (num_digits > 0) {
std::uninitialized_fill_n(buffer + size + 1, num_digits, '0');
size += to_unsigned(num_digits);
} else if (num_digits < 0) {
round(buffer, size, exp, -num_digits);
}
char *p = buffer + size + 1;
*p++ = upper ? 'E' : 'e';
size = to_unsigned(write_exponent(p, exp) - buffer);
}
// Prettifies the output of the Grisu2 algorithm.
// The number is given as v = buffer * 10^exp.
FMT_FUNC void grisu2_prettify(char *buffer, size_t &size, int exp,
int precision, bool upper) {
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
int int_size = static_cast<int>(size);
int full_exp = int_size + exp;
const int exp_threshold = 21;
if (int_size <= full_exp && full_exp <= exp_threshold) {
// 1234e7 -> 12340000000[.0+]
std::uninitialized_fill_n(buffer + int_size, full_exp - int_size, '0');
char *p = buffer + full_exp;
if (precision > 0) {
*p++ = '.';
std::uninitialized_fill_n(p, precision, '0');
p += precision;
}
size = to_unsigned(p - buffer);
} else if (0 < full_exp && full_exp <= exp_threshold) {
// 1234e-2 -> 12.34[0+]
int fractional_size = -exp;
std::memmove(buffer + full_exp + 1, buffer + full_exp,
to_unsigned(fractional_size));
buffer[full_exp] = '.';
int num_zeros = precision - fractional_size;
if (num_zeros > 0) {
std::uninitialized_fill_n(buffer + size + 1, num_zeros, '0');
size += to_unsigned(num_zeros);
}
++size;
} else if (-6 < full_exp && full_exp <= 0) {
// 1234e-6 -> 0.001234
int offset = 2 - full_exp;
std::memmove(buffer + offset, buffer, size);
buffer[0] = '0';
buffer[1] = '.';
std::uninitialized_fill_n(buffer + 2, -full_exp, '0');
size = to_unsigned(int_size + offset);
} else {
format_exp_notation(buffer, size, exp, precision, upper);
}
}
#if FMT_CLANG_VERSION
# define FMT_FALLTHROUGH [[clang::fallthrough]];
#elif FMT_GCC_VERSION >= 700
# define FMT_FALLTHROUGH [[gnu::fallthrough]];
#else
# define FMT_FALLTHROUGH
#endif
// Formats a nonnegative value using Grisu2 algorithm. Grisu2 doesn't give any
// guarantees on the shortness of the result.
FMT_FUNC void grisu2_format(double value, char *buffer, size_t &size, char type,
int precision, bool write_decimal_point) {
FMT_ASSERT(value >= 0, "value is negative");
int dec_exp = 0; // K in Grisu.
if (value > 0) {
grisu2_format_positive(value, buffer, size, dec_exp);
} else {
*buffer = '0';
size = 1;
}
const int default_precision = 6;
if (precision < 0)
precision = default_precision;
bool upper = false;
switch (type) {
case 'G':
upper = true;
FMT_FALLTHROUGH
case '\0': case 'g': {
int digits_to_remove = static_cast<int>(size) - precision;
if (digits_to_remove > 0) {
round(buffer, size, dec_exp, digits_to_remove);
// Remove trailing zeros.
while (size > 0 && buffer[size - 1] == '0') {
--size;
++dec_exp;
}
}
precision = 0;
break;
}
case 'F':
upper = true;
FMT_FALLTHROUGH
case 'f': {
int digits_to_remove = -dec_exp - precision;
if (digits_to_remove > 0) {
if (digits_to_remove >= static_cast<int>(size))
digits_to_remove = static_cast<int>(size) - 1;
round(buffer, size, dec_exp, digits_to_remove);
}
break;
}
case 'e': case 'E':
format_exp_notation(buffer, size, dec_exp, precision, type == 'E');
return;
}
if (write_decimal_point && precision < 1)
precision = 1;
grisu2_prettify(buffer, size, dec_exp, precision, upper);
}
} // namespace internal
#if FMT_USE_WINDOWS_H
FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
if (s.size() > INT_MAX)
FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG));
int s_size = static_cast<int>(s.size());
if (s_size == 0) {
// MultiByteToWideChar does not support zero length, handle separately.
buffer_.resize(1);
buffer_[0] = 0;
return;
}
int length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
if (length == 0)
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
buffer_.resize(length + 1);
length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
if (length == 0)
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
buffer_[length] = 0;
}
FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
if (int error_code = convert(s)) {
FMT_THROW(windows_error(error_code,
"cannot convert string from UTF-16 to UTF-8"));
}
}
FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
if (s.size() > INT_MAX)
return ERROR_INVALID_PARAMETER;
int s_size = static_cast<int>(s.size());
if (s_size == 0) {
// WideCharToMultiByte does not support zero length, handle separately.
buffer_.resize(1);
buffer_[0] = 0;
return 0;
}
int length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_.resize(length + 1);
length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_[length] = 0;
return 0;
}
FMT_FUNC void windows_error::init(
int err_code, string_view format_str, format_args args) {
error_code_ = err_code;
memory_buffer buffer;
internal::format_windows_error(buffer, err_code, vformat(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(to_string(buffer));
}
FMT_FUNC void internal::format_windows_error(
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
FMT_TRY {
wmemory_buffer buf;
buf.resize(inline_buffer_size);
for (;;) {
wchar_t *system_message = &buf[0];
int result = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
system_message, static_cast<uint32_t>(buf.size()), FMT_NULL);
if (result != 0) {
utf16_to_utf8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
writer w(out);
w.write(message);
w.write(": ");
w.write(utf8_message);
return;
}
break;
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break; // Can't get error message, report error code instead.
buf.resize(buf.size() * 2);
}
} FMT_CATCH(...) {}
format_error_code(out, error_code, message);
}
#endif // FMT_USE_WINDOWS_H
FMT_FUNC void format_system_error(
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
FMT_TRY {
memory_buffer buf;
buf.resize(inline_buffer_size);
for (;;) {
char *system_message = &buf[0];
int result = safe_strerror(error_code, system_message, buf.size());
if (result == 0) {
writer w(out);
w.write(message);
w.write(": ");
w.write(system_message);
return;
}
if (result != ERANGE)
break; // Can't get error message, report error code instead.
buf.resize(buf.size() * 2);
}
} FMT_CATCH(...) {}
format_error_code(out, error_code, message);
}
template <typename Char>
void basic_fixed_buffer<Char>::grow(std::size_t) {
FMT_THROW(std::runtime_error("buffer overflow"));
}
FMT_FUNC void internal::error_handler::on_error(const char *message) {
FMT_THROW(format_error(message));
}
FMT_FUNC void report_system_error(
int error_code, fmt::string_view message) FMT_NOEXCEPT {
report_error(format_system_error, error_code, message);
}
#if FMT_USE_WINDOWS_H
FMT_FUNC void report_windows_error(
int error_code, fmt::string_view message) FMT_NOEXCEPT {
report_error(internal::format_windows_error, error_code, message);
}
#endif
FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
memory_buffer buffer;
vformat_to(buffer, format_str, args);
std::fwrite(buffer.data(), 1, buffer.size(), f);
}
FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
wmemory_buffer buffer;
vformat_to(buffer, format_str, args);
std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
}
FMT_FUNC void vprint(string_view format_str, format_args args) {
vprint(stdout, format_str, args);
}
FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
vprint(stdout, format_str, args);
}
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
FMT_FUNC locale locale_provider::locale() { return fmt::locale(); }
#endif
FMT_END_NAMESPACE
#ifdef _MSC_VER
# pragma warning(pop)
#endif
#endif // FMT_FORMAT_INL_H_
File diff suppressed because it is too large. Load diff
+157
View File
@@ -0,0 +1,157 @@
// Formatting library for C++ - std::ostream support
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#include "format.h"
#include <ostream>
FMT_BEGIN_NAMESPACE
namespace internal {
template <class Char>
class formatbuf : public std::basic_streambuf<Char> {
private:
typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
basic_buffer<Char> &buffer_;
public:
formatbuf(basic_buffer<Char> &buffer) : buffer_(buffer) {}
protected:
// The put-area is actually always empty. This makes the implementation
// simpler and has the advantage that the streambuf and the buffer are always
// in sync and sputc never writes into uninitialized memory. The obvious
// disadvantage is that each call to sputc always results in a (virtual) call
// to overflow. There is no disadvantage here for sputn since this always
// results in a call to xsputn.
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
if (!traits_type::eq_int_type(ch, traits_type::eof()))
buffer_.push_back(static_cast<Char>(ch));
return ch;
}
std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
buffer_.append(s, s + count);
return count;
}
};
template <typename Char>
struct test_stream : std::basic_ostream<Char> {
private:
struct null;
// Hide all operator<< from std::basic_ostream<Char>.
void operator<<(null);
};
// Checks if T has a user-defined operator<< (e.g. not a member of std::ostream).
template <typename T, typename Char>
class is_streamable {
private:
template <typename U>
static decltype(
internal::declval<test_stream<Char>&>()
<< internal::declval<U>(), std::true_type()) test(int);
template <typename>
static std::false_type test(...);
typedef decltype(test<T>(0)) result;
public:
static const bool value = result::value;
};
// Write the content of buf to os.
template <typename Char>
void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) {
const Char *data = buf.data();
typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;
UnsignedStreamSize size = buf.size();
UnsignedStreamSize max_size =
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
do {
UnsignedStreamSize n = size <= max_size ? size : max_size;
os.write(data, static_cast<std::streamsize>(n));
data += n;
size -= n;
} while (size != 0);
}
template <typename Char, typename T>
void format_value(basic_buffer<Char> &buffer, const T &value) {
internal::formatbuf<Char> format_buf(buffer);
std::basic_ostream<Char> output(&format_buf);
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
output << value;
buffer.resize(buffer.size());
}
} // namespace internal
// Disable conversion to int if T has an overloaded operator<< which is a free
// function (not a member of std::ostream).
template <typename T, typename Char>
struct convert_to_int<T, Char, void> {
static const bool value =
convert_to_int<T, Char, int>::value &&
!internal::is_streamable<T, Char>::value;
};
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename T, typename Char>
struct formatter<T, Char,
typename std::enable_if<
internal::is_streamable<T, Char>::value &&
!internal::format_type<
typename buffer_context<Char>::type, T>::value>::type>
: formatter<basic_string_view<Char>, Char> {
template <typename Context>
auto format(const T &value, Context &ctx) -> decltype(ctx.out()) {
basic_memory_buffer<Char> buffer;
internal::format_value(buffer, value);
basic_string_view<Char> str(buffer.data(), buffer.size());
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
}
};
template <typename Char>
inline void vprint(std::basic_ostream<Char> &os,
basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> args) {
basic_memory_buffer<Char> buffer;
vformat_to(buffer, format_str, args);
internal::write(os, buffer);
}
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fmt::print(cerr, "Don't {}!", "panic");
\endrst
*/
template <typename... Args>
inline void print(std::ostream &os, string_view format_str,
const Args & ... args) {
vprint<char>(os, format_str, make_format_args<format_context>(args...));
}
template <typename... Args>
inline void print(std::wostream &os, wstring_view format_str,
const Args & ... args) {
vprint<wchar_t>(os, format_str, make_format_args<wformat_context>(args...));
}
FMT_END_NAMESPACE
#endif // FMT_OSTREAM_H_
+324
View File
@@ -0,0 +1,324 @@
// A C++ interface to POSIX functions.
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_POSIX_H_
#define FMT_POSIX_H_
#if defined(__MINGW32__) || defined(__CYGWIN__)
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
# undef __STRICT_ANSI__
#endif
#include <errno.h>
#include <fcntl.h> // for O_RDONLY
#include <locale.h> // for locale_t
#include <stdio.h>
#include <stdlib.h> // for strtod_l
#include <cstddef>
#if defined __APPLE__ || defined(__FreeBSD__)
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
#endif
#include "format.h"
#ifndef FMT_POSIX
# if defined(_WIN32) && !defined(__MINGW32__)
// Fix warnings about deprecated symbols.
# define FMT_POSIX(call) _##call
# else
# define FMT_POSIX(call) call
# endif
#endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else
# define FMT_SYSTEM(call) call
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX_CALL(call) ::_##call
# else
# define FMT_POSIX_CALL(call) ::call
# endif
#endif
// Retries the expression while it evaluates to error_result and errno
// equals to EINTR.
#ifndef _WIN32
# define FMT_RETRY_VAL(result, expression, error_result) \
do { \
result = (expression); \
} while (result == error_result && errno == EINTR)
#else
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
FMT_BEGIN_NAMESPACE
/**
\rst
A reference to a null-terminated string. It can be constructed from a C
string or ``std::string``.
You can use one of the following typedefs for common character types:
+---------------+-----------------------------+
| Type | Definition |
+===============+=============================+
| cstring_view | basic_cstring_view<char> |
+---------------+-----------------------------+
| wcstring_view | basic_cstring_view<wchar_t> |
+---------------+-----------------------------+
This class is most useful as a parameter type to allow passing
different types of strings to a function, for example::
template <typename... Args>
std::string format(cstring_view format_str, const Args & ... args);
format("{}", 42);
format(std::string("{}"), 42);
\endrst
*/
template <typename Char>
class basic_cstring_view {
private:
const Char *data_;
public:
/** Constructs a string reference object from a C string. */
basic_cstring_view(const Char *s) : data_(s) {}
/**
\rst
Constructs a string reference from an ``std::string`` object.
\endrst
*/
basic_cstring_view(const std::basic_string<Char> &s) : data_(s.c_str()) {}
/** Returns the pointer to a C string. */
const Char *c_str() const { return data_; }
};
typedef basic_cstring_view<char> cstring_view;
typedef basic_cstring_view<wchar_t> wcstring_view;
// An error code.
class error_code {
private:
int value_;
public:
explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
int get() const FMT_NOEXCEPT { return value_; }
};
// A buffered file.
class buffered_file {
private:
FILE *file_;
friend class file;
explicit buffered_file(FILE *f) : file_(f) {}
public:
// Constructs a buffered_file object which doesn't represent any file.
buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
// Destroys the object closing the file it represents if any.
FMT_API ~buffered_file() FMT_DTOR_NOEXCEPT;
private:
buffered_file(const buffered_file &) = delete;
void operator=(const buffered_file &) = delete;
public:
buffered_file(buffered_file &&other) FMT_NOEXCEPT : file_(other.file_) {
other.file_ = FMT_NULL;
}
buffered_file& operator=(buffered_file &&other) {
close();
file_ = other.file_;
other.file_ = FMT_NULL;
return *this;
}
// Opens a file.
FMT_API buffered_file(cstring_view filename, cstring_view mode);
// Closes the file.
FMT_API void close();
// Returns the pointer to a FILE object representing this file.
FILE *get() const FMT_NOEXCEPT { return file_; }
// We place parentheses around fileno to workaround a bug in some versions
// of MinGW that define fileno as a macro.
FMT_API int (fileno)() const;
void vprint(string_view format_str, format_args args) {
fmt::vprint(file_, format_str, args);
}
template <typename... Args>
inline void print(string_view format_str, const Args & ... args) {
vprint(format_str, make_format_args(args...));
}
};
// A file. Closed file is represented by a file object with descriptor -1.
// Methods that are not declared with FMT_NOEXCEPT may throw
// fmt::system_error in case of failure. Note that some errors such as
// closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler.
class file {
private:
int fd_; // File descriptor.
// Constructs a file object with a given descriptor.
explicit file(int fd) : fd_(fd) {}
public:
// Possible values for the oflag argument to the constructor.
enum {
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
};
// Constructs a file object which doesn't represent any file.
file() FMT_NOEXCEPT : fd_(-1) {}
// Opens a file and constructs a file object representing this file.
FMT_API file(cstring_view path, int oflag);
private:
file(const file &) = delete;
void operator=(const file &) = delete;
public:
file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1;
}
file& operator=(file &&other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
// Destroys the object closing the file it represents if any.
FMT_API ~file() FMT_DTOR_NOEXCEPT;
// Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; }
// Closes the file.
FMT_API void close();
// Returns the file size. The size has signed type for consistency with
// stat::st_size.
FMT_API long long size() const;
// Attempts to read count bytes from the file into the specified buffer.
FMT_API std::size_t read(void *buffer, std::size_t count);
// Attempts to write count bytes from the specified buffer to the file.
FMT_API std::size_t write(const void *buffer, std::size_t count);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
FMT_API static file dup(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
FMT_API void dup2(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
FMT_API void dup2(int fd, error_code &ec) FMT_NOEXCEPT;
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
FMT_API static void pipe(file &read_end, file &write_end);
// Creates a buffered_file object associated with this file and detaches
// this file object from the file.
FMT_API buffered_file fdopen(const char *mode);
};
// Returns the memory page size.
long getpagesize();
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
!defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \
!defined(__NEWLIB_H__)
# define FMT_LOCALE
#endif
#ifdef FMT_LOCALE
// A "C" numeric locale.
class Locale {
private:
# ifdef _MSC_VER
typedef _locale_t locale_t;
enum { LC_NUMERIC_MASK = LC_NUMERIC };
static locale_t newlocale(int category_mask, const char *locale, locale_t) {
return _create_locale(category_mask, locale);
}
static void freelocale(locale_t locale) {
_free_locale(locale);
}
static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
return _strtod_l(nptr, endptr, locale);
}
# endif
locale_t locale_;
Locale(const Locale &) = delete;
void operator=(const Locale &) = delete;
public:
typedef locale_t Type;
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
if (!locale_)
FMT_THROW(system_error(errno, "cannot create locale"));
}
~Locale() { freelocale(locale_); }
Type get() const { return locale_; }
// Converts string to floating-point number and advances str past the end
// of the parsed input.
double strtod(const char *&str) const {
char *end = FMT_NULL;
double result = strtod_l(str, &end, locale_);
str = end;
return result;
}
};
#endif // FMT_LOCALE
FMT_END_NAMESPACE
#endif // FMT_POSIX_H_
+726
View File
@@ -0,0 +1,726 @@
// Formatting library for C++
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_PRINTF_H_
#define FMT_PRINTF_H_
#include <algorithm> // std::fill_n
#include <limits> // std::numeric_limits
#include "ostream.h"
FMT_BEGIN_NAMESPACE
namespace internal {
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template <bool IsSigned>
struct int_checker {
template <typename T>
static bool fits_in_int(T value) {
unsigned max = std::numeric_limits<int>::max();
return value <= max;
}
static bool fits_in_int(bool) { return true; }
};
template <>
struct int_checker<true> {
template <typename T>
static bool fits_in_int(T value) {
return value >= std::numeric_limits<int>::min() &&
value <= std::numeric_limits<int>::max();
}
static bool fits_in_int(int) { return true; }
};
class printf_precision_handler: public function<int> {
public:
template <typename T>
typename std::enable_if<std::is_integral<T>::value, int>::type
operator()(T value) {
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(format_error("number is too big"));
return static_cast<int>(value);
}
template <typename T>
typename std::enable_if<!std::is_integral<T>::value, int>::type operator()(T) {
FMT_THROW(format_error("precision is not integer"));
return 0;
}
};
// An argument visitor that returns true iff arg is a zero integer.
class is_zero_int: public function<bool> {
public:
template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
operator()(T value) { return value == 0; }
template <typename T>
typename std::enable_if<!std::is_integral<T>::value, bool>::type
operator()(T) { return false; }
};
template <typename T>
struct make_unsigned_or_bool : std::make_unsigned<T> {};
template <>
struct make_unsigned_or_bool<bool> {
typedef bool type;
};
template <typename T, typename Context>
class arg_converter: public function<void> {
private:
typedef typename Context::char_type Char;
basic_format_arg<Context> &arg_;
typename Context::char_type type_;
public:
arg_converter(basic_format_arg<Context> &arg, Char type)
: arg_(arg), type_(type) {}
void operator()(bool value) {
if (type_ != 's')
operator()<bool>(value);
}
template <typename U>
typename std::enable_if<std::is_integral<U>::value>::type
operator()(U value) {
bool is_signed = type_ == 'd' || type_ == 'i';
typedef typename std::conditional<
std::is_same<T, void>::value, U, T>::type TargetType;
if (const_check(sizeof(TargetType) <= sizeof(int))) {
// Extra casts are used to silence warnings.
if (is_signed) {
arg_ = internal::make_arg<Context>(
static_cast<int>(static_cast<TargetType>(value)));
} else {
typedef typename make_unsigned_or_bool<TargetType>::type Unsigned;
arg_ = internal::make_arg<Context>(
static_cast<unsigned>(static_cast<Unsigned>(value)));
}
} else {
if (is_signed) {
// glibc's printf doesn't sign extend arguments of smaller types:
// std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB.
arg_ = internal::make_arg<Context>(static_cast<long long>(value));
} else {
arg_ = internal::make_arg<Context>(
static_cast<typename make_unsigned_or_bool<U>::type>(value));
}
}
}
template <typename U>
typename std::enable_if<!std::is_integral<U>::value>::type operator()(U) {
// No coversion needed for non-integral types.
}
};
// Converts an integer argument to T for printf, if T is an integral type.
// If T is void, the argument is converted to corresponding signed or unsigned
// type depending on the type specifier: 'd' and 'i' - signed, other -
// unsigned).
template <typename T, typename Context, typename Char>
void convert_arg(basic_format_arg<Context> &arg, Char type) {
fmt::visit(arg_converter<T, Context>(arg, type), arg);
}
// Converts an integer argument to char for printf.
template <typename Context>
class char_converter: public function<void> {
private:
basic_format_arg<Context> &arg_;
public:
explicit char_converter(basic_format_arg<Context> &arg) : arg_(arg) {}
template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type
operator()(T value) {
typedef typename Context::char_type Char;
arg_ = internal::make_arg<Context>(static_cast<Char>(value));
}
template <typename T>
typename std::enable_if<!std::is_integral<T>::value>::type operator()(T) {
// No coversion needed for non-integral types.
}
};
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
template <typename Char>
class printf_width_handler: public function<unsigned> {
private:
typedef basic_format_specs<Char> format_specs;
format_specs &spec_;
public:
explicit printf_width_handler(format_specs &spec) : spec_(spec) {}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, unsigned>::type
operator()(T value) {
typedef typename internal::int_traits<T>::main_type UnsignedType;
UnsignedType width = static_cast<UnsignedType>(value);
if (internal::is_negative(value)) {
spec_.align_ = ALIGN_LEFT;
width = 0 - width;
}
unsigned int_max = std::numeric_limits<int>::max();
if (width > int_max)
FMT_THROW(format_error("number is too big"));
return static_cast<unsigned>(width);
}
template <typename T>
typename std::enable_if<!std::is_integral<T>::value, unsigned>::type
operator()(T) {
FMT_THROW(format_error("width is not integer"));
return 0;
}
};
} // namespace internal
template <typename Range>
class printf_arg_formatter;
template <
typename OutputIt, typename Char,
typename ArgFormatter =
printf_arg_formatter<back_insert_range<internal::basic_buffer<Char>>>>
class basic_printf_context;
/**
\rst
The ``printf`` argument formatter.
\endrst
*/
template <typename Range>
class printf_arg_formatter:
public internal::function<
typename internal::arg_formatter_base<Range>::iterator>,
public internal::arg_formatter_base<Range> {
private:
typedef typename Range::value_type char_type;
typedef decltype(internal::declval<Range>().begin()) iterator;
typedef internal::arg_formatter_base<Range> base;
typedef basic_printf_context<iterator, char_type> context_type;
context_type &context_;
void write_null_pointer(char) {
this->spec()->type_ = 0;
this->write("(nil)");
}
void write_null_pointer(wchar_t) {
this->spec()->type_ = 0;
this->write(L"(nil)");
}
public:
typedef typename base::format_specs format_specs;
/**
\rst
Constructs an argument formatter object.
*buffer* is a reference to the output buffer and *spec* contains format
specifier information for standard argument types.
\endrst
*/
printf_arg_formatter(internal::basic_buffer<char_type> &buffer,
format_specs &spec, context_type &ctx)
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec),
context_(ctx) {}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, iterator>::type
operator()(T value) {
// MSVC2013 fails to compile separate overloads for bool and char_type so
// use std::is_same instead.
if (std::is_same<T, bool>::value) {
format_specs &fmt_spec = *this->spec();
if (fmt_spec.type_ != 's')
return base::operator()(value ? 1 : 0);
fmt_spec.type_ = 0;
this->write(value != 0);
} else if (std::is_same<T, char_type>::value) {
format_specs &fmt_spec = *this->spec();
if (fmt_spec.type_ && fmt_spec.type_ != 'c')
return (*this)(static_cast<int>(value));
fmt_spec.flags_ = 0;
fmt_spec.align_ = ALIGN_RIGHT;
return base::operator()(value);
} else {
return base::operator()(value);
}
return this->out();
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, iterator>::type
operator()(T value) {
return base::operator()(value);
}
/** Formats a null-terminated C string. */
iterator operator()(const char *value) {
if (value)
base::operator()(value);
else if (this->spec()->type_ == 'p')
write_null_pointer(char_type());
else
this->write("(null)");
return this->out();
}
/** Formats a null-terminated wide C string. */
iterator operator()(const wchar_t *value) {
if (value)
base::operator()(value);
else if (this->spec()->type_ == 'p')
write_null_pointer(char_type());
else
this->write(L"(null)");
return this->out();
}
iterator operator()(basic_string_view<char_type> value) {
return base::operator()(value);
}
iterator operator()(monostate value) {
return base::operator()(value);
}
/** Formats a pointer. */
iterator operator()(const void *value) {
if (value)
return base::operator()(value);
this->spec()->type_ = 0;
write_null_pointer(char_type());
return this->out();
}
/** Formats an argument of a custom (user-defined) type. */
iterator operator()(typename basic_format_arg<context_type>::handle handle) {
handle.format(context_);
return this->out();
}
};
template <typename T>
struct printf_formatter {
template <typename ParseContext>
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); }
template <typename FormatContext>
auto format(const T &value, FormatContext &ctx) -> decltype(ctx.out()) {
internal::format_value(internal::get_container(ctx.out()), value);
return ctx.out();
}
};
/** This template formats data and writes the output to a writer. */
template <typename OutputIt, typename Char, typename ArgFormatter>
class basic_printf_context :
// Inherit publicly as a workaround for the icc bug
// https://software.intel.com/en-us/forums/intel-c-compiler/topic/783476.
public internal::context_base<
OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> {
public:
/** The character type for the output. */
typedef Char char_type;
template <typename T>
struct formatter_type { typedef printf_formatter<T> type; };
private:
typedef internal::context_base<OutputIt, basic_printf_context, Char> base;
typedef typename base::format_arg format_arg;
typedef basic_format_specs<char_type> format_specs;
typedef internal::null_terminating_iterator<char_type> iterator;
void parse_flags(format_specs &spec, iterator &it);
// Returns the argument with specified index or, if arg_index is equal
// to the maximum unsigned value, the next argument.
format_arg get_arg(
iterator it,
unsigned arg_index = (std::numeric_limits<unsigned>::max)());
// Parses argument index, flags and width and returns the argument index.
unsigned parse_header(iterator &it, format_specs &spec);
public:
/**
\rst
Constructs a ``printf_context`` object. References to the arguments and
the writer are stored in the context object so make sure they have
appropriate lifetimes.
\endrst
*/
basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
basic_format_args<basic_printf_context> args)
: base(out, format_str, args) {}
using base::parse_context;
using base::out;
using base::advance_to;
/** Formats stored arguments and writes the output to the range. */
void format();
};
template <typename OutputIt, typename Char, typename AF>
void basic_printf_context<OutputIt, Char, AF>::parse_flags(
format_specs &spec, iterator &it) {
for (;;) {
switch (*it++) {
case '-':
spec.align_ = ALIGN_LEFT;
break;
case '+':
spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
break;
case '0':
spec.fill_ = '0';
break;
case ' ':
spec.flags_ |= SIGN_FLAG;
break;
case '#':
spec.flags_ |= HASH_FLAG;
break;
default:
--it;
return;
}
}
}
template <typename OutputIt, typename Char, typename AF>
typename basic_printf_context<OutputIt, Char, AF>::format_arg
basic_printf_context<OutputIt, Char, AF>::get_arg(
iterator it, unsigned arg_index) {
(void)it;
if (arg_index == std::numeric_limits<unsigned>::max())
return this->do_get_arg(this->parse_context().next_arg_id());
return base::get_arg(arg_index - 1);
}
template <typename OutputIt, typename Char, typename AF>
unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
iterator &it, format_specs &spec) {
unsigned arg_index = std::numeric_limits<unsigned>::max();
char_type c = *it;
if (c >= '0' && c <= '9') {
// Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s).
internal::error_handler eh;
unsigned value = parse_nonnegative_int(it, eh);
if (*it == '$') { // value is an argument index
++it;
arg_index = value;
} else {
if (c == '0')
spec.fill_ = '0';
if (value != 0) {
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
spec.width_ = value;
return arg_index;
}
}
}
parse_flags(spec, it);
// Parse width.
if (*it >= '0' && *it <= '9') {
internal::error_handler eh;
spec.width_ = parse_nonnegative_int(it, eh);
} else if (*it == '*') {
++it;
spec.width_ =
fmt::visit(internal::printf_width_handler<char_type>(spec), get_arg(it));
}
return arg_index;
}
template <typename OutputIt, typename Char, typename AF>
void basic_printf_context<OutputIt, Char, AF>::format() {
auto &buffer = internal::get_container(this->out());
auto start = iterator(this->parse_context());
auto it = start;
using internal::pointer_from;
while (*it) {
char_type c = *it++;
if (c != '%') continue;
if (*it == c) {
buffer.append(pointer_from(start), pointer_from(it));
start = ++it;
continue;
}
buffer.append(pointer_from(start), pointer_from(it) - 1);
format_specs spec;
spec.align_ = ALIGN_RIGHT;
// Parse argument index, flags and width.
unsigned arg_index = parse_header(it, spec);
// Parse precision.
if (*it == '.') {
++it;
if ('0' <= *it && *it <= '9') {
internal::error_handler eh;
spec.precision_ = static_cast<int>(parse_nonnegative_int(it, eh));
} else if (*it == '*') {
++it;
spec.precision_ =
fmt::visit(internal::printf_precision_handler(), get_arg(it));
} else {
spec.precision_ = 0;
}
}
format_arg arg = get_arg(it, arg_index);
if (spec.flag(HASH_FLAG) && fmt::visit(internal::is_zero_int(), arg))
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
if (spec.fill_ == '0') {
if (arg.is_arithmetic())
spec.align_ = ALIGN_NUMERIC;
else
spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
}
// Parse length and convert the argument to the required type.
using internal::convert_arg;
switch (*it++) {
case 'h':
if (*it == 'h')
convert_arg<signed char>(arg, *++it);
else
convert_arg<short>(arg, *it);
break;
case 'l':
if (*it == 'l')
convert_arg<long long>(arg, *++it);
else
convert_arg<long>(arg, *it);
break;
case 'j':
convert_arg<intmax_t>(arg, *it);
break;
case 'z':
convert_arg<std::size_t>(arg, *it);
break;
case 't':
convert_arg<std::ptrdiff_t>(arg, *it);
break;
case 'L':
// printf produces garbage when 'L' is omitted for long double, no
// need to do the same.
break;
default:
--it;
convert_arg<void>(arg, *it);
}
// Parse type.
if (!*it)
FMT_THROW(format_error("invalid format string"));
spec.type_ = static_cast<char>(*it++);
if (arg.is_integral()) {
// Normalize type.
switch (spec.type_) {
case 'i': case 'u':
spec.type_ = 'd';
break;
case 'c':
// TODO: handle wchar_t better?
fmt::visit(internal::char_converter<basic_printf_context>(arg), arg);
break;
}
}
start = it;
// Format argument.
fmt::visit(AF(buffer, spec, *this), arg);
}
buffer.append(pointer_from(start), pointer_from(it));
}
template <typename Char, typename Context>
void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
Context(std::back_inserter(buf), format, args).format();
}
template <typename Buffer>
struct printf_context {
typedef basic_printf_context<
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
};
template <typename ...Args>
inline format_arg_store<printf_context<internal::buffer>::type, Args...>
make_printf_args(const Args & ... args) {
return format_arg_store<printf_context<internal::buffer>::type, Args...>(
args...);
}
typedef basic_format_args<printf_context<internal::buffer>::type> printf_args;
typedef basic_format_args<printf_context<internal::wbuffer>::type> wprintf_args;
inline std::string vsprintf(string_view format, printf_args args) {
memory_buffer buffer;
printf(buffer, format, args);
return to_string(buffer);
}
/**
\rst
Formats arguments and returns the result as a string.
**Example**::
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
template <typename... Args>
inline std::string sprintf(string_view format_str, const Args & ... args) {
return vsprintf(format_str,
make_format_args<typename printf_context<internal::buffer>::type>(args...));
}
inline std::wstring vsprintf(wstring_view format, wprintf_args args) {
wmemory_buffer buffer;
printf(buffer, format, args);
return to_string(buffer);
}
template <typename... Args>
inline std::wstring sprintf(wstring_view format_str, const Args & ... args) {
return vsprintf(format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
}
template <typename Char>
inline int vfprintf(std::FILE *f, basic_string_view<Char> format,
basic_format_args<typename printf_context<
internal::basic_buffer<Char>>::type> args) {
basic_memory_buffer<Char> buffer;
printf(buffer, format, args);
std::size_t size = buffer.size();
return std::fwrite(
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);
}
/**
\rst
Prints formatted data to the file *f*.
**Example**::
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
template <typename... Args>
inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) {
auto vargs = make_format_args<
typename printf_context<internal::buffer>::type>(args...);
return vfprintf<char>(f, format_str, vargs);
}
template <typename... Args>
inline int fprintf(std::FILE *f, wstring_view format_str,
const Args & ... args) {
return vfprintf(f, format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
}
inline int vprintf(string_view format, printf_args args) {
return vfprintf(stdout, format, args);
}
inline int vprintf(wstring_view format, wprintf_args args) {
return vfprintf(stdout, format, args);
}
/**
\rst
Prints formatted data to ``stdout``.
**Example**::
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
template <typename... Args>
inline int printf(string_view format_str, const Args & ... args) {
return vprintf(format_str,
make_format_args<typename printf_context<internal::buffer>::type>(args...));
}
template <typename... Args>
inline int printf(wstring_view format_str, const Args & ... args) {
return vprintf(format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
}
inline int vfprintf(std::ostream &os, string_view format_str,
printf_args args) {
memory_buffer buffer;
printf(buffer, format_str, args);
internal::write(os, buffer);
return static_cast<int>(buffer.size());
}
inline int vfprintf(std::wostream &os, wstring_view format_str,
wprintf_args args) {
wmemory_buffer buffer;
printf(buffer, format_str, args);
internal::write(os, buffer);
return static_cast<int>(buffer.size());
}
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fmt::fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
template <typename... Args>
inline int fprintf(std::ostream &os, string_view format_str,
const Args & ... args) {
auto vargs = make_format_args<
typename printf_context<internal::buffer>::type>(args...);
return vfprintf(os, format_str, vargs);
}
template <typename... Args>
inline int fprintf(std::wostream &os, wstring_view format_str,
const Args & ... args) {
auto vargs = make_format_args<
typename printf_context<internal::buffer>::type>(args...);
return vfprintf(os, format_str, vargs);
}
FMT_END_NAMESPACE
#endif // FMT_PRINTF_H_
+308
View File
@@ -0,0 +1,308 @@
// Formatting library for C++ - the core API
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
//
// Copyright (c) 2018 - present, Remotion (Igor Schulz)
// All Rights Reserved
// {fmt} support for ranges, containers and types tuple interface.
#ifndef FMT_RANGES_H_
#define FMT_RANGES_H_
#include "format.h"
#include <type_traits>
// output only up to N items from the range.
#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
#endif
FMT_BEGIN_NAMESPACE
template <typename Char>
struct formatting_base {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
};
template <typename Char, typename Enable = void>
struct formatting_range : formatting_base<Char> {
static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range.
Char prefix;
Char delimiter;
Char postfix;
formatting_range() : prefix('{'), delimiter(','), postfix('}') {}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
};
template <typename Char, typename Enable = void>
struct formatting_tuple : formatting_base<Char> {
Char prefix;
Char delimiter;
Char postfix;
formatting_tuple() : prefix('('), delimiter(','), postfix(')') {}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
};
namespace internal {
template <typename RangeT, typename OutputIterator>
void copy(const RangeT &range, OutputIterator out) {
for (auto it = range.begin(), end = range.end(); it != end; ++it)
*out++ = *it;
}
template <typename OutputIterator>
void copy(const char *str, OutputIterator out) {
const char *p_curr = str;
while (*p_curr) {
*out++ = *p_curr++;
}
}
template <typename OutputIterator>
void copy(char ch, OutputIterator out) {
*out++ = ch;
}
/// Return true value if T has std::string interface, like std::string_view.
template <typename T>
class is_like_std_string {
template <typename U>
static auto check(U *p) ->
decltype(p->find('a'), p->length(), p->data(), int());
template <typename>
static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
};
template <typename Char>
struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {};
template <typename... Ts>
struct conditional_helper {};
template <typename T, typename _ = void>
struct is_range_ : std::false_type {};
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
template <typename T>
struct is_range_<T, typename std::conditional<
false,
conditional_helper<decltype(internal::declval<T>().begin()),
decltype(internal::declval<T>().end())>,
void>::type> : std::true_type {};
#endif
/// tuple_size and tuple_element check.
template <typename T>
class is_tuple_like_ {
template <typename U>
static auto check(U *p) ->
decltype(std::tuple_size<U>::value,
internal::declval<typename std::tuple_element<0, U>::type>(), int());
template <typename>
static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
};
// Check for integer_sequence
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
template <typename T, T... N>
using integer_sequence = std::integer_sequence<T, N...>;
template <std::size_t... N>
using index_sequence = std::index_sequence<N...>;
template <std::size_t N>
using make_index_sequence = std::make_index_sequence<N>;
#else
template <typename T, T... N>
struct integer_sequence {
typedef T value_type;
static FMT_CONSTEXPR std::size_t size() {
return sizeof...(N);
}
};
template <std::size_t... N>
using index_sequence = integer_sequence<std::size_t, N...>;
template <typename T, std::size_t N, T... Ns>
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
template <typename T, T... Ns>
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
template <std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
#endif
template <class Tuple, class F, size_t... Is>
void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT {
using std::get;
// using free function get<I>(T) now.
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
(void)_; // blocks warnings
}
template <class T>
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value>
get_indexes(T const &) { return {}; }
template <class Tuple, class F>
void for_each(Tuple &&tup, F &&f) {
const auto indexes = get_indexes(tup);
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
}
template<typename Arg>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
typename std::enable_if<
!is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
return add_space ? " {}" : "{}";
}
template<typename Arg>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
typename std::enable_if<
is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
return add_space ? " \"{}\"" : "\"{}\"";
}
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) {
return add_space ? " \"{}\"" : "\"{}\"";
}
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) {
return add_space ? L" \"{}\"" : L"\"{}\"";
}
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
return add_space ? " '{}'" : "'{}'";
}
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
return add_space ? L" '{}'" : L"'{}'";
}
} // namespace internal
template <typename T>
struct is_tuple_like {
static FMT_CONSTEXPR_DECL const bool value =
internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
};
template <typename TupleT, typename Char>
struct formatter<TupleT, Char,
typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> {
private:
// C++11 generic lambda for format()
template <typename FormatContext>
struct format_each {
template <typename T>
void operator()(const T& v) {
if (i > 0) {
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.delimiter, out);
}
format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), v),
v);
++i;
}
formatting_tuple<Char>& formatting;
std::size_t& i;
typename std::add_lvalue_reference<decltype(std::declval<FormatContext>().out())>::type out;
};
public:
formatting_tuple<Char> formatting;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return formatting.parse(ctx);
}
template <typename FormatContext = format_context>
auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) {
auto out = ctx.out();
std::size_t i = 0;
internal::copy(formatting.prefix, out);
internal::for_each(values, format_each<FormatContext>{formatting, i, out});
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.postfix, out);
return ctx.out();
}
};
template <typename T>
struct is_range {
static FMT_CONSTEXPR_DECL const bool value =
internal::is_range_<T>::value && !internal::is_like_std_string<T>::value;
};
template <typename RangeT, typename Char>
struct formatter<RangeT, Char,
typename std::enable_if<fmt::is_range<RangeT>::value>::type> {
formatting_range<Char> formatting;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return formatting.parse(ctx);
}
template <typename FormatContext>
typename FormatContext::iterator format(
const RangeT &values, FormatContext &ctx) {
auto out = ctx.out();
internal::copy(formatting.prefix, out);
std::size_t i = 0;
for (auto it = values.begin(), end = values.end(); it != end; ++it) {
if (i > 0) {
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.delimiter, out);
}
format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), *it),
*it);
if (++i > formatting.range_length_limit) {
format_to(out, " ... <other elements>");
break;
}
}
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.postfix, out);
return ctx.out();
}
};
FMT_END_NAMESPACE
#endif // FMT_RANGES_H_
+156
View File
@@ -0,0 +1,156 @@
// Formatting library for C++ - time formatting
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_TIME_H_
#define FMT_TIME_H_
#include "format.h"
#include <ctime>
FMT_BEGIN_NAMESPACE
// Prevents expansion of a preceding token as a function-style macro.
// Usage: f FMT_NOMACRO()
#define FMT_NOMACRO
namespace internal{
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
inline null<> localtime_s(...) { return null<>(); }
inline null<> gmtime_r(...) { return null<>(); }
inline null<> gmtime_s(...) { return null<>(); }
}
// Thread-safe replacement for std::localtime
inline std::tm localtime(std::time_t time) {
struct dispatcher {
std::time_t time_;
std::tm tm_;
dispatcher(std::time_t t): time_(t) {}
bool run() {
using namespace fmt::internal;
return handle(localtime_r(&time_, &tm_));
}
bool handle(std::tm *tm) { return tm != FMT_NULL; }
bool handle(internal::null<>) {
using namespace fmt::internal;
return fallback(localtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
bool fallback(internal::null<>) {
using namespace fmt::internal;
std::tm *tm = std::localtime(&time_);
if (tm) tm_ = *tm;
return tm != FMT_NULL;
}
};
dispatcher lt(time);
if (lt.run())
return lt.tm_;
// Too big time values may be unsupported.
FMT_THROW(format_error("time_t value out of range"));
}
// Thread-safe replacement for std::gmtime
inline std::tm gmtime(std::time_t time) {
struct dispatcher {
std::time_t time_;
std::tm tm_;
dispatcher(std::time_t t): time_(t) {}
bool run() {
using namespace fmt::internal;
return handle(gmtime_r(&time_, &tm_));
}
bool handle(std::tm *tm) { return tm != FMT_NULL; }
bool handle(internal::null<>) {
using namespace fmt::internal;
return fallback(gmtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
bool fallback(internal::null<>) {
std::tm *tm = std::gmtime(&time_);
if (tm) tm_ = *tm;
return tm != FMT_NULL;
}
};
dispatcher gt(time);
if (gt.run())
return gt.tm_;
// Too big time values may be unsupported.
FMT_THROW(format_error("time_t value out of range"));
}
namespace internal {
inline std::size_t strftime(char *str, std::size_t count, const char *format,
const std::tm *time) {
return std::strftime(str, count, format, time);
}
inline std::size_t strftime(wchar_t *str, std::size_t count,
const wchar_t *format, const std::tm *time) {
return std::wcsftime(str, count, format, time);
}
}
template <typename Char>
struct formatter<std::tm, Char> {
template <typename ParseContext>
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
auto it = internal::null_terminating_iterator<Char>(ctx);
if (*it == ':')
++it;
auto end = it;
while (*end && *end != '}')
++end;
tm_format.reserve(end - it + 1);
using internal::pointer_from;
tm_format.append(pointer_from(it), pointer_from(end));
tm_format.push_back('\0');
return pointer_from(end);
}
template <typename FormatContext>
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
internal::basic_buffer<Char> &buf = internal::get_container(ctx.out());
std::size_t start = buf.size();
for (;;) {
std::size_t size = buf.capacity() - start;
std::size_t count =
internal::strftime(&buf[start], size, &tm_format[0], &tm);
if (count != 0) {
buf.resize(start + count);
break;
}
if (size >= tm_format.size() * 256) {
// If the buffer is 256 times larger than the format string, assume
// that `strftime` gives an empty result. There doesn't seem to be a
// better way to distinguish the two cases:
// https://github.com/fmtlib/fmt/issues/367
break;
}
const std::size_t MIN_GROWTH = 10;
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
}
return ctx.out();
}
basic_memory_buffer<Char> tm_format;
};
FMT_END_NAMESPACE
#endif // FMT_TIME_H_
+25
View File
@@ -0,0 +1,25 @@
//
// Copyright(c) 2016-2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// Include a bundled header-only copy of fmtlib or an external one.
// By default spdlog include its own copy.
//
#if !defined(SPDLOG_FMT_EXTERNAL)
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#ifndef FMT_USE_WINDOWS_H
#define FMT_USE_WINDOWS_H 0
#endif
#include "spdlog/fmt/bundled/core.h"
#include "spdlog/fmt/bundled/format.h"
#else // external fmtlib
#include <fmt/core.h>
#include <fmt/format.h>
#endif
+18
View File
@@ -0,0 +1,18 @@
//
// Copyright(c) 2016 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// include bundled or external copy of fmtlib's ostream support
//
#if !defined(SPDLOG_FMT_EXTERNAL)
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include "spdlog/fmt/bundled/ostream.h"
#include "fmt.h"
#else
#include <fmt/ostream.h>
#endif
+20
View File
@@ -0,0 +1,20 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/fmt/fmt.h"
#include "spdlog/details/log_msg.h"
namespace spdlog {
class formatter
{
public:
virtual ~formatter() = default;
virtual void format(const details::log_msg &msg, fmt::memory_buffer &dest) = 0;
virtual std::unique_ptr<formatter> clone() const = 0;
};
} // namespace spdlog
+167
View File
@@ -0,0 +1,167 @@
//
// Copyright(c) 2015-2108 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Thread safe logger (except for set_pattern(..), set_formatter(..) and
// set_error_handler())
// Has name, log level, vector of std::shared sink pointers and formatter
// Upon each log write the logger:
// 1. Checks if its log level is enough to log the message and if yes:
// 2. Call the underlying sinks to do the job.
// 3. Each sink use its own private copy of a formatter to format the message
// and send to its destination.
//
// The use of private formatter per sink provides the opportunity to cache some
// formatted data,
// and support customize format per each sink.
#include "spdlog/common.h"
#include "spdlog/formatter.h"
#include "spdlog/sinks/sink.h"
#include <locale>
#include <memory>
#include <string>
#include <vector>
namespace spdlog {
class logger
{
public:
logger(std::string name, sink_ptr single_sink);
logger(std::string name, sinks_init_list sinks);
template<typename It>
logger(std::string name, It begin, It end);
virtual ~logger();
logger(const logger &) = delete;
logger &operator=(const logger &) = delete;
template<typename... Args>
void log(level::level_enum lvl, const char *fmt, const Args &... args);
template<typename... Args>
void log(level::level_enum lvl, const char *msg);
template<typename... Args>
void trace(const char *fmt, const Args &... args);
template<typename... Args>
void debug(const char *fmt, const Args &... args);
template<typename... Args>
void info(const char *fmt, const Args &... args);
template<typename... Args>
void warn(const char *fmt, const Args &... args);
template<typename... Args>
void error(const char *fmt, const Args &... args);
template<typename... Args>
void critical(const char *fmt, const Args &... args);
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
#ifndef _WIN32
#error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows
#else
template<typename... Args>
void log(level::level_enum lvl, const wchar_t *fmt, const Args &... args);
template<typename... Args>
void trace(const wchar_t *fmt, const Args &... args);
template<typename... Args>
void debug(const wchar_t *fmt, const Args &... args);
template<typename... Args>
void info(const wchar_t *fmt, const Args &... args);
template<typename... Args>
void warn(const wchar_t *fmt, const Args &... args);
template<typename... Args>
void error(const wchar_t *fmt, const Args &... args);
template<typename... Args>
void critical(const wchar_t *fmt, const Args &... args);
#endif // _WIN32
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
template<typename T>
void log(level::level_enum lvl, const T &);
template<typename T>
void trace(const T &msg);
template<typename T>
void debug(const T &msg);
template<typename T>
void info(const T &msg);
template<typename T>
void warn(const T &msg);
template<typename T>
void error(const T &msg);
template<typename T>
void critical(const T &msg);
bool should_log(level::level_enum msg_level) const;
void set_level(level::level_enum log_level);
level::level_enum level() const;
const std::string &name() const;
// set formatting for the sinks in this logger.
// each sink will get a seperate instance of the formatter object.
void set_formatter(std::unique_ptr<formatter> formatter);
void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local);
// flush functions
void flush();
void flush_on(level::level_enum log_level);
level::level_enum flush_level() const;
// sinks
const std::vector<sink_ptr> &sinks() const;
std::vector<sink_ptr> &sinks();
// error handler
void set_error_handler(log_err_handler err_handler);
log_err_handler error_handler();
// create new logger with same sinks and configuration.
virtual std::shared_ptr<logger> clone(std::string logger_name);
protected:
virtual void sink_it_(details::log_msg &msg);
virtual void flush_();
bool should_flush_(const details::log_msg &msg);
// default error handler: print the error to stderr with the max rate of 1
// message/minute
void default_err_handler_(const std::string &msg);
// increment the message count (only if defined(SPDLOG_ENABLE_MESSAGE_COUNTER))
void incr_msg_counter_(details::log_msg &msg);
const std::string name_;
std::vector<sink_ptr> sinks_;
spdlog::level_t level_;
spdlog::level_t flush_level_;
log_err_handler err_handler_;
std::atomic<time_t> last_err_time_;
std::atomic<size_t> msg_counter_;
};
} // namespace spdlog
#include "spdlog/details/logger_impl.h"
+117
View File
@@ -0,0 +1,117 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/fmt_helper.h"
#include "spdlog/details/null_mutex.h"
#include "spdlog/details/os.h"
#include "spdlog/sinks/base_sink.h"
#include <android/log.h>
#include <chrono>
#include <mutex>
#include <string>
#include <thread>
#if !defined(SPDLOG_ANDROID_RETRIES)
#define SPDLOG_ANDROID_RETRIES 2
#endif
namespace spdlog {
namespace sinks {
/*
* Android sink (logging using __android_log_write)
*/
template<typename Mutex>
class android_sink final : public base_sink<Mutex>
{
public:
explicit android_sink(std::string tag = "spdlog", bool use_raw_msg = false)
: tag_(std::move(tag))
, use_raw_msg_(use_raw_msg)
{
}
protected:
void sink_it_(const details::log_msg &msg) override
{
const android_LogPriority priority = convert_to_android_(msg.level);
fmt::memory_buffer formatted;
if (use_raw_msg_)
{
details::fmt_helper::append_buf(msg.raw, formatted);
}
else
{
sink::formatter_->format(msg, formatted);
}
formatted.push_back('\0');
const char *msg_output = formatted.data();
// See system/core/liblog/logger_write.c for explanation of return value
int ret = __android_log_write(priority, tag_.c_str(), msg_output);
int retry_count = 0;
while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES))
{
details::os::sleep_for_millis(5);
ret = __android_log_write(priority, tag_.c_str(), msg_output);
retry_count++;
}
if (ret < 0)
{
throw spdlog_ex("__android_log_write() failed", ret);
}
}
void flush_() override {}
private:
static android_LogPriority convert_to_android_(spdlog::level::level_enum level)
{
switch (level)
{
case spdlog::level::trace:
return ANDROID_LOG_VERBOSE;
case spdlog::level::debug:
return ANDROID_LOG_DEBUG;
case spdlog::level::info:
return ANDROID_LOG_INFO;
case spdlog::level::warn:
return ANDROID_LOG_WARN;
case spdlog::level::err:
return ANDROID_LOG_ERROR;
case spdlog::level::critical:
return ANDROID_LOG_FATAL;
default:
return ANDROID_LOG_DEFAULT;
}
}
std::string tag_;
bool use_raw_msg_;
};
using android_sink_mt = android_sink<std::mutex>;
using android_sink_st = android_sink<details::null_mutex>;
} // namespace sinks
// Create and register android syslog logger
template<typename Factory = default_factory>
inline std::shared_ptr<logger> android_logger_mt(const std::string &logger_name, const std::string &tag = "spdlog")
{
return Factory::template create<sinks::android_sink_mt>(logger_name, tag);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> android_logger_st(const std::string &logger_name, const std::string &tag = "spdlog")
{
return Factory::template create<sinks::android_sink_st>(logger_name, tag);
}
} // namespace spdlog
+157
View File
@@ -0,0 +1,157 @@
//
// Copyright(c) 2017 spdlog authors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/console_globals.h"
#include "spdlog/details/null_mutex.h"
#include "spdlog/details/os.h"
#include "spdlog/sinks/sink.h"
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
namespace spdlog {
namespace sinks {
/**
* This sink prefixes the output with an ANSI escape sequence color code
* depending on the severity
* of the message.
* If no color terminal detected, omit the escape codes.
*/
template<typename TargetStream, class ConsoleMutex>
class ansicolor_sink final : public sink
{
public:
using mutex_t = typename ConsoleMutex::mutex_t;
ansicolor_sink()
: target_file_(TargetStream::stream())
, mutex_(ConsoleMutex::mutex())
{
should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal();
colors_[level::trace] = white;
colors_[level::debug] = cyan;
colors_[level::info] = green;
colors_[level::warn] = yellow + bold;
colors_[level::err] = red + bold;
colors_[level::critical] = bold + on_red;
colors_[level::off] = reset;
}
~ansicolor_sink() override = default;
ansicolor_sink(const ansicolor_sink &other) = delete;
ansicolor_sink &operator=(const ansicolor_sink &other) = delete;
void set_color(level::level_enum color_level, const std::string &color)
{
std::lock_guard<mutex_t> lock(mutex_);
colors_[color_level] = color;
}
/// Formatting codes
const std::string reset = "\033[m";
const std::string bold = "\033[1m";
const std::string dark = "\033[2m";
const std::string underline = "\033[4m";
const std::string blink = "\033[5m";
const std::string reverse = "\033[7m";
const std::string concealed = "\033[8m";
const std::string clear_line = "\033[K";
// Foreground colors
const std::string black = "\033[30m";
const std::string red = "\033[31m";
const std::string green = "\033[32m";
const std::string yellow = "\033[33m";
const std::string blue = "\033[34m";
const std::string magenta = "\033[35m";
const std::string cyan = "\033[36m";
const std::string white = "\033[37m";
/// Background colors
const std::string on_black = "\033[40m";
const std::string on_red = "\033[41m";
const std::string on_green = "\033[42m";
const std::string on_yellow = "\033[43m";
const std::string on_blue = "\033[44m";
const std::string on_magenta = "\033[45m";
const std::string on_cyan = "\033[46m";
const std::string on_white = "\033[47m";
void log(const details::log_msg &msg) override
{
// Wrap the originally formatted message in color codes.
// If color is not supported in the terminal, log as is instead.
std::lock_guard<mutex_t> lock(mutex_);
fmt::memory_buffer formatted;
formatter_->format(msg, formatted);
if (should_do_colors_ && msg.color_range_end > msg.color_range_start)
{
// before color range
print_range_(formatted, 0, msg.color_range_start);
// in color range
print_ccode_(colors_[msg.level]);
print_range_(formatted, msg.color_range_start, msg.color_range_end);
print_ccode_(reset);
// after color range
print_range_(formatted, msg.color_range_end, formatted.size());
}
else // no color
{
print_range_(formatted, 0, formatted.size());
}
fflush(target_file_);
}
void flush() override
{
std::lock_guard<mutex_t> lock(mutex_);
fflush(target_file_);
}
void set_pattern(const std::string &pattern) final
{
std::lock_guard<mutex_t> lock(mutex_);
formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern));
}
void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override
{
std::lock_guard<mutex_t> lock(mutex_);
formatter_ = std::move(sink_formatter);
}
private:
void print_ccode_(const std::string &color_code)
{
fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_);
}
void print_range_(const fmt::memory_buffer &formatted, size_t start, size_t end)
{
fwrite(formatted.data() + start, sizeof(char), end - start, target_file_);
}
FILE *target_file_;
mutex_t &mutex_;
bool should_do_colors_;
std::unordered_map<level::level_enum, std::string, level::level_hasher> colors_;
};
using ansicolor_stdout_sink_mt = ansicolor_sink<details::console_stdout, details::console_mutex>;
using ansicolor_stdout_sink_st = ansicolor_sink<details::console_stdout, details::console_nullmutex>;
using ansicolor_stderr_sink_mt = ansicolor_sink<details::console_stderr, details::console_mutex>;
using ansicolor_stderr_sink_st = ansicolor_sink<details::console_stderr, details::console_nullmutex>;
} // namespace sinks
} // namespace spdlog
+69
View File
@@ -0,0 +1,69 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// base sink templated over a mutex (either dummy or real)
// concrete implementation should override the sink_it_() and flush_() methods.
// locking is taken care of in this class - no locking needed by the
// implementers..
//
#include "spdlog/common.h"
#include "spdlog/details/log_msg.h"
#include "spdlog/formatter.h"
#include "spdlog/sinks/sink.h"
namespace spdlog {
namespace sinks {
template<typename Mutex>
class base_sink : public sink
{
public:
base_sink() = default;
base_sink(const base_sink &) = delete;
base_sink &operator=(const base_sink &) = delete;
void log(const details::log_msg &msg) final
{
std::lock_guard<Mutex> lock(mutex_);
sink_it_(msg);
}
void flush() final
{
std::lock_guard<Mutex> lock(mutex_);
flush_();
}
void set_pattern(const std::string &pattern) final
{
std::lock_guard<Mutex> lock(mutex_);
set_pattern_(pattern);
}
void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) final
{
std::lock_guard<Mutex> lock(mutex_);
set_formatter_(std::move(sink_formatter));
}
protected:
virtual void sink_it_(const details::log_msg &msg) = 0;
virtual void flush_() = 0;
virtual void set_pattern_(const std::string &pattern)
{
set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern));
}
virtual void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter)
{
formatter_ = std::move(sink_formatter);
}
Mutex mutex_;
};
} // namespace sinks
} // namespace spdlog
+66
View File
@@ -0,0 +1,66 @@
//
// Copyright(c) 2015-2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/file_helper.h"
#include "spdlog/details/null_mutex.h"
#include "spdlog/sinks/base_sink.h"
#include "spdlog/spdlog.h"
#include <mutex>
#include <string>
namespace spdlog {
namespace sinks {
/*
* Trivial file sink with single file as target
*/
template<typename Mutex>
class basic_file_sink final : public base_sink<Mutex>
{
public:
explicit basic_file_sink(const filename_t &filename, bool truncate = false)
{
file_helper_.open(filename, truncate);
}
protected:
void sink_it_(const details::log_msg &msg) override
{
fmt::memory_buffer formatted;
sink::formatter_->format(msg, formatted);
file_helper_.write(formatted);
}
void flush_() override
{
file_helper_.flush();
}
private:
details::file_helper file_helper_;
};
using basic_file_sink_mt = basic_file_sink<std::mutex>;
using basic_file_sink_st = basic_file_sink<details::null_mutex>;
} // namespace sinks
//
// factory functions
//
template<typename Factory = default_factory>
inline std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false)
{
return Factory::template create<sinks::basic_file_sink_mt>(logger_name, filename, truncate);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false)
{
return Factory::template create<sinks::basic_file_sink_st>(logger_name, filename, truncate);
}
} // namespace spdlog
+132
View File
@@ -0,0 +1,132 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/file_helper.h"
#include "spdlog/details/null_mutex.h"
#include "spdlog/fmt/fmt.h"
#include "spdlog/sinks/base_sink.h"
#include "spdlog/spdlog.h"
#include <chrono>
#include <cstdio>
#include <ctime>
#include <mutex>
#include <string>
namespace spdlog {
namespace sinks {
/*
* Generator of daily log file names in format basename.YYYY-MM-DD.ext
*/
struct daily_filename_calculator
{
// Create filename for the form basename.YYYY-MM-DD
static filename_t calc_filename(const filename_t &filename, const tm &now_tm)
{
filename_t basename, ext;
std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);
std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::memory_buffer, fmt::wmemory_buffer>::type w;
fmt::format_to(
w, SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext);
return fmt::to_string(w);
}
};
/*
* Rotating file sink based on date. rotates at midnight
*/
template<typename Mutex, typename FileNameCalc = daily_filename_calculator>
class daily_file_sink final : public base_sink<Mutex>
{
public:
// create daily file sink which rotates on given time
daily_file_sink(filename_t base_filename, int rotation_hour, int rotation_minute, bool truncate = false)
: base_filename_(std::move(base_filename))
, rotation_h_(rotation_hour)
, rotation_m_(rotation_minute)
, truncate_(truncate)
{
if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)
{
throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor");
}
auto now = log_clock::now();
file_helper_.open(FileNameCalc::calc_filename(base_filename_, now_tm(now)), truncate_);
rotation_tp_ = next_rotation_tp_();
}
protected:
void sink_it_(const details::log_msg &msg) override
{
if (msg.time >= rotation_tp_)
{
file_helper_.open(FileNameCalc::calc_filename(base_filename_, now_tm(msg.time)), truncate_);
rotation_tp_ = next_rotation_tp_();
}
fmt::memory_buffer formatted;
sink::formatter_->format(msg, formatted);
file_helper_.write(formatted);
}
void flush_() override
{
file_helper_.flush();
}
private:
tm now_tm(log_clock::time_point tp)
{
time_t tnow = log_clock::to_time_t(tp);
return spdlog::details::os::localtime(tnow);
}
log_clock::time_point next_rotation_tp_()
{
auto now = log_clock::now();
tm date = now_tm(now);
date.tm_hour = rotation_h_;
date.tm_min = rotation_m_;
date.tm_sec = 0;
auto rotation_time = log_clock::from_time_t(std::mktime(&date));
if (rotation_time > now)
{
return rotation_time;
}
return {rotation_time + std::chrono::hours(24)};
}
filename_t base_filename_;
int rotation_h_;
int rotation_m_;
log_clock::time_point rotation_tp_;
details::file_helper file_helper_;
bool truncate_;
};
using daily_file_sink_mt = daily_file_sink<std::mutex>;
using daily_file_sink_st = daily_file_sink<details::null_mutex>;
} // namespace sinks
//
// factory functions
//
template<typename Factory = default_factory>
inline std::shared_ptr<logger> daily_logger_mt(
const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false)
{
return Factory::template create<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute, truncate);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> daily_logger_st(
const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false)
{
return Factory::template create<sinks::daily_file_sink_st>(logger_name, filename, hour, minute, truncate);
}
} // namespace spdlog
+90
View File
@@ -0,0 +1,90 @@
//
// Copyright (c) 2015 David Schury, Gabi Melman
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "base_sink.h"
#include "spdlog/details/log_msg.h"
#include "spdlog/details/null_mutex.h"
#include <algorithm>
#include <memory>
#include <mutex>
#include <vector>
// Distribution sink (mux). Stores a vector of sinks which get called when log
// is called
namespace spdlog {
namespace sinks {
template<typename Mutex>
class dist_sink : public base_sink<Mutex>
{
public:
dist_sink() = default;
dist_sink(const dist_sink &) = delete;
dist_sink &operator=(const dist_sink &) = delete;
void add_sink(std::shared_ptr<sink> sink)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
sinks_.push_back(sink);
}
void remove_sink(std::shared_ptr<sink> sink)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end());
}
void set_sinks(std::vector<std::shared_ptr<sink>> sinks)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
sinks_ = std::move(sinks);
}
protected:
void sink_it_(const details::log_msg &msg) override
{
for (auto &sink : sinks_)
{
if (sink->should_log(msg.level))
{
sink->log(msg);
}
}
}
void flush_() override
{
for (auto &sink : sinks_)
{
sink->flush();
}
}
void set_pattern_(const std::string &pattern) override
{
set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern));
}
void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter) override
{
base_sink<Mutex>::formatter_ = std::move(sink_formatter);
for (auto &sink : sinks_)
{
sink->set_formatter(base_sink<Mutex>::formatter_->clone());
}
}
std::vector<std::shared_ptr<sink>> sinks_;
};
using dist_sink_mt = dist_sink<std::mutex>;
using dist_sink_st = dist_sink<details::null_mutex>;
} // namespace sinks
} // namespace spdlog
+50
View File
@@ -0,0 +1,50 @@
//
// Copyright(c) 2016 Alexander Dalshov.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#if defined(_WIN32)
#include "spdlog/details/null_mutex.h"
#include "spdlog/sinks/base_sink.h"
#include <winbase.h>
#include <mutex>
#include <string>
namespace spdlog {
namespace sinks {
/*
* MSVC sink (logging using OutputDebugStringA)
*/
template<typename Mutex>
class msvc_sink : public base_sink<Mutex>
{
public:
explicit msvc_sink() {}
protected:
void sink_it_(const details::log_msg &msg) override
{
fmt::memory_buffer formatted;
sink::formatter_->format(msg, formatted);
OutputDebugStringA(fmt::to_string(formatted).c_str());
}
void flush_() override {}
};
using msvc_sink_mt = msvc_sink<std::mutex>;
using msvc_sink_st = msvc_sink<details::null_mutex>;
using windebug_sink_mt = msvc_sink_mt;
using windebug_sink_st = msvc_sink_st;
} // namespace sinks
} // namespace spdlog
#endif
+28
View File
@@ -0,0 +1,28 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/null_mutex.h"
#include "spdlog/sinks/base_sink.h"
#include <mutex>
namespace spdlog {
namespace sinks {
template<typename Mutex>
class null_sink : public base_sink<Mutex>
{
protected:
void sink_it_(const details::log_msg &) override {}
void flush_() override {}
};
using null_sink_mt = null_sink<std::mutex>;
using null_sink_st = null_sink<details::null_mutex>;
} // namespace sinks
} // namespace spdlog
+53
View File
@@ -0,0 +1,53 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/null_mutex.h"
#include "spdlog/sinks/base_sink.h"
#include <mutex>
#include <ostream>
namespace spdlog {
namespace sinks {
template<typename Mutex>
class ostream_sink final : public base_sink<Mutex>
{
public:
explicit ostream_sink(std::ostream &os, bool force_flush = false)
: ostream_(os)
, force_flush_(force_flush)
{
}
ostream_sink(const ostream_sink &) = delete;
ostream_sink &operator=(const ostream_sink &) = delete;
protected:
void sink_it_(const details::log_msg &msg) override
{
fmt::memory_buffer formatted;
sink::formatter_->format(msg, formatted);
ostream_.write(formatted.data(), static_cast<std::streamsize>(formatted.size()));
if (force_flush_)
{
ostream_.flush();
}
}
void flush_() override
{
ostream_.flush();
}
std::ostream &ostream_;
bool force_flush_;
};
using ostream_sink_mt = ostream_sink<std::mutex>;
using ostream_sink_st = ostream_sink<details::null_mutex>;
} // namespace sinks
} // namespace spdlog
+150
View File
@@ -0,0 +1,150 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/file_helper.h"
#include "spdlog/details/null_mutex.h"
#include "spdlog/fmt/fmt.h"
#include "spdlog/sinks/base_sink.h"
#include "spdlog/spdlog.h"
#include <cerrno>
#include <chrono>
#include <ctime>
#include <mutex>
#include <string>
#include <tuple>
namespace spdlog {
namespace sinks {
//
// Rotating file sink based on size
//
template<typename Mutex>
class rotating_file_sink final : public base_sink<Mutex>
{
public:
rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files)
: base_filename_(std::move(base_filename))
, max_size_(max_size)
, max_files_(max_files)
{
file_helper_.open(calc_filename(base_filename_, 0));
current_size_ = file_helper_.size(); // expensive. called only once
}
// calc filename according to index and file extension if exists.
// e.g. calc_filename("logs/mylog.txt, 3) => "logs/mylog.3.txt".
static filename_t calc_filename(const filename_t &filename, std::size_t index)
{
typename std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::memory_buffer, fmt::wmemory_buffer>::type w;
if (index != 0u)
{
filename_t basename, ext;
std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);
fmt::format_to(w, SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext);
}
else
{
fmt::format_to(w, SPDLOG_FILENAME_T("{}"), filename);
}
return fmt::to_string(w);
}
protected:
void sink_it_(const details::log_msg &msg) override
{
fmt::memory_buffer formatted;
sink::formatter_->format(msg, formatted);
current_size_ += formatted.size();
if (current_size_ > max_size_)
{
rotate_();
current_size_ = formatted.size();
}
file_helper_.write(formatted);
}
void flush_() override
{
file_helper_.flush();
}
private:
// Rotate files:
// log.txt -> log.1.txt
// log.1.txt -> log.2.txt
// log.2.txt -> log.3.txt
// log.3.txt -> delete
void rotate_()
{
using details::os::filename_to_str;
file_helper_.close();
for (auto i = max_files_; i > 0; --i)
{
filename_t src = calc_filename(base_filename_, i - 1);
if (!details::file_helper::file_exists(src))
{
continue;
}
filename_t target = calc_filename(base_filename_, i);
if (!rename_file(src, target))
{
// if failed try again after a small delay.
// this is a workaround to a windows issue, where very high rotation
// rates can cause the rename to fail with permission denied (because of antivirus?).
details::os::sleep_for_millis(100);
if (!rename_file(src, target))
{
file_helper_.reopen(true); // truncate the log file anyway to prevent it to grow beyond its limit!
throw spdlog_ex(
"rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno);
}
}
}
file_helper_.reopen(true);
}
// delete the target if exists, and rename the src file to target
// return true on success, false otherwise.
bool rename_file(const filename_t &src_filename, const filename_t &target_filename)
{
// try to delete the target file in case it already exists.
(void)details::os::remove(target_filename);
return details::os::rename(src_filename, target_filename) == 0;
}
filename_t base_filename_;
std::size_t max_size_;
std::size_t max_files_;
std::size_t current_size_;
details::file_helper file_helper_;
};
using rotating_file_sink_mt = rotating_file_sink<std::mutex>;
using rotating_file_sink_st = rotating_file_sink<details::null_mutex>;
} // namespace sinks
//
// factory functions
//
template<typename Factory = default_factory>
inline std::shared_ptr<logger> rotating_logger_mt(
const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files)
{
return Factory::template create<sinks::rotating_file_sink_mt>(logger_name, filename, max_file_size, max_files);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> rotating_logger_st(
const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files)
{
return Factory::template create<sinks::rotating_file_sink_st>(logger_name, filename, max_file_size, max_files);
}
} // namespace spdlog
+59
View File
@@ -0,0 +1,59 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/log_msg.h"
#include "spdlog/details/pattern_formatter.h"
#include "spdlog/formatter.h"
namespace spdlog {
namespace sinks {
class sink
{
public:
sink()
: level_(level::trace)
, formatter_(new pattern_formatter("%+"))
{
}
explicit sink(std::unique_ptr<spdlog::pattern_formatter> formatter)
: level_(level::trace)
, formatter_(std::move(formatter))
{
}
virtual ~sink() = default;
virtual void log(const details::log_msg &msg) = 0;
virtual void flush() = 0;
virtual void set_pattern(const std::string &pattern) = 0;
virtual void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) = 0;
bool should_log(level::level_enum msg_level) const
{
return msg_level >= level_.load(std::memory_order_relaxed);
}
void set_level(level::level_enum log_level)
{
level_.store(log_level);
}
level::level_enum level() const
{
return static_cast<spdlog::level::level_enum>(level_.load(std::memory_order_relaxed));
}
protected:
// sink log level - default is all
level_t level_;
// sink formatter - default is full format
std::unique_ptr<spdlog::formatter> formatter_;
};
} // namespace sinks
} // namespace spdlog
+53
View File
@@ -0,0 +1,53 @@
//
// Copyright(c) 2018 spdlog
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/spdlog.h"
#ifdef _WIN32
#include "spdlog/sinks/wincolor_sink.h"
#else
#include "spdlog/sinks/ansicolor_sink.h"
#endif
namespace spdlog {
namespace sinks {
#ifdef _WIN32
using stdout_color_sink_mt = wincolor_stdout_sink_mt;
using stdout_color_sink_st = wincolor_stdout_sink_st;
using stderr_color_sink_mt = wincolor_stderr_sink_mt;
using stderr_color_sink_st = wincolor_stderr_sink_st;
#else
using stdout_color_sink_mt = ansicolor_stdout_sink_mt;
using stdout_color_sink_st = ansicolor_stdout_sink_st;
using stderr_color_sink_mt = ansicolor_stderr_sink_mt;
using stderr_color_sink_st = ansicolor_stderr_sink_st;
#endif
} // namespace sinks
template<typename Factory = default_factory>
inline std::shared_ptr<logger> stdout_color_mt(const std::string &logger_name)
{
return Factory::template create<sinks::stdout_color_sink_mt>(logger_name);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> stdout_color_st(const std::string &logger_name)
{
return Factory::template create<sinks::stdout_color_sink_st>(logger_name);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> stderr_color_mt(const std::string &logger_name)
{
return Factory::template create<sinks::stderr_color_sink_mt>(logger_name);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> stderr_color_st(const std::string &logger_name)
{
return Factory::template create<sinks::stderr_color_sink_mt>(logger_name);
}
} // namespace spdlog
+99
View File
@@ -0,0 +1,99 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/console_globals.h"
#include "spdlog/details/null_mutex.h"
#include "spdlog/spdlog.h"
#include <cstdio>
#include <memory>
#include <mutex>
namespace spdlog {
namespace sinks {
template<typename TargetStream, typename ConsoleMutex>
class stdout_sink final : public sink
{
public:
using mutex_t = typename ConsoleMutex::mutex_t;
stdout_sink()
: mutex_(ConsoleMutex::mutex())
, file_(TargetStream::stream())
{
}
~stdout_sink() override = default;
stdout_sink(const stdout_sink &other) = delete;
stdout_sink &operator=(const stdout_sink &other) = delete;
void log(const details::log_msg &msg) override
{
std::lock_guard<mutex_t> lock(mutex_);
fmt::memory_buffer formatted;
formatter_->format(msg, formatted);
fwrite(formatted.data(), sizeof(char), formatted.size(), file_);
fflush(TargetStream::stream());
}
void flush() override
{
std::lock_guard<mutex_t> lock(mutex_);
fflush(file_);
}
void set_pattern(const std::string &pattern) override
{
std::lock_guard<mutex_t> lock(mutex_);
formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern));
}
void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override
{
std::lock_guard<mutex_t> lock(mutex_);
formatter_ = std::move(sink_formatter);
}
private:
mutex_t &mutex_;
FILE *file_;
};
using stdout_sink_mt = stdout_sink<details::console_stdout, details::console_mutex>;
using stdout_sink_st = stdout_sink<details::console_stdout, details::console_nullmutex>;
using stderr_sink_mt = stdout_sink<details::console_stderr, details::console_mutex>;
using stderr_sink_st = stdout_sink<details::console_stderr, details::console_nullmutex>;
} // namespace sinks
// factory methods
template<typename Factory = default_factory>
inline std::shared_ptr<logger> stdout_logger_mt(const std::string &logger_name)
{
return Factory::template create<sinks::stdout_sink_mt>(logger_name);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> stdout_logger_st(const std::string &logger_name)
{
return Factory::template create<sinks::stdout_sink_st>(logger_name);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> stderr_logger_mt(const std::string &logger_name)
{
return Factory::template create<sinks::stderr_sink_mt>(logger_name);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> stderr_logger_st(const std::string &logger_name)
{
return Factory::template create<sinks::stderr_sink_st>(logger_name);
}
} // namespace spdlog
+91
View File
@@ -0,0 +1,91 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/sinks/base_sink.h"
#include "spdlog/spdlog.h"
#include <array>
#include <string>
#include <syslog.h>
namespace spdlog {
namespace sinks {
/**
* Sink that write to syslog using the `syscall()` library call.
*
* Locking is not needed, as `syslog()` itself is thread-safe.
*/
template<typename Mutex>
class syslog_sink : public base_sink<Mutex>
{
public:
//
explicit syslog_sink(std::string ident = "", int syslog_option = 0, int syslog_facility = LOG_USER)
: ident_(std::move(ident))
{
priorities_[static_cast<size_t>(level::trace)] = LOG_DEBUG;
priorities_[static_cast<size_t>(level::debug)] = LOG_DEBUG;
priorities_[static_cast<size_t>(level::info)] = LOG_INFO;
priorities_[static_cast<size_t>(level::warn)] = LOG_WARNING;
priorities_[static_cast<size_t>(level::err)] = LOG_ERR;
priorities_[static_cast<size_t>(level::critical)] = LOG_CRIT;
priorities_[static_cast<size_t>(level::off)] = LOG_INFO;
// set ident to be program name if empty
::openlog(ident_.empty() ? nullptr : ident_.c_str(), syslog_option, syslog_facility);
}
~syslog_sink() override
{
::closelog();
}
syslog_sink(const syslog_sink &) = delete;
syslog_sink &operator=(const syslog_sink &) = delete;
protected:
void sink_it_(const details::log_msg &msg) override
{
::syslog(syslog_prio_from_level(msg), "%s", fmt::to_string(msg.raw).c_str());
}
void flush_() override {}
private:
std::array<int, 7> priorities_;
// must store the ident because the man says openlog might use the pointer as
// is and not a string copy
const std::string ident_;
//
// Simply maps spdlog's log level to syslog priority level.
//
int syslog_prio_from_level(const details::log_msg &msg) const
{
return priorities_[static_cast<size_t>(msg.level)];
}
};
using syslog_sink_mt = syslog_sink<std::mutex>;
using syslog_sink_st = syslog_sink<details::null_mutex>;
} // namespace sinks
// Create and register a syslog logger
template<typename Factory = default_factory>
inline std::shared_ptr<logger> syslog_logger_mt(
const std::string &logger_name, const std::string &syslog_ident = "", int syslog_option = 0, int syslog_facility = (1 << 3))
{
return Factory::template create<sinks::syslog_sink_mt>(logger_name, syslog_ident, syslog_option, syslog_facility);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> syslog_logger_st(
const std::string &logger_name, const std::string &syslog_ident = "", int syslog_option = 0, int syslog_facility = (1 << 3))
{
return Factory::template create<sinks::syslog_sink_st>(logger_name, syslog_ident, syslog_option, syslog_facility);
}
} // namespace spdlog
+139
View File
@@ -0,0 +1,139 @@
//
// Copyright(c) 2016 spdlog
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/common.h"
#include "spdlog/details/console_globals.h"
#include "spdlog/details/null_mutex.h"
#include "spdlog/sinks/sink.h"
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <wincon.h>
namespace spdlog {
namespace sinks {
/*
* Windows color console sink. Uses WriteConsoleA to write to the console with
* colors
*/
template<typename OutHandle, typename ConsoleMutex>
class wincolor_sink : public sink
{
public:
const WORD BOLD = FOREGROUND_INTENSITY;
const WORD RED = FOREGROUND_RED;
const WORD GREEN = FOREGROUND_GREEN;
const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN;
wincolor_sink()
: out_handle_(OutHandle::handle())
, mutex_(ConsoleMutex::mutex())
{
colors_[level::trace] = WHITE;
colors_[level::debug] = CYAN;
colors_[level::info] = GREEN;
colors_[level::warn] = YELLOW | BOLD;
colors_[level::err] = RED | BOLD; // red bold
colors_[level::critical] = BACKGROUND_RED | WHITE | BOLD; // white bold on red background
colors_[level::off] = 0;
}
~wincolor_sink() override
{
this->flush();
}
wincolor_sink(const wincolor_sink &other) = delete;
wincolor_sink &operator=(const wincolor_sink &other) = delete;
// change the color for the given level
void set_color(level::level_enum level, WORD color)
{
std::lock_guard<mutex_t> lock(mutex_);
colors_[level] = color;
}
void log(const details::log_msg &msg) final override
{
std::lock_guard<mutex_t> lock(mutex_);
fmt::memory_buffer formatted;
formatter_->format(msg, formatted);
if (msg.color_range_end > msg.color_range_start)
{
// before color range
print_range_(formatted, 0, msg.color_range_start);
// in color range
auto orig_attribs = set_console_attribs(colors_[msg.level]);
print_range_(formatted, msg.color_range_start, msg.color_range_end);
::SetConsoleTextAttribute(out_handle_,
orig_attribs); // reset to orig colors
// after color range
print_range_(formatted, msg.color_range_end, formatted.size());
}
else // print without colors if color range is invalid
{
print_range_(formatted, 0, formatted.size());
}
}
void flush() final override
{
// windows console always flushed?
}
void set_pattern(const std::string &pattern) override final
{
std::lock_guard<mutex_t> lock(mutex_);
formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern));
}
void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override final
{
std::lock_guard<mutex_t> lock(mutex_);
formatter_ = std::move(sink_formatter);
}
private:
using mutex_t = typename ConsoleMutex::mutex_t;
// set color and return the orig console attributes (for resetting later)
WORD set_console_attribs(WORD attribs)
{
CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info;
::GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info);
WORD back_color = orig_buffer_info.wAttributes;
// retrieve the current background color
back_color &= static_cast<WORD>(~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY));
// keep the background color unchanged
::SetConsoleTextAttribute(out_handle_, attribs | back_color);
return orig_buffer_info.wAttributes; // return orig attribs
}
// print a range of formatted message to console
void print_range_(const fmt::memory_buffer &formatted, size_t start, size_t end)
{
auto size = static_cast<DWORD>(end - start);
::WriteConsoleA(out_handle_, formatted.data() + start, size, nullptr, nullptr);
}
HANDLE out_handle_;
mutex_t &mutex_;
std::unordered_map<level::level_enum, WORD, level::level_hasher> colors_;
};
using wincolor_stdout_sink_mt = wincolor_sink<details::console_stdout, details::console_mutex>;
using wincolor_stdout_sink_st = wincolor_sink<details::console_stdout, details::console_nullmutex>;
using wincolor_stderr_sink_mt = wincolor_sink<details::console_stderr, details::console_mutex>;
using wincolor_stderr_sink_st = wincolor_sink<details::console_stderr, details::console_nullmutex>;
} // namespace sinks
} // namespace spdlog
+161
View File
@@ -0,0 +1,161 @@
//
// Copyright(c) 2015-2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
// spdlog main header file.
// see example.cpp for usage example
#pragma once
#include "spdlog/common.h"
#include "spdlog/details/registry.h"
#include "spdlog/logger.h"
#include "spdlog/version.h"
#include <chrono>
#include <functional>
#include <memory>
#include <string>
namespace spdlog {
// Default logger factory- creates synchronous loggers
struct synchronous_factory
{
template<typename Sink, typename... SinkArgs>
static std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&... args)
{
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
auto new_logger = std::make_shared<logger>(std::move(logger_name), std::move(sink));
details::registry::instance().register_and_init(new_logger);
return new_logger;
}
};
using default_factory = synchronous_factory;
// Create and register a logger with a templated sink type
// The logger's level, formatter and flush level will be set according the
// global settings.
// Example:
// spdlog::create<daily_file_sink_st>("logger_name", "dailylog_filename", 11, 59);
template<typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&... sink_args)
{
return default_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
}
// Return an existing logger or nullptr if a logger with such name doesn't
// exist.
// example: spdlog::get("my_logger")->info("hello {}", "world");
inline std::shared_ptr<logger> get(const std::string &name)
{
return details::registry::instance().get(name);
}
// Set global formatter. Each sink in each logger will get a clone of this object
inline void set_formatter(std::unique_ptr<spdlog::formatter> formatter)
{
details::registry::instance().set_formatter(std::move(formatter));
}
// Set global format string.
// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v");
inline void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local)
{
set_formatter(std::unique_ptr<spdlog::formatter>(new pattern_formatter(std::move(pattern), time_type)));
}
// Set global logging level
inline void set_level(level::level_enum log_level)
{
details::registry::instance().set_level(log_level);
}
// Set global flush level
inline void flush_on(level::level_enum log_level)
{
details::registry::instance().flush_on(log_level);
}
// Start/Restart a periodic flusher thread
// Warning: Use only if all your loggers are thread safe!
inline void flush_every(std::chrono::seconds interval)
{
details::registry::instance().flush_every(interval);
}
// Set global error handler
inline void set_error_handler(log_err_handler handler)
{
details::registry::instance().set_error_handler(std::move(handler));
}
// Register the given logger with the given name
inline void register_logger(std::shared_ptr<logger> logger)
{
details::registry::instance().register_logger(std::move(logger));
}
// Apply a user defined function on all registered loggers
// Example:
// spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) {l->flush();});
inline void apply_all(const std::function<void(std::shared_ptr<logger>)> &fun)
{
details::registry::instance().apply_all(fun);
}
// Drop the reference to the given logger
inline void drop(const std::string &name)
{
details::registry::instance().drop(name);
}
// Drop all references from the registry
inline void drop_all()
{
details::registry::instance().drop_all();
}
// stop any running threads started by spdlog and clean registry loggers
inline void shutdown()
{
details::registry::instance().shutdown();
}
///////////////////////////////////////////////////////////////////////////////
//
// Trace & Debug can be switched on/off at compile time for zero cost debug
// statements.
// Uncomment SPDLOG_DEBUG_ON/SPDLOG_TRACE_ON in tweakme.h to enable.
// SPDLOG_TRACE(..) will also print current file and line.
//
// Example:
// spdlog::set_level(spdlog::level::trace);
// SPDLOG_TRACE(my_logger, "some trace message");
// SPDLOG_TRACE(my_logger, "another trace message {} {}", 1, 2);
// SPDLOG_DEBUG(my_logger, "some debug message {} {}", 3, 4);
///////////////////////////////////////////////////////////////////////////////
#ifdef SPDLOG_TRACE_ON
#define SPDLOG_STR_H(x) #x
#define SPDLOG_STR_HELPER(x) SPDLOG_STR_H(x)
#ifdef _MSC_VER
#define SPDLOG_TRACE(logger, ...) logger->trace("[ " __FILE__ "(" SPDLOG_STR_HELPER(__LINE__) ") ] " __VA_ARGS__)
#else
#define SPDLOG_TRACE(logger, ...) \
logger->trace("[ " __FILE__ ":" SPDLOG_STR_HELPER(__LINE__) " ]" \
" " __VA_ARGS__)
#endif
#else
#define SPDLOG_TRACE(logger, ...) (void)0
#endif
#ifdef SPDLOG_DEBUG_ON
#define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__)
#else
#define SPDLOG_DEBUG(logger, ...) (void)0
#endif
} // namespace spdlog
+123
View File
@@ -0,0 +1,123 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
///////////////////////////////////////////////////////////////////////////////
//
// Edit this file to squeeze more performance, and to customize supported
// features
//
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Under Linux, the much faster CLOCK_REALTIME_COARSE clock can be used.
// This clock is less accurate - can be off by dozens of millis - depending on
// the kernel HZ.
// Uncomment to use it instead of the regular clock.
//
// #define SPDLOG_CLOCK_COARSE
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment if date/time logging is not needed and never appear in the log
// pattern.
// This will prevent spdlog from querying the clock on each log call.
//
// WARNING: If the log pattern contains any date/time while this flag is on, the
// result is undefined.
// You must set new pattern(spdlog::set_pattern(..") without any
// date/time in it
//
// #define SPDLOG_NO_DATETIME
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment if thread id logging is not needed (i.e. no %t in the log pattern).
// This will prevent spdlog from querying the thread id on each log call.
//
// WARNING: If the log pattern contains thread id (i.e, %t) while this flag is
// on, the result is undefined.
//
// #define SPDLOG_NO_THREAD_ID
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to prevent spdlog from caching thread ids in thread local storage.
// By default spdlog saves thread ids in tls to gain a few micros for each call.
//
// WARNING: if your program forks, UNCOMMENT this flag to prevent undefined
// thread ids in the children logs.
//
// #define SPDLOG_DISABLE_TID_CACHING
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment if logger name logging is not needed.
// This will prevent spdlog from copying the logger name on each log call.
//
// #define SPDLOG_NO_NAME
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to enable the SPDLOG_DEBUG/SPDLOG_TRACE macros.
//
// #define SPDLOG_DEBUG_ON
// #define SPDLOG_TRACE_ON
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to avoid spdlog's usage of atomic log levels
// Use only if your code never modifies a logger's log levels concurrently by
// different threads.
//
// #define SPDLOG_NO_ATOMIC_LEVELS
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to enable usage of wchar_t for file names on Windows.
//
// #define SPDLOG_WCHAR_FILENAMES
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to override default eol ("\n" or "\r\n" under Linux/Windows)
//
// #define SPDLOG_EOL ";-)\n"
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to use your own copy of the fmt library instead of spdlog's copy.
// In this case spdlog will try to include <fmt/format.h> so set your -I flag
// accordingly.
//
// #define SPDLOG_FMT_EXTERNAL
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to enable wchar_t support (convert to utf8)
//
// #define SPDLOG_WCHAR_TO_UTF8_SUPPORT
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to prevent child processes from inheriting log file descriptors
//
// #define SPDLOG_PREVENT_CHILD_FD
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to enable message counting feature.
// Use the %i in the logger pattern to display log message sequence id.
//
// #define SPDLOG_ENABLE_MESSAGE_COUNTER
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to customize level names (e.g. "MT TRACE")
//
// #define SPDLOG_LEVEL_NAMES { "MY TRACE", "MY DEBUG", "MY INFO", "MY WARNING",
// "MY ERROR", "MY CRITICAL", "OFF" }
///////////////////////////////////////////////////////////////////////////////
+12
View File
@@ -0,0 +1,12 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#define SPDLOG_VER_MAJOR 1
#define SPDLOG_VER_MINOR 2
#define SPDLOG_VER_PATCH 0
#define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH)
-258
View File
@@ -1,258 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_boost_base.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
#
# DESCRIPTION
#
# Test for the Boost C++ libraries of a particular version (or newer)
#
# If no path to the installed boost library is given the macro searchs
# under /usr, /usr/local, /opt and /opt/local and evaluates the
# $BOOST_ROOT environment variable. Further documentation is available at
# <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS)
#
# And sets:
#
# HAVE_BOOST
#
# LICENSE
#
# Copyright (c) 2008 Thomas Porschberg <[email protected]>
# Copyright (c) 2009 Peter Adolphs
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 20
AC_DEFUN([AX_BOOST_BASE],
[
AC_ARG_WITH([boost],
[AS_HELP_STRING([--with-boost@<:@=ARG@:>@],
[use Boost library from a standard location (ARG=yes),
from the specified location (ARG=<path>),
or disable it (ARG=no)
@<:@ARG=yes@:>@ ])],
[
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ac_boost_path=""
else
want_boost="yes"
ac_boost_path="$withval"
fi
],
[want_boost="yes"])
AC_ARG_WITH([boost-libdir],
AS_HELP_STRING([--with-boost-libdir=LIB_DIR],
[Force given directory for boost libraries. Note that this will override library path detection, so use this parameter only if default library detection fails and you know exactly where your boost libraries are located.]),
[
if test -d "$withval"
then
ac_boost_lib_path="$withval"
else
AC_MSG_ERROR(--with-boost-libdir expected directory name)
fi
],
[ac_boost_lib_path=""]
)
if test "x$want_boost" = "xyes"; then
boost_lib_version_req=ifelse([$1], ,1.20.0,$1)
boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'`
boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'`
boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
if test "x$boost_lib_version_req_sub_minor" = "x" ; then
boost_lib_version_req_sub_minor="0"
fi
WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor`
AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req)
succeeded=no
dnl On 64-bit systems check for system libraries in both lib64 and lib.
dnl The former is specified by FHS, but e.g. Debian does not adhere to
dnl this (as it rises problems for generic multi-arch support).
dnl The last entry in the list is chosen by default when no libraries
dnl are found, e.g. when only header-only libraries are installed!
libsubdirs="lib"
ax_arch=`uname -m`
if test $ax_arch = x86_64 -o $ax_arch = ppc64 -o $ax_arch = s390x -o $ax_arch = sparc64; then
libsubdirs="lib64 lib lib64"
fi
dnl first we check the system location for boost libraries
dnl this location ist chosen if boost libraries are installed with the --layout=system option
dnl or if you install boost with RPM
if test "$ac_boost_path" != ""; then
BOOST_CPPFLAGS="-I$ac_boost_path/include"
for ac_boost_path_tmp in $libsubdirs; do
if test -d "$ac_boost_path"/"$ac_boost_path_tmp" ; then
BOOST_LDFLAGS="-L$ac_boost_path/$ac_boost_path_tmp"
break
fi
done
elif test "$cross_compiling" != yes; then
for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do
if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then
for libsubdir in $libsubdirs ; do
if ls "$ac_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
BOOST_LDFLAGS="-L$ac_boost_path_tmp/$libsubdir"
BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include"
break;
fi
done
fi
dnl overwrite ld flags if we have required special directory with
dnl --with-boost-libdir parameter
if test "$ac_boost_lib_path" != ""; then
BOOST_LDFLAGS="-L$ac_boost_lib_path"
fi
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_REQUIRE([AC_PROG_CXX])
AC_LANG_PUSH(C++)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@%:@include <boost/version.hpp>
]], [[
#if BOOST_VERSION >= $WANT_BOOST_VERSION
// Everything is okay
#else
# error Boost version is too old
#endif
]])],[
AC_MSG_RESULT(yes)
succeeded=yes
found_system=yes
],[
])
AC_LANG_POP([C++])
dnl if we found no boost with system layout we search for boost libraries
dnl built and installed without the --layout=system option or for a staged(not installed) version
if test "x$succeeded" != "xyes"; then
_version=0
if test "$ac_boost_path" != ""; then
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
V_CHECK=`expr $_version_tmp \> $_version`
if test "$V_CHECK" = "1" ; then
_version=$_version_tmp
fi
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
done
fi
else
if test "$cross_compiling" != yes; then
for ac_boost_path in /usr /usr/local /opt /opt/local ; do
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
V_CHECK=`expr $_version_tmp \> $_version`
if test "$V_CHECK" = "1" ; then
_version=$_version_tmp
best_path=$ac_boost_path
fi
done
fi
done
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
if test "$ac_boost_lib_path" = ""; then
for libsubdir in $libsubdirs ; do
if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
BOOST_LDFLAGS="-L$best_path/$libsubdir"
fi
fi
if test "x$BOOST_ROOT" != "x"; then
for libsubdir in $libsubdirs ; do
if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then
version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'`
stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
V_CHECK=`expr $stage_version_shorten \>\= $_version`
if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then
AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
BOOST_CPPFLAGS="-I$BOOST_ROOT"
BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir"
fi
fi
fi
fi
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_LANG_PUSH(C++)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@%:@include <boost/version.hpp>
]], [[
#if BOOST_VERSION >= $WANT_BOOST_VERSION
// Everything is okay
#else
# error Boost version is too old
#endif
]])],[
AC_MSG_RESULT(yes)
succeeded=yes
found_system=yes
],[
])
AC_LANG_POP([C++])
fi
if test "$succeeded" != "yes" ; then
if test "$_version" = "0" ; then
AC_MSG_NOTICE([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
else
AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).])
fi
# execute ACTION-IF-NOT-FOUND (if present):
ifelse([$3], , :, [$3])
else
AC_SUBST(BOOST_CPPFLAGS)
AC_SUBST(BOOST_LDFLAGS)
AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available])
# execute ACTION-IF-FOUND (if present):
ifelse([$2], , :, [$2])
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])
-116
View File
@@ -1,116 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_boost_iostreams.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_BOOST_IOSTREAMS
#
# DESCRIPTION
#
# Test for IOStreams library from the Boost C++ libraries. The macro
# requires a preceding call to AX_BOOST_BASE. Further documentation is
# available at <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_IOSTREAMS_LIB)
#
# And sets:
#
# HAVE_BOOST_IOSTREAMS
#
# LICENSE
#
# Copyright (c) 2008 Thomas Porschberg <[email protected]>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 20
AC_DEFUN([AX_BOOST_IOSTREAMS],
[
AC_ARG_WITH([boost-iostreams],
AS_HELP_STRING([--with-boost-iostreams@<:@=special-lib@:>@],
[use the IOStreams library from boost - it is possible to specify a certain library for the linker
e.g. --with-boost-iostreams=boost_iostreams-gcc-mt-d-1_33_1 ]),
[
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ax_boost_user_iostreams_lib=""
else
want_boost="yes"
ax_boost_user_iostreams_lib="$withval"
fi
],
[want_boost="yes"]
)
if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC])
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_CACHE_CHECK(whether the Boost::IOStreams library is available,
ax_cv_boost_iostreams,
[AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/iostreams/filtering_stream.hpp>
@%:@include <boost/range/iterator_range.hpp>
]],
[[std::string input = "Hello World!";
namespace io = boost::iostreams;
io::filtering_istream in(boost::make_iterator_range(input));
return 0;
]])],
ax_cv_boost_iostreams=yes, ax_cv_boost_iostreams=no)
AC_LANG_POP([C++])
])
if test "x$ax_cv_boost_iostreams" = "xyes"; then
AC_DEFINE(HAVE_BOOST_IOSTREAMS,,[define if the Boost::IOStreams library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
if test "x$ax_boost_user_iostreams_lib" = "x"; then
for libextension in `ls $BOOSTLIBDIR/libboost_iostreams*.so* $BOOSTLIBDIR/libboost_iostream*.dylib* $BOOSTLIBDIR/libboost_iostreams*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_iostreams.*\)\.so.*$;\1;' -e 's;^lib\(boost_iostream.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_iostreams.*\)\.a.*$;\1;'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_IOSTREAMS_LIB="-l$ax_lib"; AC_SUBST(BOOST_IOSTREAMS_LIB) link_iostreams="yes"; break],
[link_iostreams="no"])
done
if test "x$link_iostreams" != "xyes"; then
for libextension in `ls $BOOSTLIBDIR/boost_iostreams*.dll* $BOOSTLIBDIR/boost_iostreams*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_iostreams.*\)\.dll.*$;\1;' -e 's;^\(boost_iostreams.*\)\.a.*$;\1;'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_IOSTREAMS_LIB="-l$ax_lib"; AC_SUBST(BOOST_IOSTREAMS_LIB) link_iostreams="yes"; break],
[link_iostreams="no"])
done
fi
else
for ax_lib in $ax_boost_user_iostreams_lib boost_iostreams-$ax_boost_user_iostreams_lib; do
AC_CHECK_LIB($ax_lib, main,
[BOOST_IOSTREAMS_LIB="-l$ax_lib"; AC_SUBST(BOOST_IOSTREAMS_LIB) link_iostreams="yes"; break],
[link_iostreams="no"])
done
fi
if test "x$ax_lib" = "x"; then
AC_MSG_ERROR(Could not find a version of the library!)
fi
if test "x$link_iostreams" != "xyes"; then
AC_MSG_ERROR(Could not link against $ax_lib !)
fi
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])
-120
View File
@@ -1,120 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_boost_system.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_BOOST_SYSTEM
#
# DESCRIPTION
#
# Test for System library from the Boost C++ libraries. The macro requires
# a preceding call to AX_BOOST_BASE. Further documentation is available at
# <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_SYSTEM_LIB)
#
# And sets:
#
# HAVE_BOOST_SYSTEM
#
# LICENSE
#
# Copyright (c) 2008 Thomas Porschberg <[email protected]>
# Copyright (c) 2008 Michael Tindal
# Copyright (c) 2008 Daniel Casimiro <[email protected]>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 17
AC_DEFUN([AX_BOOST_SYSTEM],
[
AC_ARG_WITH([boost-system],
AS_HELP_STRING([--with-boost-system@<:@=special-lib@:>@],
[use the System library from boost - it is possible to specify a certain library for the linker
e.g. --with-boost-system=boost_system-gcc-mt ]),
[
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ax_boost_user_system_lib=""
else
want_boost="yes"
ax_boost_user_system_lib="$withval"
fi
],
[want_boost="yes"]
)
if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_BUILD])
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_CACHE_CHECK(whether the Boost::System library is available,
ax_cv_boost_system,
[AC_LANG_PUSH([C++])
CXXFLAGS_SAVE=$CXXFLAGS
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/system/error_code.hpp>]],
[[boost::system::system_category]])],
ax_cv_boost_system=yes, ax_cv_boost_system=no)
CXXFLAGS=$CXXFLAGS_SAVE
AC_LANG_POP([C++])
])
if test "x$ax_cv_boost_system" = "xyes"; then
AC_SUBST(BOOST_CPPFLAGS)
AC_DEFINE(HAVE_BOOST_SYSTEM,,[define if the Boost::System library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
LDFLAGS_SAVE=$LDFLAGS
if test "x$ax_boost_user_system_lib" = "x"; then
for libextension in `ls -r $BOOSTLIBDIR/libboost_system* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
[link_system="no"])
done
if test "x$link_system" != "xyes"; then
for libextension in `ls -r $BOOSTLIBDIR/boost_system* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
[link_system="no"])
done
fi
else
for ax_lib in $ax_boost_user_system_lib boost_system-$ax_boost_user_system_lib; do
AC_CHECK_LIB($ax_lib, exit,
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
[link_system="no"])
done
fi
if test "x$ax_lib" = "x"; then
AC_MSG_ERROR(Could not find a version of the library!)
fi
if test "x$link_system" = "xno"; then
AC_MSG_ERROR(Could not link against $ax_lib !)
fi
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])
-72
View File
@@ -1,72 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS])
#
# DESCRIPTION
#
# Check whether the given FLAG works with the current language's compiler
# or gives an error. (Warnings, however, are ignored)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <[email protected]>
# Copyright (c) 2011 Maarten Bosmans <[email protected]>
#
# 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 <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 2
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes],
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_COMPILE_FLAGS
-332
View File
@@ -1,332 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
#
# DESCRIPTION
#
# This macro figures out how to build C programs using POSIX threads. It
# sets the PTHREAD_LIBS output variable to the threads library and linker
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
# flags that are needed. (The user can also force certain compiler
# flags/libs to be tested by setting these environment variables.)
#
# Also sets PTHREAD_CC to any special C compiler that is needed for
# multi-threaded programs (defaults to the value of CC otherwise). (This
# is necessary on AIX to use the special cc_r compiler alias.)
#
# NOTE: You are assumed to not only compile your program with these flags,
# but also link it with them as well. e.g. you should link with
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
# If you are only building threads programs, you may wish to use these
# variables in your default LIBS, CFLAGS, and CC:
#
# LIBS="$PTHREAD_LIBS $LIBS"
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# CC="$PTHREAD_CC"
#
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
#
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
# PTHREAD_CFLAGS.
#
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
# is not found. If ACTION-IF-FOUND is not specified, the default action
# will define HAVE_PTHREAD.
#
# Please let the authors know if this macro fails on any platform, or if
# you have any other suggestions or comments. This macro was based on work
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
# grateful for the helpful feedback of numerous users.
#
# Updated for Autoconf 2.68 by Daniel Richard G.
#
# LICENSE
#
# Copyright (c) 2008 Steven G. Johnson <[email protected]>
# Copyright (c) 2011 Daniel Richard G. <[email protected]>
#
# 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 <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 21
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_LANG_PUSH([C])
ax_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
AC_MSG_RESULT([$ax_pthread_ok])
if test x"$ax_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# ... -mt is also the pthreads flag for HP/aCC
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
case ${host_os} in
solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
;;
darwin*)
ax_pthread_flags="-pthread $ax_pthread_flags"
;;
esac
# Clang doesn't consider unrecognized options an error unless we specify
# -Werror. We throw in some extra Clang-specific options to ensure that
# this doesn't happen for GCC, which also accepts -Werror.
AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
save_CFLAGS="$CFLAGS"
ax_pthread_extra_flags="-Werror"
CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
[AC_MSG_RESULT([yes])],
[ax_pthread_extra_flags=
AC_MSG_RESULT([no])])
CFLAGS="$save_CFLAGS"
if test x"$ax_pthread_ok" = xno; then
for flag in $ax_pthread_flags; do
case $flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
;;
pthread-config)
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
if test x"$ax_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
;;
esac
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
# need a special flag -Kthread to make this header compile.)
# We check for pthread_join because it is in -lpthread on IRIX
# while pthread_create is in libc. We check for pthread_attr_init
# due to DEC craziness with -lpthreads. We check for
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
static void routine(void *a) { a = 0; }
static void *start_routine(void *a) { return a; }],
[pthread_t th; pthread_attr_t attr;
pthread_create(&th, 0, start_routine, 0);
pthread_join(th, 0);
pthread_attr_init(&attr);
pthread_cleanup_push(routine, 0);
pthread_cleanup_pop(0) /* ; */])],
[ax_pthread_ok=yes],
[])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
AC_MSG_RESULT([$ax_pthread_ok])
if test "x$ax_pthread_ok" = xyes; then
break;
fi
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Various other checks:
if test "x$ax_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
AC_MSG_CHECKING([for joinable pthread attribute])
attr_name=unknown
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
[int attr = $attr; return attr /* ; */])],
[attr_name=$attr; break],
[])
done
AC_MSG_RESULT([$attr_name])
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case ${host_os} in
aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
osf* | hpux*) flag="-D_REENTRANT";;
solaris*)
if test "$GCC" = "yes"; then
flag="-D_REENTRANT"
else
# TODO: What about Clang on Solaris?
flag="-mt -D_REENTRANT"
fi
;;
esac
AC_MSG_RESULT([$flag])
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
[ax_cv_PTHREAD_PRIO_INHERIT], [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
[[int i = PTHREAD_PRIO_INHERIT;]])],
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
[ax_cv_PTHREAD_PRIO_INHERIT=no])
])
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
# More AIX lossage: compile with *_r variant
if test "x$GCC" != xyes; then
case $host_os in
aix*)
AS_CASE(["x/$CC"],
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
[#handle absolute path differently from PATH based program lookup
AS_CASE(["x$CC"],
[x/*],
[AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
[AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
;;
esac
fi
fi
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
AC_SUBST([PTHREAD_LIBS])
AC_SUBST([PTHREAD_CFLAGS])
AC_SUBST([PTHREAD_CC])
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$ax_pthread_ok" = xyes; then
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
:
else
ax_pthread_ok=no
$2
fi
AC_LANG_POP
])dnl AX_PTHREAD
-135
View File
@@ -1,135 +0,0 @@
dnl @synopsis EV_DEVEL
dnl
dnl This macro tries to find the libev library and header files.
dnl
dnl We define the following configure script flags:
dnl
dnl --with-ev: Give prefix for both library and headers, and try
dnl to guess subdirectory names for each. (e.g. tack /lib and
dnl /include onto given dir name, and other common schemes.)
dnl --with-ev-lib: Similar to --with-ev, but for library only.
dnl --with-ev-include: Similar to --with-ev, but for headers
dnl only.
AC_DEFUN([EV_DEVEL],
[
dnl
dnl Set up configure script macros
dnl
AC_ARG_WITH(ev,
[AS_HELP_STRING([--with-ev=<path>],[path containing libev header and library subdirs])],
[EV_lib_check="$with_ev/lib64 $with_ev/lib $with_ev/lib64/libev $with_ev/lib/libev"
EV_inc_check="$with_ev/include $with_ev/include/libev"],
[EV_lib_check="/usr/local/libev/lib64 /usr/local/libev/lib /usr/local/lib64/libev /usr/local/lib/libev /opt/libev/lib64 /opt/libev/lib /usr/lib64/libev /usr/lib/libev /usr/local/lib64 /usr/local/lib /usr/lib64 /usr/lib"
EV_inc_check="/usr/local/libev/include /usr/local/include/libev /opt/libev/include /usr/local/include/libev /usr/local/include /usr/include/libev /usr/include"])
AC_ARG_WITH(ev-lib,
[AS_HELP_STRING([--with-ev-lib=<path>],[directory path of libev library])],
[EV_lib_check="$with_ev_lib $with_ev_lib/lib64 $with_ev_lib/lib $with_ev_lib/lib64/libev $with_ev_lib/lib/libev"])
AC_ARG_WITH(ev-include,
[AS_HELP_STRING([--with-ev-include=<path>],[directory path of libev headers])],
[EV_inc_check="$with_ev_include $with_ev_include/include $with_ev_include/include/libev"])
dnl
dnl Look for libev library
dnl
AC_CACHE_CHECK([for libev library location], [ac_cv_ev_lib],
[
for dir in $EV_lib_check
do
if test -d "$dir" && \
( test -f "$dir/libev.so" ||
test -f "$dir/libev.a" )
then
ac_cv_ev_lib=$dir
break
fi
done
if test -z "$ac_cv_ev_lib"
then
AC_MSG_RESULT([no])
AC_MSG_ERROR([Didn't find the libev library dir in '$EV_lib_check'])
fi
case "$ac_cv_ev_lib" in
/* )
;;
* )
AC_MSG_RESULT([])
AC_MSG_ERROR([The libev library directory ($ac_cv_ev_lib) must be an absolute path.])
;;
esac
])
AC_SUBST([EV_LIB_DIR],[$ac_cv_ev_lib])
dnl
dnl Look for libev header file directory
dnl
AC_CACHE_CHECK([for libev include path], [ac_cv_ev_inc],
[
for dir in $EV_inc_check
do
if test -d "$dir" && test -f "$dir/ev++.h"
then
ac_cv_ev_inc=$dir
break
fi
done
if test -z "$ac_cv_ev_inc"
then
AC_MSG_RESULT([no])
AC_MSG_ERROR([Didn't find the libev header dir in '$EV_inc_check'])
fi
case "$ac_cv_ev_inc" in
/* )
;;
* )
AC_MSG_RESULT([])
AC_MSG_ERROR([The libev header directory ($ac_cv_ev_inc) must be an absolute path.])
;;
esac
])
AC_SUBST([EV_INC_DIR],[$ac_cv_ev_inc])
dnl
dnl Now check that the above checks resulted in -I and -L flags that
dnl let us build actual programs against libev.
dnl
case "$ac_cv_ev_lib" in
/usr/lib)
;;
*)
LDFLAGS="$LDFLAGS -L${ac_cv_ev_lib}"
;;
esac
CPPFLAGS="$CPPFLAGS -I${ac_cv_ev_inc}"
AC_MSG_CHECKING([that we can build libev programs])
AC_EGREP_CPP(
[bad_gcc_libev_ver],
[
#include <ev.h>
#if __GNUC__ && (__GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ < 9) && EV_VERSION_MAJOR == 4 && EV_VERSION_MINOR == 18
bad_gcc_libev_ver
#endif
],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([GCC versions prior to 4.9 cannot compile libev 4.18])],
[],
)
LIBS="-lev $LIBS"
AC_LANG_PUSH([C++])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[#include <ev++.h>],
[ev::io i])
],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_MSG_FAILURE([Cannot build libev programs])]
)
AC_LANG_POP([C++])
]) dnl End EV_DEVEL
-150
View File
@@ -1,150 +0,0 @@
#-######################################################################
# mysql++.m4 - Example autoconf macro showing how to find MySQL++
# library and header files.
#
# Copyright (c) 2004-2009 by Educational Technology Resources, Inc.
#
# This file 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 2.1 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with MySQL++; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
# USA
#-######################################################################
dnl @synopsis MYSQLPP_DEVEL
dnl
dnl This macro tries to find the MySQL++ library and header files.
dnl
dnl We define the following configure script flags:
dnl
dnl --with-mysqlpp: Give prefix for both library and headers, and try
dnl to guess subdirectory names for each. (e.g. tack /lib and
dnl /include onto given dir name, and other common schemes.)
dnl --with-mysqlpp-lib: Similar to --with-mysqlpp, but for library only.
dnl --with-mysqlpp-include: Similar to --with-mysqlpp, but for headers
dnl only.
dnl
dnl This macro depends on having the default compiler and linker flags
dnl set up for building programs against the MySQL C API. The mysql.m4
dnl macro in this directory fits this bill; run it first.
dnl
dnl @version 1.3, 2009/11/22
dnl @author Warren Young <[email protected]>
AC_DEFUN([MYSQLPP_DEVEL],
[
dnl
dnl Set up configure script macros
dnl
AC_ARG_WITH(mysqlpp,
[AS_HELP_STRING([--with-mysqlpp=<path>],[path containing MySQL++ header and library subdirs])],
[MYSQLPP_lib_check="$with_mysqlpp/lib64 $with_mysqlpp/lib $with_mysqlpp/lib64/mysql++ $with_mysqlpp/lib/mysql++"
MYSQLPP_inc_check="$with_mysqlpp/include $with_mysqlpp/include/mysql++"],
[MYSQLPP_lib_check="/usr/local/mysql++/lib64 /usr/local/mysql++/lib /usr/local/lib64/mysql++ /usr/local/lib/mysql++ /opt/mysql++/lib64 /opt/mysql++/lib /usr/lib64/mysql++ /usr/lib/mysql++ /usr/local/lib64 /usr/local/lib /usr/lib64 /usr/lib"
MYSQLPP_inc_check="/usr/local/mysql++/include /usr/local/include/mysql++ /opt/mysql++/include /usr/local/include/mysql++ /usr/local/include /usr/include/mysql++ /usr/include"])
AC_ARG_WITH(mysqlpp-lib,
[AS_HELP_STRING([--with-mysqlpp-lib=<path>],[directory path of MySQL++ library])],
[MYSQLPP_lib_check="$with_mysqlpp_lib $with_mysqlpp_lib/lib64 $with_mysqlpp_lib/lib $with_mysqlpp_lib/lib64/mysql $with_mysqlpp_lib/lib/mysql"])
AC_ARG_WITH(mysqlpp-include,
[AS_HELP_STRING([--with-mysqlpp-include=<path>],[directory path of MySQL++ headers])],
[MYSQLPP_inc_check="$with_mysqlpp_include $with_mysqlpp_include/include $with_mysqlpp_include/include/mysql"])
dnl
dnl Look for MySQL++ library
dnl
AC_CACHE_CHECK([for MySQL++ library location], [ac_cv_mysqlpp_lib],
[
for dir in $MYSQLPP_lib_check
do
if test -d "$dir" && \
( test -f "$dir/libmysqlpp.so" ||
test -f "$dir/libmysqlpp.a" )
then
ac_cv_mysqlpp_lib=$dir
break
fi
done
if test -z "$ac_cv_mysqlpp_lib"
then
AC_MSG_RESULT([no])
AC_MSG_ERROR([Didn't find the MySQL++ library dir in '$MYSQLPP_lib_check'])
fi
case "$ac_cv_mysqlpp_lib" in
/* )
;;
* )
AC_MSG_RESULT([no])
AC_MSG_ERROR([The MySQL++ library directory ($ac_cv_mysqlpp_lib) must be an absolute path.])
;;
esac
])
AC_SUBST([MYSQLPP_LIB_DIR],[$ac_cv_mysqlpp_lib])
dnl
dnl Look for MySQL++ header file directory
dnl
AC_CACHE_CHECK([for MySQL++ include path], [ac_cv_mysqlpp_inc],
[
for dir in $MYSQLPP_inc_check
do
if test -d "$dir" && test -f "$dir/mysql++.h"
then
ac_cv_mysqlpp_inc=$dir
break
fi
done
if test -z "$ac_cv_mysqlpp_inc"
then
AC_MSG_RESULT([no])
AC_MSG_ERROR([Didn't find the MySQL++ header dir in '$MYSQLPP_inc_check'])
fi
case "$ac_cv_mysqlpp_inc" in
/* )
;;
* )
AC_MSG_RESULT([no])
AC_MSG_ERROR([The MySQL++ header directory ($ac_cv_mysqlpp_inc) must be an absolute path.])
;;
esac
])
AC_SUBST([MYSQLPP_INC_DIR],[$ac_cv_mysqlpp_inc])
dnl
dnl Now check that the above checks resulted in -I and -L flags that
dnl let us build actual programs against MySQL++.
dnl
case "$ac_cv_mysqlpp_lib" in
/usr/lib)
;;
*)
LDFLAGS="$LDFLAGS -L${ac_cv_mysqlpp_lib}"
;;
esac
CPPFLAGS="$CPPFLAGS -I${ac_cv_mysqlpp_inc}"
LIBS="-lmysqlpp $LIBS"
AC_LANG_PUSH([C++])
AC_MSG_CHECKING([that we can build MySQL++ programs])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[#include <mysql++.h>],
[mysqlpp::Connection c(false)]
)],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([Cannot build MySQL++ programs])]
)
AC_LANG_POP([C++])
]) dnl End MYSQLPP_DEVEL
-145
View File
@@ -1,145 +0,0 @@
dnl @synopsis MYSQL_C_API_LOCATION
dnl
dnl This macro tries to find MySQL C API header and library locations.
dnl
dnl We define the following configure script flags:
dnl
dnl --with-mysql: Give prefix for both library and headers, and try
dnl to guess subdirectory names for each by tacking common
dnl suffixes on like /lib and /include.
dnl --with-mysql-lib: Same as --with-mysql, but for library only.
dnl --with-mysql-include: Same as --with-mysql, but for headers only.
dnl
dnl @version 1.4, 2009/05/28
dnl @author Warren Young <[email protected]>
AC_DEFUN([MYSQL_C_API_LOCATION],
[
#
# Set up configure script macros
#
AC_ARG_WITH(mysql,
[AS_HELP_STRING([--with-mysql=<path>],[root directory path of MySQL installation])],
[MYSQL_lib_check="$with_mysql/lib/mysql $with_mysql/lib"
MYSQL_inc_check="$with_mysql/include $with_mysql/include/mysql"],
[MYSQL_lib_check="/usr/lib64 /usr/lib /usr/lib64/mysql /usr/lib/mysql /usr/local/lib64 /usr/local/lib /usr/local/lib/mysql /usr/local/mysql/lib /usr/local/mysql/lib/mysql /usr/mysql/lib/mysql /opt/mysql/lib /opt/mysql/lib/mysql /sw/lib /sw/lib/mysql"
MYSQL_inc_check="/usr/include/mysql /usr/local/include/mysql /usr/local/mysql/include /usr/local/mysql/include/mysql /usr/mysql/include/mysql /opt/mysql/include/mysql /sw/include/mysql"])
AC_ARG_WITH(mysql-lib,
[AS_HELP_STRING([--with-mysql-lib=<path>],[directory path of MySQL library installation])],
[MYSQL_lib_check="$with_mysql_lib $with_mysql_lib/lib64 $with_mysql_lib/lib $with_mysql_lib/lib64/mysql $with_mysql_lib/lib/mysql"])
AC_ARG_WITH(mysql-include,
[AS_HELP_STRING([--with-mysql-include=<path>],[directory path of MySQL header installation])],
[MYSQL_inc_check="$with_mysql_include $with_mysql_include/include $with_mysql_include/include/mysql"])
#
# Decide which C API library to use, based on thread support
#
if test "x$acx_pthread_ok" = xyes
then
MYSQL_C_LIB_NAME=mysqlclient_r
else
MYSQL_C_LIB_NAME=mysqlclient
fi
#
# Look for MySQL C API library
#
AC_MSG_CHECKING([for MySQL library directory])
MYSQL_C_LIB_DIR=
for m in $MYSQL_lib_check
do
if test -d "$m" && \
(test -f "$m/lib$MYSQL_C_LIB_NAME.so" || \
test -f "$m/lib$MYSQL_C_LIB_NAME.a")
then
MYSQL_C_LIB_DIR=$m
break
fi
done
if test -z "$MYSQL_C_LIB_DIR"
then
AC_MSG_RESULT([no])
AC_MSG_ERROR([Didn't find $MYSQL_C_LIB_NAME library in '$MYSQL_lib_check'])
fi
case "$MYSQL_C_LIB_DIR" in
/* )
;;
* )
AC_MSG_RESULT([])
AC_MSG_ERROR([The MySQL library directory ($MYSQL_C_LIB_DIR) must be an absolute path.]) ;;
esac
AC_MSG_RESULT([$MYSQL_C_LIB_DIR])
case "$MYSQL_C_LIB_DIR" in
/usr/lib)
MYSQL_C_LIB_DIR=
;;
*)
LDFLAGS="$LDFLAGS -L${MYSQL_C_LIB_DIR}"
;;
esac
#
# Look for MySQL C API headers
#
AC_MSG_CHECKING([for MySQL include directory])
MYSQL_C_INC_DIR=
for m in $MYSQL_inc_check
do
if test -d "$m" && test -f "$m/mysql.h"
then
MYSQL_C_INC_DIR=$m
break
fi
done
if test -z "$MYSQL_C_INC_DIR"
then
AC_MSG_RESULT([no])
AC_MSG_ERROR([Didn't find the MySQL include dir in '$MYSQL_inc_check'])
fi
case "$MYSQL_C_INC_DIR" in
/* )
;;
* )
AC_MSG_RESULT([])
AC_MSG_ERROR([The MySQL include directory ($MYSQL_C_INC_DIR) must be an absolute path.]) ;;
esac
AC_MSG_RESULT([$MYSQL_C_INC_DIR])
CPPFLAGS="$CPPFLAGS -I${MYSQL_C_INC_DIR}"
AC_MSG_CHECKING([if we can link to MySQL C API library directly])
save_LIBS=$LIBS
LIBS="-l$MYSQL_C_LIB_NAME $LIBS"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[#include <mysql.h>],
[mysql_store_result(0);])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
LIBS="$save_LIBS"
AC_CHECK_HEADERS(zlib.h, AC_CHECK_LIB(z, gzread, [],
[AC_MSG_ERROR([zlib not found])]))
AC_MSG_CHECKING([whether adding -lz will let MySQL C API link succeed])
LIBS="-l$MYSQL_C_LIB_NAME -lz $save_LIBS"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[#include <mysql.h>],
[mysql_store_result(0);]
)],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([Unable to link to MySQL client library!])]
)]
)
AC_SUBST(MYSQL_C_INC_DIR)
AC_SUBST(MYSQL_C_LIB_DIR)
AC_SUBST(MYSQL_C_LIB_NAME)
]) dnl MYSQL_C_API_LOCATION
-11
View File
@@ -1,11 +0,0 @@
AC_DEFUN([TCMALLOC],
[AC_ARG_WITH(
[tcmalloc],
[AS_HELP_STRING([--with-tcmalloc], [use tcmalloc if it's available [default=yes]])],
[],
[with_tcmalloc=yes])
AS_IF([test "x$with_tcmalloc" != "xno"],
[AC_CHECK_LIB([tcmalloc], [tc_free])]
)]
)
-215
View File
@@ -1,215 +0,0 @@
#! /bin/sh
# Common wrapper for a few potentially missing GNU programs.
scriptversion=2013-10-28.13; # UTC
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# Originally written by Fran,cois Pinard <[email protected]>, 1996.
# 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, 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 <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try '$0 --help' for more information"
exit 1
fi
case $1 in
--is-lightweight)
# Used by our autoconf macros to check whether the available missing
# script is modern enough.
exit 0
;;
--run)
# Back-compat with the calling convention used by older automake.
shift
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
to PROGRAM being missing or too old.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
Supported PROGRAM values:
aclocal autoconf autoheader autom4te automake makeinfo
bison yacc flex lex help2man
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
'g' are ignored when checking the name.
Send bug reports to <[email protected]>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
exit $?
;;
-*)
echo 1>&2 "$0: unknown '$1' option"
echo 1>&2 "Try '$0 --help' for more information"
exit 1
;;
esac
# Run the given program, remember its exit status.
"$@"; st=$?
# If it succeeded, we are done.
test $st -eq 0 && exit 0
# Also exit now if we it failed (or wasn't found), and '--version' was
# passed; such an option is passed most likely to detect whether the
# program is present and works.
case $2 in --version|--help) exit $st;; esac
# Exit code 63 means version mismatch. This often happens when the user
# tries to use an ancient version of a tool on a file that requires a
# minimum version.
if test $st -eq 63; then
msg="probably too old"
elif test $st -eq 127; then
# Program was missing.
msg="missing on your system"
else
# Program was found and executed, but failed. Give up.
exit $st
fi
perl_URL=http://www.perl.org/
flex_URL=http://flex.sourceforge.net/
gnu_software_URL=http://www.gnu.org/software
program_details ()
{
case $1 in
aclocal|automake)
echo "The '$1' program is part of the GNU Automake package:"
echo "<$gnu_software_URL/automake>"
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/autoconf>"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
autoconf|autom4te|autoheader)
echo "The '$1' program is part of the GNU Autoconf package:"
echo "<$gnu_software_URL/autoconf/>"
echo "It also requires GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
esac
}
give_advice ()
{
# Normalize program name to check for.
normalized_program=`echo "$1" | sed '
s/^gnu-//; t
s/^gnu//; t
s/^g//; t'`
printf '%s\n' "'$1' is $msg."
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
case $normalized_program in
autoconf*)
echo "You should only need it if you modified 'configure.ac',"
echo "or m4 files included by it."
program_details 'autoconf'
;;
autoheader*)
echo "You should only need it if you modified 'acconfig.h' or"
echo "$configure_deps."
program_details 'autoheader'
;;
automake*)
echo "You should only need it if you modified 'Makefile.am' or"
echo "$configure_deps."
program_details 'automake'
;;
aclocal*)
echo "You should only need it if you modified 'acinclude.m4' or"
echo "$configure_deps."
program_details 'aclocal'
;;
autom4te*)
echo "You might have modified some maintainer files that require"
echo "the 'autom4te' program to be rebuilt."
program_details 'autom4te'
;;
bison*|yacc*)
echo "You should only need it if you modified a '.y' file."
echo "You may want to install the GNU Bison package:"
echo "<$gnu_software_URL/bison/>"
;;
lex*|flex*)
echo "You should only need it if you modified a '.l' file."
echo "You may want to install the Fast Lexical Analyzer package:"
echo "<$flex_URL>"
;;
help2man*)
echo "You should only need it if you modified a dependency" \
"of a man page."
echo "You may want to install the GNU Help2man package:"
echo "<$gnu_software_URL/help2man/>"
;;
makeinfo*)
echo "You should only need it if you modified a '.texi' file, or"
echo "any other file indirectly affecting the aspect of the manual."
echo "You might want to install the Texinfo package:"
echo "<$gnu_software_URL/texinfo/>"
echo "The spurious makeinfo call might also be the consequence of"
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
echo "want to install GNU make:"
echo "<$gnu_software_URL/make/>"
;;
*)
echo "You might have modified some files without having the proper"
echo "tools for further handling them. Check the 'README' file, it"
echo "often tells you about the needed prerequisites for installing"
echo "this package. You may also peek at any GNU archive site, in"
echo "case some other package contains this missing '$1' program."
;;
esac
}
give_advice "$1" | sed -e '1s/^/WARNING: /' \
-e '2,$s/^/ /' >&2
# Propagate the correct exit status (expected to be 127 for a program
# not found, 63 for a program that failed due to version mismatch).
exit $st
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
+9 -4
View File
@@ -11,14 +11,16 @@ connection_timeout = 10
keepalive_timeout = 0
announce_interval = 1800
announce_jitter = 240
max_request_size = 4096
numwant_limit = 50
request_log_size = 500
mysql_host =
mysql_username =
mysql_password =
mysql_db =
mysql_host = mysql
mysql_port = 36000
mysql_username = gazelle
mysql_password = password
mysql_db = gazelle
# The passwords must be 32 characters and match the Gazelle config
report_password = 00000000000000000000000000000000
@@ -29,4 +31,7 @@ del_reason_lifetime = 86400
reap_peers_interval = 1800
schedule_interval = 3
log = false
log_path = /tmp/ocelot
readonly = false
+20
View File
@@ -0,0 +1,20 @@
[Unit]
Description=Ocelot Bittorrent Tracker
After=network.target
After=mysql.target
Requires=network.target
Requires=mysql.service
[Service]
Type=simple
TimeoutStartSec=0
ExecStart=/usr/local/bin/ocelot
ExecReload=/bin/kill -HUP $MAINPID
PIDFile=/var/run/ocelot.pid
RestartSec=20
TimeoutStopSec=60
TimeoutStartSec=360
Restart=always
[Install]
WantedBy=multi-user.target
-56
View File
@@ -1,56 +0,0 @@
#include <iostream>
#include <map>
#include <sstream>
#include "ocelot.h"
#include "misc_functions.h"
#include "report.h"
#include "response.h"
#include "user.h"
std::string report(params_type &params, user_list &users_list, client_opts_t &client_opts) {
std::stringstream output;
std::string action = params["get"];
if (action == "") {
output << "Invalid action\n";
} else if (action == "stats") {
time_t uptime = time(NULL) - stats.start_time;
int up_d = uptime / 86400;
uptime -= up_d * 86400;
int up_h = uptime / 3600;
uptime -= up_h * 3600;
int up_m = uptime / 60;
int up_s = uptime - up_m * 60;
std::string up_ht = up_h <= 9 ? '0' + inttostr(up_h) : inttostr(up_h);
std::string up_mt = up_m <= 9 ? '0' + inttostr(up_m) : inttostr(up_m);
std::string up_st = up_s <= 9 ? '0' + inttostr(up_s) : inttostr(up_s);
output << "Uptime: " << up_d << " days, " << up_ht << ':' << up_mt << ':' << up_st << '\n'
<< stats.opened_connections << " connections opened\n"
<< stats.open_connections << " open connections\n"
<< stats.connection_rate << " connections/s\n"
<< stats.requests << " requests handled\n"
<< stats.request_rate << " requests/s\n"
<< stats.succ_announcements << " successful announcements\n"
<< (stats.announcements - stats.succ_announcements) << " failed announcements\n"
<< stats.scrapes << " scrapes\n"
<< stats.leechers << " leechers tracked\n"
<< stats.seeders << " seeders tracked\n"
<< stats.bytes_read << " bytes read\n"
<< stats.bytes_written << " bytes written\n";
} else if (action == "user") {
std::string key = params["key"];
if (key == "") {
output << "Invalid action\n";
} else {
user_list::const_iterator u = users_list.find(key);
if (u != users_list.end()) {
output << u->second->get_leeching() << " leeching\n"
<< u->second->get_seeding() << " seeding\n";
}
}
} else {
output << "Invalid action\n";
}
output << "success";
return response(output.str(), client_opts);
}
-4
View File
@@ -1,4 +0,0 @@
#include <string>
#include "ocelot.h"
std::string report(params_type &params, user_list &users_list, client_opts_t &client_opts);
+12 -2
View File
@@ -1,6 +1,7 @@
#include <iostream>
#include <fstream>
#include <string>
#include <spdlog/spdlog.h>
#include "config.h"
#include "misc_functions.h"
@@ -61,9 +62,11 @@ void config::init() {
add("max_read_buffer", 4096u);
add("connection_timeout", 10u);
add("keepalive_timeout", 0u);
add("daemonize", false);
// Tracker requests
add("announce_interval", 1800u);
add("announce_jitter", 240u);
add("max_request_size", 4096u);
add("numwant_limit", 50u);
add("request_log_size", 500u);
@@ -77,15 +80,22 @@ void config::init() {
// MySQL
add("mysql_db", "gazelle");
add("mysql_host", "localhost");
add("mysql_port", 3306u);
add("mysql_username", "");
add("mysql_password", "");
add("mysql_port", 3306u);
// Site communication
add("site_host", "127.0.0.1");
add("site_service", "http");
add("site_path", "");
add("site_password", "00000000000000000000000000000000");
add("report_password", "00000000000000000000000000000000");
// Logging
add("log", false);
add("log_path", "ocelot"); // path to where to write log + name of log (don't need to put file extension)
// Debugging
add("readonly", false);
}
@@ -93,7 +103,7 @@ void config::init() {
confval * config::get(const std::string &setting_name) {
const auto setting = settings.find(setting_name);
if (setting == settings.end()) {
std::cout << "WARNING: Unrecognized setting '" << setting_name << "'" << std::endl;
spdlog::get("logger")->info("WARNING: Unrecognized setting '" + setting_name + "'");
return dummy_setting;
}
return &setting->second;
@@ -136,7 +146,7 @@ void config::reload() {
const std::string conf_file_path(get_str("conf_file_path"));
std::ifstream conf_file(conf_file_path);
if (conf_file.fail()) {
std::cout << "Config file '" << conf_file_path << "' couldn't be opened" << std::endl;
spdlog::get("logger")->error("Config file '" + conf_file_path + "' couldn't be opened");
} else {
init();
load(conf_file);
View File
File renamed without changes.
+132 -106
View File
@@ -3,6 +3,7 @@
#include "user.h"
#include "misc_functions.h"
#include "config.h"
#include <chrono>
#include <string>
#include <iostream>
#include <queue>
@@ -11,30 +12,32 @@
#include <mutex>
#include <thread>
#include <unordered_set>
#include <spdlog/spdlog.h>
#define DB_LOCK_TIMEOUT 50
mysql::mysql(config * conf) : u_active(false), t_active(false), p_active(false), s_active(false), tok_active(false) {
logger = spdlog::get("logger");
load_config(conf);
if (mysql_db == "") {
std::cout << "No database selected" << std::endl;
if (mysql_db.empty()) {
logger->error("No database selected");
return;
}
try {
mysqlpp::ReconnectOption reconnect(true);
conn.set_option(&reconnect);
conn.connect(mysql_db.c_str(), mysql_host.c_str(), mysql_username.c_str(), mysql_password.c_str(), 0);
conn.connect(mysql_db.c_str(), mysql_host.c_str(), mysql_username.c_str(), mysql_password.c_str(), mysql_port);
} catch (const mysqlpp::Exception &er) {
std::cout << "Failed to connect to MySQL (" << er.what() << ')' << std::endl;
logger->error("Failed to connect to MySQL (" + std::string(er.what()) + ")");
return;
}
if (!readonly) {
std::cout << "Clearing xbt_files_users and resetting peer counts...";
std::cout.flush();
logger->info("Clearing xbt_files_users and resetting peer counts...");
logger->flush();
clear_peer_data();
std::cout << "done" << std::endl;
logger->info("done");
}
}
@@ -43,6 +46,7 @@ void mysql::load_config(config * conf) {
mysql_host = conf->get_str("mysql_host");
mysql_username = conf->get_str("mysql_username");
mysql_password = conf->get_str("mysql_password");
mysql_port = conf->get_uint("mysql_port");
readonly = conf->get_bool("readonly");
}
@@ -54,25 +58,31 @@ bool mysql::connected() {
return conn.connected();
}
mysqlpp::Connection mysql::create_connection() {
mysqlpp::Connection c(conn);
c.set_option(new mysqlpp::ReconnectOption(true));
return c;
}
void mysql::clear_peer_data() {
try {
mysqlpp::Query query = conn.query("TRUNCATE xbt_files_users;");
if (!query.exec()) {
std::cerr << "Unable to truncate xbt_files_users!" << std::endl;
logger->error("Unable to truncate xbt_files_users!");
}
query = conn.query("UPDATE torrents SET Seeders = 0, Leechers = 0;");
query = conn.query("UPDATE torrents_leech_stats SET Seeders = 0, Leechers = 0;");
if (!query.exec()) {
std::cerr << "Unable to reset seeder and leecher count!" << std::endl;
logger->error("Unable to reset seeder and leecher count!");
}
} catch (const mysqlpp::BadQuery &er) {
std::cerr << "Query error in clear_peer_data: " << er.what() << std::endl;
logger->error("Query error in clear_peer_data: " + std::string(er.what()));
} catch (const mysqlpp::Exception &er) {
std::cerr << "Query error in clear_peer_data: " << er.what() << std::endl;
logger->error("Query error in clear_peer_data: " + std::string(er.what()));
}
}
void mysql::load_torrents(torrent_list &torrents) {
mysqlpp::Query query = conn.query("SELECT ID, info_hash, freetorrent, Snatched FROM torrents ORDER BY ID;");
mysqlpp::Query query = conn.query("SELECT t.ID, t.info_hash, t.freetorrent, tls.Snatched FROM torrents t INNER JOIN torrents_leech_stats tls ON (tls.TorrentID = t.ID) ORDER BY t.ID");
try {
mysqlpp::StoreQueryResult res = query.store();
std::unordered_set<std::string> cur_keys;
@@ -90,7 +100,7 @@ void mysql::load_torrents(torrent_list &torrents) {
for (size_t i = 0; i < num_rows; i++) {
std::string info_hash;
res[i][1].to_string(info_hash);
if (info_hash == "") {
if (info_hash.empty()) {
continue;
}
mysqlpp::sql_enum free_torrent(res[i][2]);
@@ -132,10 +142,10 @@ void mysql::load_torrents(torrent_list &torrents) {
}
}
} catch (const mysqlpp::BadQuery &er) {
std::cerr << "Query error in load_torrents: " << er.what() << std::endl;
logger->error("Query error in load_torrents: " + std::string(er.what()));
return;
}
std::cout << "Loaded " << torrents.size() << " torrents" << std::endl;
logger->info("Loaded " + std::to_string(torrents.size()) + " torrents");
load_tokens(torrents);
}
@@ -147,7 +157,7 @@ void mysql::load_users(user_list &users) {
std::unordered_set<std::string> cur_keys;
std::lock_guard<std::mutex> ul_lock(user_list_mutex);
if (users.size() == 0) {
users.reserve(num_rows * 1.05); // Reserve 5% extra space to prevent rehashing
users.reserve(static_cast<unsigned long>(num_rows * 1.05)); // Reserve 5% extra space to prevent rehashing
} else {
// Create set with all currently known user keys to remove nonexistent ones later
cur_keys.reserve(users.size());
@@ -177,14 +187,14 @@ void mysql::load_users(user_list &users) {
}
}
} catch (const mysqlpp::BadQuery &er) {
std::cerr << "Query error in load_users: " << er.what() << std::endl;
logger->error("Query error in load_users: " + std::string(er.what()));
return;
}
std::cout << "Loaded " << users.size() << " users" << std::endl;
logger->info("Loaded " + std::to_string(users.size()) + " users");
}
void mysql::load_tokens(torrent_list &torrents) {
mysqlpp::Query query = conn.query("SELECT uf.UserID, t.info_hash FROM users_freeleeches AS uf JOIN torrents AS t ON t.ID = uf.TorrentID WHERE uf.Expired = '0';");
mysqlpp::Query query = conn.query("SELECT uf.UserID, t.info_hash FROM users_freeleeches AS uf INNER JOIN torrents AS t ON t.ID = uf.TorrentID WHERE uf.Expired = '0';");
int token_count = 0;
try {
mysqlpp::StoreQueryResult res = query.store();
@@ -201,10 +211,10 @@ void mysql::load_tokens(torrent_list &torrents) {
}
}
} catch (const mysqlpp::BadQuery &er) {
std::cerr << "Query error in load_tokens: " << er.what() << std::endl;
logger->error("Query error in load_tokens: " + std::string(er.what()));
return;
}
std::cout << "Loaded " << token_count << " tokens" << std::endl;
logger->info("Loaded " + std::to_string(token_count) + " tokens");
}
@@ -221,25 +231,25 @@ void mysql::load_whitelist(std::vector<std::string> &whitelist) {
whitelist.push_back(peer_id);
}
} catch (const mysqlpp::BadQuery &er) {
std::cerr << "Query error in load_whitelist: " << er.what() << std::endl;
logger->error("Query error in load_whitelist: " + std::string(er.what()));
return;
}
if (whitelist.size() == 0) {
std::cout << "Assuming no whitelist desired, disabling" << std::endl;
logger->info("Assuming no whitelist desired, disabling");
} else {
std::cout << "Loaded " << whitelist.size() << " clients into the whitelist" << std::endl;
logger->info("Loaded " + std::to_string(whitelist.size()) + " clients into the whitelist");
}
}
void mysql::record_token(const std::string &record) {
if (update_token_buffer != "") {
if (!update_token_buffer.empty()) {
update_token_buffer += ",";
}
update_token_buffer += record;
}
void mysql::record_user(const std::string &record) {
if (update_user_buffer != "") {
if (!update_user_buffer.empty()) {
update_user_buffer += ",";
}
update_user_buffer += record;
@@ -247,14 +257,14 @@ void mysql::record_user(const std::string &record) {
void mysql::record_torrent(const std::string &record) {
std::lock_guard<std::mutex> tb_lock(torrent_buffer_lock);
if (update_torrent_buffer != "") {
if (!update_torrent_buffer.empty()) {
update_torrent_buffer += ",";
}
update_torrent_buffer += record;
}
void mysql::record_peer(const std::string &record, const std::string &ip, const std::string &peer_id, const std::string &useragent) {
if (update_heavy_peer_buffer != "") {
if (!update_heavy_peer_buffer.empty()) {
update_heavy_peer_buffer += ",";
}
mysqlpp::Query q = conn.query();
@@ -263,7 +273,7 @@ void mysql::record_peer(const std::string &record, const std::string &ip, const
update_heavy_peer_buffer += q.str();
}
void mysql::record_peer(const std::string &record, const std::string &peer_id) {
if (update_light_peer_buffer != "") {
if (!update_light_peer_buffer.empty()) {
update_light_peer_buffer += ",";
}
mysqlpp::Query q = conn.query();
@@ -273,7 +283,7 @@ void mysql::record_peer(const std::string &record, const std::string &peer_id) {
}
void mysql::record_snatch(const std::string &record, const std::string &ip) {
if (update_snatch_buffer != "") {
if (!update_snatch_buffer.empty()) {
update_snatch_buffer += ",";
}
mysqlpp::Query q = conn.query();
@@ -302,16 +312,17 @@ void mysql::flush_users() {
std::lock_guard<std::mutex> uq_lock(user_queue_lock);
size_t qsize = user_queue.size();
if (verbose_flush || qsize > 0) {
std::cout << "User flush queue size: " << qsize << ", next query length: " << user_queue.front().size() << std::endl;
logger->info("User flush queue size: " + std::to_string(qsize) + ", next query length: " + std::to_string(user_queue.front().size()));
}
if (update_user_buffer == "") {
if (update_user_buffer.empty()) {
return;
}
sql = "INSERT INTO users_main (ID, Uploaded, Downloaded) VALUES " + update_user_buffer +
sql = "INSERT INTO users_leech_stats (UserID, Uploaded, Downloaded) VALUES " + update_user_buffer +
" ON DUPLICATE KEY UPDATE Uploaded = Uploaded + VALUES(Uploaded), Downloaded = Downloaded + VALUES(Downloaded)";
user_queue.push(sql);
update_user_buffer.clear();
if (u_active == false) {
stats.user_queue_size = qsize + 1;
if (!u_active) {
std::thread thread(&mysql::do_flush_users, this);
thread.detach();
}
@@ -327,12 +338,12 @@ void mysql::flush_torrents() {
std::lock_guard<std::mutex> tq_lock(torrent_queue_lock);
size_t qsize = torrent_queue.size();
if (verbose_flush || qsize > 0) {
std::cout << "Torrent flush queue size: " << qsize << ", next query length: " << torrent_queue.front().size() << std::endl;
logger->info("Torrent flush queue size: " + std::to_string(qsize) + ", next query length: " + std::to_string(torrent_queue.front().size()));
}
if (update_torrent_buffer == "") {
if (update_torrent_buffer.empty()) {
return;
}
sql = "INSERT INTO torrents (ID,Seeders,Leechers,Snatched,Balance) VALUES " + update_torrent_buffer +
sql = "INSERT INTO torrents_leech_stats (TorrentID,Seeders,Leechers,Snatched,Balance) VALUES " + update_torrent_buffer +
" ON DUPLICATE KEY UPDATE Seeders=VALUES(Seeders), Leechers=VALUES(Leechers), " +
"Snatched=Snatched+VALUES(Snatched), Balance=VALUES(Balance), last_action = " +
"IF(VALUES(Seeders) > 0, NOW(), last_action)";
@@ -341,7 +352,8 @@ void mysql::flush_torrents() {
sql.clear();
sql = "DELETE FROM torrents WHERE info_hash = ''";
torrent_queue.push(sql);
if (t_active == false) {
stats.torrent_queue_size = qsize + 2;
if (!t_active) {
std::thread thread(&mysql::do_flush_torrents, this);
thread.detach();
}
@@ -356,15 +368,16 @@ void mysql::flush_snatches() {
std::lock_guard<std::mutex> sq_lock(snatch_queue_lock);
size_t qsize = snatch_queue.size();
if (verbose_flush || qsize > 0) {
std::cout << "Snatch flush queue size: " << qsize << ", next query length: " << snatch_queue.front().size() << std::endl;
logger->info("Snatch flush queue size: " + std::to_string(qsize) + ", next query length: " + std::to_string(snatch_queue.front().size()));
}
if (update_snatch_buffer == "" ) {
if (update_snatch_buffer.empty()) {
return;
}
sql = "INSERT INTO xbt_snatched (uid, fid, tstamp, IP) VALUES " + update_snatch_buffer;
sql = "INSERT IGNORE INTO xbt_snatched (uid, fid, tstamp, IP) VALUES " + update_snatch_buffer;
snatch_queue.push(sql);
update_snatch_buffer.clear();
if (s_active == false) {
stats.snatch_queue_size = qsize + 1;
if (!s_active) {
std::thread thread(&mysql::do_flush_snatches, this);
thread.detach();
}
@@ -379,22 +392,25 @@ void mysql::flush_peers() {
std::string sql;
std::lock_guard<std::mutex> pq_lock(peer_queue_lock);
size_t qsize = peer_queue.size();
short qsize_added = 0;
if (verbose_flush || qsize > 0) {
std::cout << "Peer flush queue size: " << qsize << ", next query length: " << peer_queue.front().size() << std::endl;
logger->info("Peer flush queue size: " + std::to_string(qsize) + ", next query length: " + std::to_string(peer_queue.front().size()));
}
// Nothing to do
if (update_light_peer_buffer == "" && update_heavy_peer_buffer == "") {
if (update_light_peer_buffer.empty() && update_heavy_peer_buffer.empty()) {
return;
}
if (update_heavy_peer_buffer != "") {
if (!update_heavy_peer_buffer.empty()) {
// Because xfu inserts are slow and ram is not infinite we need to
// limit this queue's size
// xfu will be messed up if the light query inserts a new row,
// but that's better than an oom crash
if (qsize >= 1000) {
peer_queue.pop();
} else {
qsize_added += 1;
}
sql = "INSERT INTO xbt_files_users (uid,fid,active,uploaded,downloaded,upspeed,downspeed,remaining,corrupt," +
std::string("timespent,announced,ip,peer_id,useragent,mtime) VALUES ") + update_heavy_peer_buffer +
@@ -407,10 +423,12 @@ void mysql::flush_peers() {
update_heavy_peer_buffer.clear();
sql.clear();
}
if (update_light_peer_buffer != "") {
if (!update_light_peer_buffer.empty()) {
// See comment above
if (qsize >= 1000) {
peer_queue.pop();
} else {
qsize_added += 1;
}
sql = "INSERT INTO xbt_files_users (uid,fid,timespent,announced,peer_id,mtime) VALUES " +
update_light_peer_buffer +
@@ -420,8 +438,9 @@ void mysql::flush_peers() {
update_light_peer_buffer.clear();
sql.clear();
}
stats.peer_queue_size = qsize + qsize_added;
if (p_active == false) {
if (!p_active) {
std::thread thread(&mysql::do_flush_peers, this);
thread.detach();
}
@@ -436,16 +455,17 @@ void mysql::flush_tokens() {
std::lock_guard<std::mutex> tq_lock(token_queue_lock);
size_t qsize = token_queue.size();
if (verbose_flush || qsize > 0) {
std::cout << "Token flush queue size: " << qsize << ", next query length: " << token_queue.front().size() << std::endl;
logger->info("Token flush queue size: " + std::to_string(qsize) + ", next query length: " + std::to_string(token_queue.front().size()));
}
if (update_token_buffer == "") {
if (update_token_buffer.empty()) {
return;
}
sql = "INSERT INTO users_freeleeches (UserID, TorrentID, Downloaded) VALUES " + update_token_buffer +
" ON DUPLICATE KEY UPDATE Downloaded = Downloaded + VALUES(Downloaded)";
token_queue.push(sql);
update_token_buffer.clear();
if (tok_active == false) {
stats.token_queue_size = qsize + 1;
if (!tok_active) {
std::thread thread(&mysql::do_flush_tokens, this);
thread.detach();
}
@@ -454,33 +474,34 @@ void mysql::flush_tokens() {
void mysql::do_flush_users() {
u_active = true;
try {
mysqlpp::Connection c(mysql_db.c_str(), mysql_host.c_str(), mysql_username.c_str(), mysql_password.c_str(), 0);
mysqlpp::Connection c = create_connection();
while (user_queue.size() > 0) {
try {
std::string sql = user_queue.front();
mysqlpp::Query query = c.query(sql);
if (!query.exec()) {
std::cout << "User flush failed (" << user_queue.size() << " remain)" << std::endl;
logger->info("User flush failed (" + std::to_string(user_queue.size()) + " remain)");
sleep(3);
continue;
break;
} else {
std::lock_guard<std::mutex> uq_lock(user_queue_lock);
user_queue.pop();
stats.user_queue_size -= 1;
}
}
catch (const mysqlpp::BadQuery &er) {
std::cerr << "Query error: " << er.what() << " in flush users with a qlength: " << user_queue.front().size() << " queue size: " << user_queue.size() << std::endl;
sleep(3);
continue;
logger->error("Query error: " + std::string(er.what()) + " in flush users with a qlength: " + std::to_string(user_queue.front().size()) + " queue size: " + std::to_string(user_queue.size()));
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
} catch (const mysqlpp::Exception &er) {
std::cerr << "Query error: " << er.what() << " in flush users with a qlength: " << user_queue.front().size() << " queue size: " << user_queue.size() << std::endl;
sleep(3);
continue;
logger->error("Query error: " + std::string(er.what()) + " in flush users with a qlength: " + std::to_string(user_queue.front().size()) + " queue size: " + std::to_string(user_queue.size()));
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
}
}
}
catch (const mysqlpp::Exception &er) {
std::cerr << "MySQL error in flush_users: " << er.what() << std::endl;
logger->error("MySQL error in flush_users: " + std::string(er.what()));
}
u_active = false;
}
@@ -488,37 +509,39 @@ void mysql::do_flush_users() {
void mysql::do_flush_torrents() {
t_active = true;
try {
mysqlpp::Connection c(mysql_db.c_str(), mysql_host.c_str(), mysql_username.c_str(), mysql_password.c_str(), 0);
mysqlpp::Connection c = create_connection();
while (torrent_queue.size() > 0) {
try {
std::string sql = torrent_queue.front();
if (sql == "") {
if (sql.empty()) {
torrent_queue.pop();
stats.torrent_queue_size -= 1;
continue;
}
mysqlpp::Query query = c.query(sql);
if (!query.exec()) {
std::cout << "Torrent flush failed (" << torrent_queue.size() << " remain)" << std::endl;
sleep(3);
continue;
logger->info("Torrent flush failed (" + std::to_string(torrent_queue.size()) + " remain)");
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
} else {
std::lock_guard<std::mutex> tq_lock(torrent_queue_lock);
torrent_queue.pop();
stats.torrent_queue_size -= 1;
}
}
catch (const mysqlpp::BadQuery &er) {
std::cerr << "Query error: " << er.what() << " in flush torrents with a qlength: " << torrent_queue.front().size() << " queue size: " << torrent_queue.size() << std::endl;
sleep(3);
continue;
logger->error("Query error: " + std::string(er.what()) + " in flush torrents with a qlength: " + std::to_string(torrent_queue.front().size()) + " queue size: " + std::to_string(torrent_queue.size()));
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
} catch (const mysqlpp::Exception &er) {
std::cerr << "Query error: " << er.what() << " in flush torrents with a qlength: " << torrent_queue.front().size() << " queue size: " << torrent_queue.size() << std::endl;
sleep(3);
continue;
logger->error("Query error: " + std::string(er.what()) + " in flush torrents with a qlength: " + std::to_string(torrent_queue.front().size()) + " queue size: " + std::to_string(torrent_queue.size()));
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
}
}
}
catch (const mysqlpp::Exception &er) {
std::cerr << "MySQL error in flush_torrents: " << er.what() << std::endl;
logger->error("MySQL error in flush_torrents: " + std::string(er.what()));
}
t_active = false;
}
@@ -526,33 +549,34 @@ void mysql::do_flush_torrents() {
void mysql::do_flush_peers() {
p_active = true;
try {
mysqlpp::Connection c(mysql_db.c_str(), mysql_host.c_str(), mysql_username.c_str(), mysql_password.c_str(), 0);
mysqlpp::Connection c = create_connection();
while (peer_queue.size() > 0) {
try {
std::string sql = peer_queue.front();
mysqlpp::Query query = c.query(sql);
if (!query.exec()) {
std::cout << "Peer flush failed (" << peer_queue.size() << " remain)" << std::endl;
sleep(3);
continue;
logger->info("Peer flush failed (" + std::to_string(peer_queue.size()) + " remain)");
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
} else {
std::lock_guard<std::mutex> pq_lock(peer_queue_lock);
peer_queue.pop();
stats.peer_queue_size -= 1;
}
}
catch (const mysqlpp::BadQuery &er) {
std::cerr << "Query error: " << er.what() << " in flush peers with a qlength: " << peer_queue.front().size() << " queue size: " << peer_queue.size() << std::endl;
sleep(3);
continue;
logger->error("Query error: " + std::string(er.what()) + " in flush peers with a qlength: " + std::to_string(peer_queue.front().size()) + " queue size: " + std::to_string(peer_queue.size()));
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
} catch (const mysqlpp::Exception &er) {
std::cerr << "Query error: " << er.what() << " in flush peers with a qlength: " << peer_queue.front().size() << " queue size: " << peer_queue.size() << std::endl;
sleep(3);
continue;
logger->error("Query error: " + std::string(er.what()) + " in flush peers with a qlength: " + std::to_string(peer_queue.front().size()) + " queue size: " + std::to_string(peer_queue.size()));
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
}
}
}
catch (const mysqlpp::Exception &er) {
std::cerr << "MySQL error in flush_peers: " << er.what() << std::endl;
logger->error("MySQL error in flush_peers: " + std::string(er.what()));
}
p_active = false;
}
@@ -560,33 +584,34 @@ void mysql::do_flush_peers() {
void mysql::do_flush_snatches() {
s_active = true;
try {
mysqlpp::Connection c(mysql_db.c_str(), mysql_host.c_str(), mysql_username.c_str(), mysql_password.c_str(), 0);
mysqlpp::Connection c = create_connection();
while (snatch_queue.size() > 0) {
try {
std::string sql = snatch_queue.front();
mysqlpp::Query query = c.query(sql);
if (!query.exec()) {
std::cout << "Snatch flush failed (" << snatch_queue.size() << " remain)" << std::endl;
sleep(3);
continue;
logger->info("Snatch flush failed (" + std::to_string(snatch_queue.size()) + " remain)");
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
} else {
std::lock_guard<std::mutex> sq_lock(snatch_queue_lock);
snatch_queue.pop();
stats.snatch_queue_size -= 1;
}
}
catch (const mysqlpp::BadQuery &er) {
std::cerr << "Query error: " << er.what() << " in flush snatches with a qlength: " << snatch_queue.front().size() << " queue size: " << snatch_queue.size() << std::endl;
sleep(3);
continue;
logger->error("Query error: " + std::string(er.what()) + " in flush snatches with a qlength: " + std::to_string(snatch_queue.front().size()) + " queue size: " + std::to_string(snatch_queue.size()));
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
} catch (const mysqlpp::Exception &er) {
std::cerr << "Query error: " << er.what() << " in flush snatches with a qlength: " << snatch_queue.front().size() << " queue size: " << snatch_queue.size() << std::endl;
sleep(3);
continue;
logger->error("Query error: " + std::string(er.what()) + " in flush snatches with a qlength: " + std::to_string(snatch_queue.front().size()) + " queue size: " + std::to_string(snatch_queue.size()));
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
}
}
}
catch (const mysqlpp::Exception &er) {
std::cerr << "MySQL error in flush_snatches: " << er.what() << std::endl;
logger->error("MySQL error in flush_snatches: " + std::string(er.what()));
}
s_active = false;
}
@@ -594,33 +619,34 @@ void mysql::do_flush_snatches() {
void mysql::do_flush_tokens() {
tok_active = true;
try {
mysqlpp::Connection c(mysql_db.c_str(), mysql_host.c_str(), mysql_username.c_str(), mysql_password.c_str(), 0);
mysqlpp::Connection c = create_connection();
while (token_queue.size() > 0) {
try {
std::string sql = token_queue.front();
mysqlpp::Query query = c.query(sql);
if (!query.exec()) {
std::cout << "Token flush failed (" << token_queue.size() << " remain)" << std::endl;
sleep(3);
continue;
logger->info("Token flush failed (" + std::to_string(token_queue.size()) + " remain)");
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
} else {
std::lock_guard<std::mutex> tq_lock(token_queue_lock);
token_queue.pop();
stats.token_queue_size -= 1;
}
}
catch (const mysqlpp::BadQuery &er) {
std::cerr << "Query error: " << er.what() << " in flush tokens with a qlength: " << token_queue.front().size() << " queue size: " << token_queue.size() << std::endl;
sleep(3);
continue;
logger->error("Query error: " + std::string(er.what()) + " in flush tokens with a qlength: " + std::to_string(token_queue.front().size()) + " queue size: " + std::to_string(token_queue.size()));
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
} catch (const mysqlpp::Exception &er) {
std::cerr << "Query error: " << er.what() << " in flush tokens with a qlength: " << token_queue.front().size() << " queue size: " << token_queue.size() << std::endl;
sleep(3);
continue;
logger->error("Query error: " + std::string(er.what()) + " in flush tokens with a qlength: " + std::to_string(token_queue.front().size()) + " queue size: " + std::to_string(token_queue.size()));
std::this_thread::sleep_for(std::chrono::seconds(3));
break;
}
}
}
catch (const mysqlpp::Exception &er) {
std::cerr << "MySQL error in flush_tokens: " << er.what() << std::endl;
logger->error("MySQL error in flush_tokens: " + std::string(er.what()));
}
tok_active = false;
}
+5
View File
@@ -2,6 +2,7 @@
#define OCELOT_DB_H
#pragma GCC visibility push(default)
#include <mysql++/mysql++.h>
#include <spdlog/spdlog.h>
#include <string>
#include <unordered_map>
#include <queue>
@@ -25,6 +26,7 @@ class mysql {
std::queue<std::string> token_queue;
std::string mysql_db, mysql_host, mysql_username, mysql_password;
unsigned int mysql_port;
bool u_active, t_active, p_active, s_active, tok_active;
bool readonly;
@@ -37,8 +39,11 @@ class mysql {
std::mutex snatch_queue_lock;
std::mutex token_queue_lock;
std::shared_ptr<spdlog::logger> logger;
void load_config(config * conf);
void load_tokens(torrent_list &torrents);
mysqlpp::Connection create_connection();
void do_flush_users();
void do_flush_torrents();
+21 -16
View File
@@ -1,4 +1,5 @@
#include <cerrno>
#include <spdlog/spdlog.h>
#include "ocelot.h"
#include "config.h"
#include "db.h"
@@ -14,11 +15,19 @@
//---------- Connection mother - spawns middlemen and lets them deal with the connection
connection_mother::connection_mother(config * conf, worker * worker_obj, mysql * db_obj, site_comm * sc_obj, schedule * sched) : work(worker_obj), db(db_obj) {
logger = spdlog::get("logger");
// Handle config stuff first
load_config(conf);
listen_socket = create_listen_socket();
// We failed to create the socket, so no point in running Ocelot
if (listen_socket == 0) {
logger->critical("Failed to create socket for Ocelot. Exiting.");
exit(1);
}
listen_event.set<connection_mother, &connection_mother::handle_connect>(this);
listen_event.start(listen_socket, ev::READ);
// Create libev timer
@@ -41,7 +50,7 @@ void connection_mother::reload_config(config * conf) {
unsigned int old_max_connections = max_connections;
load_config(conf);
if (old_listen_port != listen_port) {
std::cout << "Changing listen port from " << old_listen_port << " to " << listen_port << std::endl;
logger->info("Changing listen port from " + std::to_string(old_listen_port) +" to " + std::to_string(listen_port));
int new_listen_socket = create_listen_socket();
if (new_listen_socket != 0) {
listen_event.stop();
@@ -49,7 +58,7 @@ void connection_mother::reload_config(config * conf) {
close(listen_socket);
listen_socket = new_listen_socket;
} else {
std::cout << "Couldn't create new listen socket when reloading config" << std::endl;
logger->error("Couldn't create new listen socket when reloading config");
}
} else if (old_max_connections != max_connections) {
listen(listen_socket, max_connections);
@@ -64,7 +73,7 @@ int connection_mother::create_listen_socket() {
// Stop old sockets from hogging the port
int yes = 1;
if (setsockopt(new_listen_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
std::cout << "Could not reuse socket: " << strerror(errno) << std::endl;
logger->error("Could not reuse socket: " + std::string(strerror(errno)));
return 0;
}
@@ -76,24 +85,24 @@ int connection_mother::create_listen_socket() {
// Bind
if (bind(new_listen_socket, (sockaddr *) &address, sizeof(address)) == -1) {
std::cout << "Bind failed: " << strerror(errno) << std::endl;
logger->error("Bind failed: " + std::string(strerror(errno)));
return 0;
}
// Listen
if (listen(new_listen_socket, max_connections) == -1) {
std::cout << "Listen failed: " << strerror(errno) << std::endl;
logger->error("Listen failed: " + std::string(strerror(errno)));
return 0;
}
// Set non-blocking
int flags = fcntl(new_listen_socket, F_GETFL);
if (flags == -1) {
std::cout << "Could not get socket flags: " << strerror(errno) << std::endl;
logger->error("Could not get socket flags: " + std::string(strerror(errno)));
return 0;
}
if (fcntl(new_listen_socket, F_SETFL, flags | O_NONBLOCK) == -1) {
std::cout << "Could not set non-blocking: " << strerror(errno) << std::endl;
logger->error("Could not set non-blocking: " + std::string(strerror(errno)));
return 0;
}
@@ -101,7 +110,7 @@ int connection_mother::create_listen_socket() {
}
void connection_mother::run() {
std::cout << "Sockets up on port " << listen_port << ", starting event loop!" << std::endl;
logger->info("Sockets up on port " + std::to_string(listen_port) + ", starting event loop!");
ev_loop(ev_default_loop(0), 0);
}
@@ -120,19 +129,15 @@ connection_mother::~connection_mother()
}
//---------- Connection middlemen - these little guys live until their connection is closed
connection_middleman::connection_middleman(int &listen_socket, worker * new_work, connection_mother * mother_arg) :
written(0), mother(mother_arg), work(new_work)
{
auto logger = spdlog::get("logger");
connect_sock = accept(listen_socket, NULL, NULL);
if (connect_sock == -1) {
std::cout << "Accept failed, errno " << errno << ": " << strerror(errno) << std::endl;
logger->error("Accept failed, errno " + std::to_string(errno) + ": " + std::string(strerror(errno)));
delete this;
return;
}
@@ -140,10 +145,10 @@ connection_middleman::connection_middleman(int &listen_socket, worker * new_work
// Set non-blocking
int flags = fcntl(connect_sock, F_GETFL);
if (flags == -1) {
std::cout << "Could not get connect socket flags" << std::endl;
logger->warn("Could not get connect socket flags");
}
if (fcntl(connect_sock, F_SETFL, flags | O_NONBLOCK) == -1) {
std::cout << "Could not set non-blocking" << std::endl;
logger->warn("Could not set non-blocking");
}
// Get their info
+10
View File
@@ -1,6 +1,15 @@
#ifdef EV_ERROR
#undef EV_ERROR
#endif
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0x2000 /* don't raise SIGPIPE */
#endif
#include <iostream>
#include <string>
#include <cstring>
#include <spdlog/spdlog.h>
// libev
#include <ev++.h>
@@ -60,6 +69,7 @@ class connection_mother {
mysql * db;
ev::io listen_event;
ev::timer schedule_event;
std::shared_ptr<spdlog::logger> logger;
public:
connection_mother(config * conf, worker * worker_obj, mysql * db_obj, site_comm * sc_obj, schedule * sched_obj);
File renamed without changes.
File renamed without changes.
+94 -15
View File
@@ -2,13 +2,16 @@
#include <iostream>
#include <csignal>
#include <thread>
#include <sys/stat.h>
#include <syslog.h>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/daily_file_sink.h>
#include <spdlog/sinks/stdout_sinks.h>
#include "ocelot.h"
#include "config.h"
#include "db.h"
#include "worker.h"
#include "events.h"
#include "schedule.h"
#include "site_comm.h"
static connection_mother *mother;
static worker *work;
@@ -19,24 +22,70 @@ static schedule *sched;
struct stats_t stats;
const char * version()
{
return "2.1.0";
}
static void create_daemon()
{
pid_t pid;
/* Fork off the parent process */
pid = fork();
/* An error occurred */
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* Success: Let the parent terminate */
if (pid > 0) {
exit(EXIT_SUCCESS);
}
/* On success: The child process becomes session leader */
if (setsid() < 0)
exit(EXIT_FAILURE);
/* Set new file permissions */
umask(0);
/* Change the working directory to the root directory */
/* or another appropriated directory */
if (chdir("/") < 0) {
exit(EXIT_FAILURE);
}
/* Close all open file descriptors */
int x;
for (x = static_cast<int>(sysconf(_SC_OPEN_MAX)); x >= 0; x--) {
close (x);
}
/* Open the log file */
openlog("ocelot", LOG_PID, LOG_DAEMON);
}
static void sig_handler(int sig) {
std::shared_ptr<spdlog::logger> logger = spdlog::get("logger");
if (sig == SIGINT || sig == SIGTERM) {
std::cout << "Caught SIGINT/SIGTERM" << std::endl;
logger->info("Caught SIGINT/SIGTERM");
if (work->shutdown()) {
exit(0);
}
} else if (sig == SIGHUP) {
std::cout << "Reloading config" << std::endl;
std::cout.flush();
logger->info("Reloading config");
logger->flush();
conf->reload();
db->reload_config(conf);
mother->reload_config(conf);
sc->reload_config(conf);
sched->reload_config(conf);
work->reload_config(conf);
std::cout << "Done reloading config" << std::endl;
logger->info("Done reloading config");
} else if (sig == SIGUSR1) {
std::cout << "Reloading from database" << std::endl;
logger->info("Reloading from database");
std::thread w_thread(&worker::reload_lists, work);
w_thread.detach();
}
@@ -48,16 +97,28 @@ int main(int argc, char **argv) {
conf = new config();
bool verbose = false, conf_arg = false;
bool conf_arg = false;
bool daemonize = false;
bool verbose = false;
std::string conf_file_path("./ocelot.conf");
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-v")) {
if (strcmp(argv[i], "-v") == 0) {
verbose = true;
} else if (!strcmp(argv[i], "-c") && i < argc - 1) {
}
else if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--daemonize") == 0) {
daemonize = true;
}
else if (strcmp(argv[i], "-c") == 0 && i < argc - 1) {
conf_arg = true;
conf_file_path = argv[++i];
} else {
std::cout << "Usage: " << argv[0] << " [-v] [-c configfile]" << std::endl;
}
else if(strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0) {
std::cout << "Ocelot version " << version() << std::endl;
return 0;
}
else {
std::cout << "Usage: " << argv[0] << " [-v] [-c configfile] [--daemonize]" << std::endl;
return 0;
}
}
@@ -68,14 +129,32 @@ int main(int argc, char **argv) {
if (!conf_arg) {
std::cout << "Start Ocelot with -c <path> to specify config file if necessary" << std::endl;
}
} else {
}
else {
conf->load(conf_file_path, conf_file);
}
if (conf->get_bool("daemonize") || daemonize) {
create_daemon();
}
std::vector<spdlog::sink_ptr> sinks;
if (!conf->get_bool("daemonize") && !daemonize) {
sinks.push_back(std::make_shared<spdlog::sinks::stdout_sink_mt>());
}
if (conf->get_bool("log") && !conf->get_str("log_path").empty()) {
sinks.push_back(std::make_shared<spdlog::sinks::daily_file_sink_mt>(conf->get_str("log_path"), 23, 59));
}
auto combined_logger = std::make_shared<spdlog::logger>("logger", begin(sinks), end(sinks));
// If we don't set flush on info, the file log takes a long while to actually flush
combined_logger->flush_on(spdlog::level::info);
spdlog::register_logger(combined_logger);
db = new mysql(conf);
if (!db->connected()) {
std::cout << "Exiting" << std::endl;
combined_logger->critical("Could not connect to DB. Exiting!");
return 0;
}
db->verbose_flush = verbose;
@@ -114,7 +193,7 @@ int main(int argc, char **argv) {
mother = new connection_mother(conf, work, db, sc, sched);
// Add signal handlers now that all objects have been created
struct sigaction handler, ignore;
struct sigaction handler{}, ignore{};
ignore.sa_handler = SIG_IGN;
handler.sa_handler = sig_handler;
sigemptyset(&handler.sa_mask);
+8
View File
@@ -8,6 +8,7 @@
#include <set>
#include <memory>
#include <atomic>
#include <time.h>
typedef uint32_t torid_t;
typedef uint32_t userid_t;
@@ -94,6 +95,11 @@ struct stats_t {
std::atomic<uint64_t> connection_rate;
std::atomic<uint32_t> leechers;
std::atomic<uint32_t> seeders;
std::atomic<uint32_t> user_queue_size;
std::atomic<uint32_t> torrent_queue_size;
std::atomic<uint32_t> peer_queue_size;
std::atomic<uint32_t> snatch_queue_size;
std::atomic<uint32_t> token_queue_size;
std::atomic<uint64_t> requests;
std::atomic<uint64_t> request_rate;
std::atomic<uint64_t> announcements;
@@ -104,4 +110,6 @@ struct stats_t {
time_t start_time;
};
extern struct stats_t stats;
extern const char *version();
#endif
+88
View File
@@ -0,0 +1,88 @@
#include <iostream>
#include <map>
#include <sstream>
#include "ocelot.h"
#include "misc_functions.h"
#include "report.h"
#include "response.h"
#include "user.h"
std::string report(params_type &params, user_list &users_list, client_opts_t &client_opts, unsigned int announce_interval, unsigned int announce_jitter) {
std::stringstream output;
std::string action = params["get"];
if (action == "stats") {
time_t uptime = time(NULL) - stats.start_time;
int up_d = uptime / 86400;
uptime -= up_d * 86400;
int up_h = uptime / 3600;
uptime -= up_h * 3600;
int up_m = uptime / 60;
int up_s = uptime - up_m * 60;
output << "Uptime: " << up_d << " days, "
<< (up_h < 10 ? "0" : "") << inttostr(up_h) << ':'
<< (up_m < 10 ? "0" : "") << inttostr(up_m) << ':'
<< (up_s < 10 ? "0" : "") << inttostr(up_s) << "\n"
<< "version: " << version() << "\n"
<< stats.opened_connections << " connections opened\n"
<< stats.open_connections << " open connections\n"
<< stats.connection_rate << " connections/s\n"
<< stats.requests << " requests handled\n"
<< stats.request_rate << " requests/s\n"
<< stats.succ_announcements << " successful announcements\n"
<< (stats.announcements - stats.succ_announcements) << " failed announcements\n"
<< stats.scrapes << " scrapes\n"
<< stats.leechers << " leechers tracked\n"
<< stats.seeders << " seeders tracked\n"
<< stats.user_queue_size << " items in user queue\n"
<< stats.torrent_queue_size << " items in torrent queue\n"
<< stats.peer_queue_size << " items in peer queue\n"
<< stats.snatch_queue_size << " items in snatch queue\n"
<< stats.token_queue_size << " items in token queue\n"
<< stats.bytes_read << " bytes read\n"
<< stats.bytes_written << " bytes written\n"
<< announce_interval << " announce interval\n"
<< announce_jitter << " announce jitter\n"
;
} else if (action == "prom_stats") {
time_t uptime = time(NULL) - stats.start_time;
output << "ocelot_uptime " << uptime << "\n"
<< "ocelot_open_connections " << stats.open_connections << "\n"
<< "ocelot_connection_rate " << stats.connection_rate << "\n"
<< "ocelot_requests " << stats.requests << "\n"
<< "ocelot_request_rate " << stats.request_rate << "\n"
<< "ocelot_succ_announcements " << stats.succ_announcements << "\n"
<< "ocelot_total_announcements " << stats.announcements << "\n"
<< "ocelot_scrapes " << stats.scrapes << "\n"
<< "ocelot_leechers " << stats.leechers << "\n"
<< "ocelot_seeders " << stats.seeders << "\n"
<< "ocelot_user_queue " << stats.user_queue_size << "\n"
<< "ocelot_torrent_queue " << stats.torrent_queue_size << "\n"
<< "ocelot_peer_queue " << stats.peer_queue_size << "\n"
<< "ocelot_snatch_queue " << stats.snatch_queue_size << "\n"
<< "ocelot_token_queue " << stats.token_queue_size << "\n"
<< "ocelot_bytes_read " << stats.bytes_read << "\n"
<< "ocelot_bytes_written " << stats.bytes_written << "\n#";
} else if (action == "user") {
std::string key = params["key"];
if (key.empty()) {
output << "Invalid action\n";
} else {
user_list::const_iterator u = users_list.find(key);
if (u != users_list.end()) {
output << "{\"id\":" << u->second->get_id()
<< ",\"leeching\":" << u->second->get_leeching()
<< ",\"seeding\":" << u->second->get_seeding()
<< ",\"deleted\":" << u->second->is_deleted()
<< ",\"protected\":" << u->second->is_protected()
<< ",\"can_leech\":" << u->second->can_leech()
<< "}" << "\n";
return response(output.str(), client_opts);
}
}
} else {
output << "Invalid action\n";
}
output << "success";
return response(output.str(), client_opts);
}
+9
View File
@@ -0,0 +1,9 @@
#include "ocelot.h"
std::string report(
params_type &params,
user_list &users_list,
client_opts_t &client_opts,
unsigned int announce_interval,
unsigned int announce_jitter
);
View File
File renamed without changes.
Loaded 100 of 109 files, more files were not shown because too many files have changed in this diff. Show more