mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2025-11-01 13:30:25 -04:00
Merge branch 'develop' into feat-fst280
This commit is contained in:
commit
2964bc6295
43
AppVersion/AppVersion.cpp
Normal file
43
AppVersion/AppVersion.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
//
|
||||
// wsjtx_app_version - a console application that outputs WSJT-X
|
||||
// application version
|
||||
//
|
||||
// This application is only provided as a simple console application
|
||||
//
|
||||
//
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QCommandLineParser>
|
||||
#include <QCommandLineOption>
|
||||
|
||||
#include "revision_utils.hpp"
|
||||
|
||||
int main (int argc, char * argv[])
|
||||
{
|
||||
QCoreApplication app {argc, argv};
|
||||
try
|
||||
{
|
||||
app.setApplicationName ("WSJT-X");
|
||||
app.setApplicationVersion (version());
|
||||
|
||||
QCommandLineParser parser;
|
||||
// parser.setApplicationDescription ("\n" PROJECT_DESCRIPTION);
|
||||
parser.addHelpOption ();
|
||||
parser.addVersionOption ();
|
||||
parser.process (app);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
std::cerr << "Error: " << e.what () << '\n';
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Unexpected error\n";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -2,12 +2,15 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QAudioFormat>
|
||||
#include <QAudioInput>
|
||||
#include <QSysInfo>
|
||||
#include <QDebug>
|
||||
|
||||
#include "Logger.hpp"
|
||||
|
||||
#include "moc_soundin.cpp"
|
||||
|
||||
bool SoundInput::checkStream ()
|
||||
@ -178,8 +181,18 @@ void SoundInput::reset (bool report_dropped_frames)
|
||||
if (cummulative_lost_usec_ != std::numeric_limits<qint64>::min () && report_dropped_frames)
|
||||
{
|
||||
auto lost_usec = elapsed_usecs - m_stream->processedUSecs () - cummulative_lost_usec_;
|
||||
Q_EMIT dropped_frames (m_stream->format ().framesForDuration (lost_usec), lost_usec);
|
||||
//qDebug () << "SoundInput::reset: frames dropped:" << m_stream->format ().framesForDuration (lost_usec) << "sec:" << lost_usec / 1.e6;
|
||||
if (std::abs (lost_usec) > 48000 / 5)
|
||||
{
|
||||
LOG_WARN ("Detected dropped audio source samples: "
|
||||
<< m_stream->format ().framesForDuration (lost_usec)
|
||||
<< " (" << std::setprecision (4) << lost_usec / 1.e6 << " S)")
|
||||
}
|
||||
else if (std::abs (lost_usec) > 5 * 48000)
|
||||
{
|
||||
LOG_ERROR ("Detected excessive dropped audio source samples: "
|
||||
<< m_stream->format ().framesForDuration (lost_usec)
|
||||
<< " (" << std::setprecision (4) << lost_usec / 1.e6 << " S)")
|
||||
}
|
||||
}
|
||||
cummulative_lost_usec_ = elapsed_usecs - m_stream->processedUSecs ();
|
||||
}
|
||||
|
||||
@ -40,7 +40,6 @@ public:
|
||||
|
||||
Q_SIGNAL void error (QString message) const;
|
||||
Q_SIGNAL void status (QString message) const;
|
||||
Q_SIGNAL void dropped_frames (qint32 dropped, qint64 usec);
|
||||
|
||||
private:
|
||||
// used internally
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <qmath.h>
|
||||
#include <QDebug>
|
||||
|
||||
#include "Logger.hpp"
|
||||
#include "Audio/AudioDevice.hpp"
|
||||
|
||||
#include "moc_soundout.cpp"
|
||||
@ -104,15 +105,13 @@ void SoundOutput::restart (QIODevice * source)
|
||||
// Windows implementation seems to forget the buffer size after a
|
||||
// stop.
|
||||
//qDebug () << "SoundOut default buffer size (bytes):" << m_stream->bufferSize () << "period size:" << m_stream->periodSize ();
|
||||
if (m_framesBuffered)
|
||||
if (m_framesBuffered > 0)
|
||||
{
|
||||
#if defined (Q_OS_WIN)
|
||||
m_stream->setBufferSize (m_stream->format().bytesForFrames (m_framesBuffered));
|
||||
#endif
|
||||
}
|
||||
m_stream->setCategory ("production");
|
||||
m_stream->start (source);
|
||||
// qDebug () << "SoundOut selected buffer size (bytes):" << m_stream->bufferSize () << "period size:" << m_stream->periodSize ();
|
||||
LOG_INFO ("Selected buffer size (bytes): " << m_stream->bufferSize () << " period size: " << m_stream->periodSize ());
|
||||
}
|
||||
|
||||
void SoundOutput::suspend ()
|
||||
|
||||
101
CMakeLists.txt
101
CMakeLists.txt
@ -1,4 +1,4 @@
|
||||
cmake_minimum_required (VERSION 3.9 FATAL_ERROR)
|
||||
cmake_minimum_required (VERSION 3.7.2 FATAL_ERROR)
|
||||
|
||||
if (APPLE)
|
||||
#
|
||||
@ -13,7 +13,7 @@ if (APPLE)
|
||||
set (CMAKE_OSX_DEPLOYMENT_TARGET 10.12
|
||||
CACHE STRING "Earliest version of macOS supported
|
||||
|
||||
Earliest version we can support with Qt 5.12, C++11 & libc++ is 10.13.
|
||||
Earliest version we can support with Qt 5.12, C++11 & libc++ is 10.12.
|
||||
Do not override this if you intend to build an official deployable installer.")
|
||||
endif (APPLE)
|
||||
|
||||
@ -29,7 +29,7 @@ if (POLICY CMP0043)
|
||||
endif ()
|
||||
|
||||
if (POLICY CMP0048)
|
||||
cmake_policy (SET CMP0048 NEW) # clear PROJECT_Version_* vriables if not set in project() command
|
||||
cmake_policy (SET CMP0048 NEW) # clear PROJECT_Version_* variables if not set in project() command
|
||||
endif ()
|
||||
|
||||
if (POLICY CMP0063)
|
||||
@ -40,11 +40,15 @@ if (POLICY CMP0071)
|
||||
cmake_policy (SET CMP0071 NEW) # run automoc and autouic on generated sources
|
||||
endif ()
|
||||
|
||||
if (POLICY CMP0075)
|
||||
cmake_policy (SET CMP0075 NEW) # honour CMAKE_REQUIRED_LIBRARIES in config checks
|
||||
endif ()
|
||||
|
||||
project (wsjtx
|
||||
VERSION 2.4.0.0
|
||||
DESCRIPTION "WSJT-X: Digital Modes for Weak Signal Communications in Amateur Radio"
|
||||
LANGUAGES C CXX Fortran
|
||||
)
|
||||
set (PROJECT_DESCRIPTION "WSJT-X: Digital Modes for Weak Signal Communications in Amateur Radio")
|
||||
|
||||
#
|
||||
# Local CMake modules and support files
|
||||
@ -115,9 +119,6 @@ option (UPDATE_TRANSLATIONS "Update source translation translations/*.ts
|
||||
files (WARNING: make clean will delete the source .ts files! Danger!)")
|
||||
option (WSJT_SHARED_RUNTIME "Debugging option that allows running from a shared Cloud directory.")
|
||||
option (WSJT_QDEBUG_TO_FILE "Redirect Qt debuging messages to a trace file.")
|
||||
option (WSJT_TRACE_CAT "Debugging option that turns on CAT diagnostics.")
|
||||
option (WSJT_TRACE_CAT_POLLS "Debugging option that turns on CAT diagnostics during polling.")
|
||||
option (WSJT_HAMLIB_TRACE "Debugging option that turns on minimal Hamlib internal diagnostics.")
|
||||
option (WSJT_SOFT_KEYING "Apply a ramp to CW keying envelope to reduce transients." ON)
|
||||
option (WSJT_SKIP_MANPAGES "Skip *nix manpage generation.")
|
||||
option (WSJT_GENERATE_DOCS "Generate documentation files." ON)
|
||||
@ -125,9 +126,6 @@ option (WSJT_RIG_NONE_CAN_SPLIT "Allow split operation with \"None\" as rig.")
|
||||
option (WSJT_TRACE_UDP "Debugging option that turns on UDP message protocol diagnostics.")
|
||||
option (WSJT_BUILD_UTILS "Build simulators and code demonstrators." ON)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION (WSJT_HAMLIB_VERBOSE_TRACE "Debugging option that turns on full Hamlib internal diagnostics." OFF WSJT_HAMLIB_TRACE OFF)
|
||||
CMAKE_DEPENDENT_OPTION (WSJT_QDEBUG_IN_RELEASE "Leave Qt debugging statements in Release configuration." OFF
|
||||
"NOT is_debug_build" OFF)
|
||||
CMAKE_DEPENDENT_OPTION (WSJT_ENABLE_EXPERIMENTAL_FEATURES "Enable features not fully ready for public releases." ON
|
||||
is_debug_build OFF)
|
||||
CMAKE_DEPENDENT_OPTION (WSJT_CREATE_WINMAIN
|
||||
@ -179,6 +177,7 @@ set (wsjt_qt_CXXSRCS
|
||||
WFPalette.cpp
|
||||
Radio.cpp
|
||||
RadioMetaType.cpp
|
||||
NonInheritingProcess.cpp
|
||||
models/IARURegions.cpp
|
||||
models/Bands.cpp
|
||||
models/Modes.cpp
|
||||
@ -190,7 +189,6 @@ set (wsjt_qt_CXXSRCS
|
||||
item_delegates/ForeignKeyDelegate.cpp
|
||||
validators/LiveFrequencyValidator.cpp
|
||||
GetUserId.cpp
|
||||
TraceFile.cpp
|
||||
Audio/AudioDevice.cpp
|
||||
Transceiver/Transceiver.cpp
|
||||
Transceiver/TransceiverBase.cpp
|
||||
@ -237,6 +235,7 @@ set (wsjt_qt_CXXSRCS
|
||||
logbook/Multiplier.cpp
|
||||
Network/NetworkAccessManager.cpp
|
||||
widgets/LazyFillComboBox.cpp
|
||||
widgets/CheckableItemComboBox.cpp
|
||||
)
|
||||
|
||||
set (wsjt_qtmm_CXXSRCS
|
||||
@ -249,6 +248,7 @@ set (jt9_FSRCS
|
||||
)
|
||||
|
||||
set (wsjtx_CXXSRCS
|
||||
WSJTXLogging.cpp
|
||||
logbook/logbook.cpp
|
||||
Network/PSKReporter.cpp
|
||||
Modulator/Modulator.cpp
|
||||
@ -281,6 +281,7 @@ set (wsjtx_CXXSRCS
|
||||
)
|
||||
|
||||
set (wsjt_CXXSRCS
|
||||
Logger.cpp
|
||||
lib/crc10.cpp
|
||||
lib/crc13.cpp
|
||||
lib/crc14.cpp
|
||||
@ -770,17 +771,10 @@ set_source_files_properties (${WSJTX_ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATI
|
||||
set_source_files_properties (lib/decoder.f90 PROPERTIES COMPILE_FLAGS "-Wno-unused-dummy-argument")
|
||||
set_source_files_properties (lib/filbig.f90 PROPERTIES COMPILE_FLAGS "-Wno-aliasing")
|
||||
|
||||
if (WSJT_QDEBUG_IN_RELEASE)
|
||||
# context info in Qt message handler in release configuration
|
||||
set_property (DIRECTORY APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS $<$<NOT:$<CONFIG:Debug>>:QT_MESSAGELOGCONTEXT>
|
||||
)
|
||||
else (WSJT_QDEBUG_IN_RELEASE)
|
||||
# disable Qt trace and warning messages from release configurations
|
||||
set_property (DIRECTORY APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS $<$<NOT:$<CONFIG:Debug>>:QT_NO_DEBUG_OUTPUT;QT_NO_WARNING_OUTPUT>
|
||||
)
|
||||
endif (WSJT_QDEBUG_IN_RELEASE)
|
||||
## disable Qt trace and warning messages from release configurations
|
||||
#set_property (DIRECTORY APPEND PROPERTY
|
||||
# COMPILE_DEFINITIONS $<$<NOT:$<CONFIG:Debug>>:QT_NO_DEBUG_OUTPUT;QT_NO_WARNING_OUTPUT>
|
||||
# )
|
||||
|
||||
set_property (SOURCE ${all_C_and_CXXSRCS} APPEND_STRING PROPERTY COMPILE_FLAGS " -include wsjtx_config.h")
|
||||
set_property (SOURCE ${all_C_and_CXXSRCS} APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/wsjtx_config.h)
|
||||
@ -824,6 +818,7 @@ endif (APPLE)
|
||||
#
|
||||
# find some useful tools
|
||||
#
|
||||
include (CheckTypeSize)
|
||||
include (CheckCSourceCompiles)
|
||||
include (CheckSymbolExists)
|
||||
include (generate_version_info)
|
||||
@ -851,11 +846,10 @@ endif ()
|
||||
#
|
||||
# Boost
|
||||
#
|
||||
set (Boost_NO_SYSTEM_PATHS TRUE)
|
||||
if (Boost_NO_SYSTEM_PATHS)
|
||||
set (BOOST_ROOT ${PROJECT_SOURCE_DIR}/boost)
|
||||
if (WIN32)
|
||||
set (Boost_USE_STATIC_LIBS OFF)
|
||||
endif ()
|
||||
find_package (Boost 1.63 REQUIRED)
|
||||
find_package (Boost 1.62 REQUIRED COMPONENTS log_setup log)
|
||||
|
||||
#
|
||||
# OpenMP
|
||||
@ -882,7 +876,8 @@ message (STATUS "hamlib_LIBRARY_DIRS: ${hamlib_LIBRARY_DIRS}")
|
||||
|
||||
set (CMAKE_REQUIRED_INCLUDES "${hamlib_INCLUDE_DIRS}")
|
||||
set (CMAKE_REQUIRED_LIBRARIES "${hamlib_LIBRARIES}")
|
||||
check_symbol_exists (CACHE_ALL "hamlib/rig.h" HAVE_HAMLIB_OLD_CACHING)
|
||||
set (CMAKE_EXTRA_INCLUDE_FILES "hamlib/rig.h")
|
||||
check_type_size (CACHE_ALL HAMLIB_OLD_CACHING)
|
||||
check_symbol_exists (rig_set_cache_timeout_ms "hamlib/rig.h" HAVE_HAMLIB_CACHING)
|
||||
|
||||
|
||||
@ -1069,7 +1064,7 @@ query_qmake (QT_HOST_DATA QT_DATA_DIR)
|
||||
set (QT_MKSPECS_DIR ${QT_DATA_DIR}/mkspecs)
|
||||
|
||||
# project definitions
|
||||
add_definitions (-DQT5 -DCMAKE_BUILD -DBIGSYM=1)
|
||||
add_definitions (-DQT5 -DCMAKE_BUILD -DBIGSYM=1 -DBOOST_ALL_DYN_LINK)
|
||||
if (CMAKE_HOST_UNIX)
|
||||
add_definitions (-DUNIX)
|
||||
elseif (CMAKE_HOST_WIN32)
|
||||
@ -1078,7 +1073,7 @@ endif ()
|
||||
|
||||
# build a library of package functionality (without and optionally with OpenMP support)
|
||||
add_library (wsjt_cxx STATIC ${wsjt_CSRCS} ${wsjt_CXXSRCS})
|
||||
target_link_libraries (wsjt_cxx ${LIBM_LIBRARIES})
|
||||
target_link_libraries (wsjt_cxx ${LIBM_LIBRARIES} Boost::log_setup ${LIBM_LIBRARIES})
|
||||
|
||||
# build an OpenMP variant of the Fortran library routines
|
||||
add_library (wsjt_fort STATIC ${wsjt_FSRCS})
|
||||
@ -1187,6 +1182,11 @@ target_link_libraries (ft4sim_mult wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (fst4sim lib/fst4/fst4sim.f90)
|
||||
target_link_libraries (fst4sim wsjt_fort wsjt_cxx)
|
||||
if (WIN32)
|
||||
set_target_properties (fst4sim PROPERTIES
|
||||
LINK_FLAGS -Wl,--stack,0x4000000,--heap,0x6000000
|
||||
)
|
||||
endif ()
|
||||
|
||||
add_executable (ldpcsim240_101 lib/fst4/ldpcsim240_101.f90)
|
||||
target_link_libraries (ldpcsim240_101 wsjt_fort wsjt_cxx)
|
||||
@ -1282,11 +1282,6 @@ else ()
|
||||
endif ()
|
||||
add_custom_target (translations DEPENDS ${QM_FILES})
|
||||
set_property (DIRECTORY PROPERTY CLEAN_NO_CUSTOM TRUE)
|
||||
# do this after i18n to stop lupdate walking the boost tree which it
|
||||
# chokes on
|
||||
if (Boost_FOUND)
|
||||
include_directories (${Boost_INCLUDE_DIRS})
|
||||
endif ()
|
||||
|
||||
# embedded resources
|
||||
function (add_resources resources path)
|
||||
@ -1329,9 +1324,6 @@ endif (WIN32)
|
||||
# targets dependent on Qt
|
||||
#
|
||||
|
||||
add_executable (record_time_signal Audio/tools/record_time_signal.cpp)
|
||||
target_link_libraries (record_time_signal wsjt_cxx wsjt_qtmm wsjt_qt)
|
||||
|
||||
# build a library for the QCustomPlot widget
|
||||
add_library (qcp STATIC ${qcp_CXXSRCS})
|
||||
target_include_directories (qcp PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/qcustomplot-source>)
|
||||
@ -1341,7 +1333,7 @@ target_link_libraries (qcp Qt5::Widgets Qt5::PrintSupport)
|
||||
add_library (wsjt_qt STATIC ${wsjt_qt_CXXSRCS} ${wsjt_qt_GENUISRCS} ${GENAXSRCS})
|
||||
# set wsjtx_udp exports to static variants
|
||||
target_compile_definitions (wsjt_qt PUBLIC UDP_STATIC_DEFINE)
|
||||
target_link_libraries (wsjt_qt qcp Qt5::Widgets Qt5::Network Qt5::Sql)
|
||||
target_link_libraries (wsjt_qt Boost::log qcp Qt5::Widgets Qt5::Network Qt5::Sql)
|
||||
target_include_directories (wsjt_qt BEFORE PRIVATE ${hamlib_INCLUDE_DIRS})
|
||||
if (WIN32)
|
||||
target_link_libraries (wsjt_qt Qt5::AxContainer Qt5::AxBase)
|
||||
@ -1360,9 +1352,12 @@ generate_version_info (jt9_VERSION_RESOURCES
|
||||
NAME jt9
|
||||
BUNDLE ${PROJECT_BUNDLE_NAME}
|
||||
ICON ${WSJTX_ICON_FILE}
|
||||
FILE_DESCRIPTION "Slow mode decoder"
|
||||
FILE_DESCRIPTION "jt9 - WSJT-X slow mode decoder"
|
||||
)
|
||||
|
||||
add_executable (record_time_signal Audio/tools/record_time_signal.cpp)
|
||||
target_link_libraries (record_time_signal wsjt_cxx wsjt_qtmm wsjt_qt)
|
||||
|
||||
add_executable (jt9 ${jt9_FSRCS} ${jt9_VERSION_RESOURCES})
|
||||
if (${OPENMP_FOUND} OR APPLE)
|
||||
if (APPLE)
|
||||
@ -1449,7 +1444,7 @@ else ()
|
||||
)
|
||||
if (WIN32)
|
||||
set_target_properties (wsjtx PROPERTIES
|
||||
LINK_FLAGS -Wl,--stack,28000000
|
||||
LINK_FLAGS -Wl,--stack,0x1000000,--heap,0x20000000
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
@ -1485,6 +1480,15 @@ generate_version_info (udp_daemon_VERSION_RESOURCES
|
||||
add_executable (udp_daemon UDPExamples/UDPDaemon.cpp ${udp_daemon_VERSION_RESOURCES})
|
||||
target_link_libraries (udp_daemon wsjtx_udp-static)
|
||||
|
||||
generate_version_info (wsjtx_app_version_VERSION_RESOURCES
|
||||
NAME wsjtx_app_version
|
||||
BUNDLE ${PROJECT_BUNDLE_NAME}
|
||||
ICON ${WSJTX_ICON_FILE}
|
||||
FILE_DESCRIPTION "Display WSJT-X Application Version on console"
|
||||
)
|
||||
add_executable (wsjtx_app_version AppVersion/AppVersion.cpp ${wsjtx_app_version_VERSION_RESOURCES})
|
||||
target_link_libraries (wsjtx_app_version wsjt_qt)
|
||||
|
||||
generate_version_info (message_aggregator_VERSION_RESOURCES
|
||||
NAME message_aggregator
|
||||
BUNDLE ${PROJECT_BUNDLE_NAME}
|
||||
@ -1502,7 +1506,7 @@ add_executable (message_aggregator
|
||||
${message_aggregator_RESOURCES_RCC}
|
||||
${message_aggregator_VERSION_RESOURCES}
|
||||
)
|
||||
target_link_libraries (message_aggregator Qt5::Widgets wsjtx_udp-static)
|
||||
target_link_libraries (message_aggregator wsjt_qt Qt5::Widgets wsjtx_udp-static)
|
||||
|
||||
if (WSJT_CREATE_WINMAIN)
|
||||
set_target_properties (message_aggregator PROPERTIES WIN32_EXECUTABLE ON)
|
||||
@ -1544,7 +1548,7 @@ install (TARGETS wsjtx
|
||||
# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wsjtx
|
||||
# )
|
||||
|
||||
install (TARGETS udp_daemon message_aggregator
|
||||
install (TARGETS udp_daemon message_aggregator wsjtx_app_version
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
)
|
||||
@ -1601,6 +1605,13 @@ install (FILES
|
||||
#COMPONENT runtime
|
||||
)
|
||||
|
||||
install (DIRECTORY
|
||||
example_log_configurations
|
||||
DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
FILES_MATCHING REGEX "^.*[^~]$"
|
||||
#COMPONENT runtime
|
||||
)
|
||||
|
||||
#
|
||||
# Mac installer files
|
||||
#
|
||||
@ -1846,7 +1857,7 @@ set (CPACK_MONOLITHIC_INSTALL 1)
|
||||
set (CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
|
||||
set (CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||
set (CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
||||
set (CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
|
||||
set (CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}${BUILD_TYPE_REVISION}")
|
||||
|
||||
if (WIN32)
|
||||
set (CPACK_GENERATOR "NSIS")
|
||||
@ -1880,11 +1891,11 @@ else ()
|
||||
endif ()
|
||||
|
||||
set (CPACK_DEBIAN_PACKAGE_HOMEPAGE "${PROJECT_HOMEPAGE}")
|
||||
set (CPACK_DEBIAN_PACKAGE_DEPENDS "libgfortran5 (>=8.3) | libgfortran4 (>=7.3) | libgfortran3 (>=6.3), libfftw3-single3 (>=3.3), libgomp1 (>=6), libqt5serialport5 (>=5.7), libqt5multimedia5-plugins (>=5.7), libqt5widgets5 (>=5.7), libqt5network5 (>=5.7), libqt5printsupport5 (>=5.7), libqt5sql5-sqlite (>=5.7), libusb-1.0-0 (>=1.0.21), libboost-log1.65.1 (>=1.62.0) | libboost-log1.65.1 (>=1.65.1) | libboost-log1.67.0 (>=1.67.0) | libboost-log1.71.0 (>=1.71.0)")
|
||||
set (CPACK_DEBIAN_PACKAGE_DEPENDS "libgfortran5 (>=8.3) | libgfortran4 (>=7.3) | libgfortran3 (>=6.3), libfftw3-single3 (>=3.3), libgomp1 (>=6), libqt5serialport5 (>=5.7), libqt5multimedia5-plugins (>=5.7), libqt5widgets5 (>=5.7), libqt5network5 (>=5.7), libqt5printsupport5 (>=5.7), libqt5sql5-sqlite (>=5.7), libusb-1.0-0 (>=1.0.21), libboost-log1.62.0 (>=1.62.0) | libboost-log1.65.1 (>=1.65.1) | libboost-log1.67.0 (>=1.67.0) | libboost-log1.71.0 (>=1.71.0) | libboost-log1.74.0 (>=1.74.0)")
|
||||
set (CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||
|
||||
set (CPACK_RPM_PACKAGE_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
|
||||
set (CPACK_RPM_PACKAGE_REQUIRES "qt5-qtbase >= 5.9, qt5-qtserialport >= 5.9, qt5-qtmultimedia >= 5.9, qt5-qtsvg >= 5.9, libusbx >= 1.0.22, libgfortran >= 7, libgomp >= 7, fftw-libs-single >= 3.3")
|
||||
set (CPACK_RPM_PACKAGE_REQUIRES "qt5-qtbase >= 5.9, qt5-qtserialport >= 5.9, qt5-qtmultimedia >= 5.9, qt5-qtsvg >= 5.9, libusbx >= 1.0.22, libgfortran >= 7, libgomp >= 7, fftw-libs-single >= 3.3, boost-log >= 1.62")
|
||||
set (CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/share/pixmaps /usr/share/applications /usr/share/man /usr/share/man1)
|
||||
|
||||
configure_file ("${PROJECT_SOURCE_DIR}/CMakeCPackOptions.cmake.in"
|
||||
|
||||
@ -163,9 +163,14 @@
|
||||
#include <QFontDialog>
|
||||
#include <QSerialPortInfo>
|
||||
#include <QScopedPointer>
|
||||
#include <QNetworkInterface>
|
||||
#include <QHostInfo>
|
||||
#include <QHostAddress>
|
||||
#include <QStandardItem>
|
||||
#include <QDebug>
|
||||
|
||||
#include "pimpl_impl.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "qt_helpers.hpp"
|
||||
#include "MetaDataRegistry.hpp"
|
||||
#include "SettingsGroup.hpp"
|
||||
@ -439,6 +444,12 @@ private:
|
||||
void load_audio_devices (QAudio::Mode, QComboBox *, QAudioDeviceInfo *);
|
||||
void update_audio_channels (QComboBox const *, int, QComboBox *, bool);
|
||||
|
||||
void load_network_interfaces (CheckableItemComboBox *, QStringList current);
|
||||
Q_SLOT void validate_network_interfaces (QString const&);
|
||||
QStringList get_selected_network_interfaces (CheckableItemComboBox *);
|
||||
Q_SLOT void host_info_results (QHostInfo);
|
||||
void check_multicast (QHostAddress const&);
|
||||
|
||||
void find_tab (QWidget *);
|
||||
|
||||
void initialize_models ();
|
||||
@ -492,6 +503,8 @@ private:
|
||||
Q_SLOT void on_add_macro_line_edit_editingFinished ();
|
||||
Q_SLOT void delete_macro ();
|
||||
void delete_selected_macros (QModelIndexList);
|
||||
Q_SLOT void on_udp_server_line_edit_textChanged (QString const&);
|
||||
Q_SLOT void on_udp_server_line_edit_editingFinished ();
|
||||
Q_SLOT void on_save_path_select_push_button_clicked (bool);
|
||||
Q_SLOT void on_azel_path_select_push_button_clicked (bool);
|
||||
Q_SLOT void on_calibration_intercept_spin_box_valueChanged (double);
|
||||
@ -641,7 +654,12 @@ private:
|
||||
bool use_dynamic_grid_;
|
||||
QString opCall_;
|
||||
QString udp_server_name_;
|
||||
bool udp_server_name_edited_;
|
||||
int dns_lookup_id_;
|
||||
port_type udp_server_port_;
|
||||
QStringList udp_interface_names_;
|
||||
QString loopback_interface_name_;
|
||||
int udp_TTL_;
|
||||
QString n1mm_server_name_;
|
||||
port_type n1mm_server_port_;
|
||||
bool broadcast_to_n1mm_;
|
||||
@ -741,6 +759,8 @@ QString Configuration::opCall() const {return m_->opCall_;}
|
||||
void Configuration::opCall (QString const& call) {m_->opCall_ = call;}
|
||||
QString Configuration::udp_server_name () const {return m_->udp_server_name_;}
|
||||
auto Configuration::udp_server_port () const -> port_type {return m_->udp_server_port_;}
|
||||
QStringList Configuration::udp_interface_names () const {return m_->udp_interface_names_;}
|
||||
int Configuration::udp_TTL () const {return m_->udp_TTL_;}
|
||||
bool Configuration::accept_udp_requests () const {return m_->accept_udp_requests_;}
|
||||
QString Configuration::n1mm_server_name () const {return m_->n1mm_server_name_;}
|
||||
auto Configuration::n1mm_server_port () const -> port_type {return m_->n1mm_server_port_;}
|
||||
@ -792,10 +812,7 @@ bool Configuration::is_dummy_rig () const
|
||||
|
||||
bool Configuration::transceiver_online ()
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "Configuration::transceiver_online: " << m_->cached_rig_state_;
|
||||
#endif
|
||||
|
||||
LOG_TRACE (m_->cached_rig_state_);
|
||||
return m_->have_rig ();
|
||||
}
|
||||
|
||||
@ -806,54 +823,37 @@ int Configuration::transceiver_resolution () const
|
||||
|
||||
void Configuration::transceiver_offline ()
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "Configuration::transceiver_offline:" << m_->cached_rig_state_;
|
||||
#endif
|
||||
|
||||
LOG_TRACE (m_->cached_rig_state_);
|
||||
m_->close_rig ();
|
||||
}
|
||||
|
||||
void Configuration::transceiver_frequency (Frequency f)
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "Configuration::transceiver_frequency:" << f << m_->cached_rig_state_;
|
||||
#endif
|
||||
LOG_TRACE (f << ' ' << m_->cached_rig_state_);
|
||||
m_->transceiver_frequency (f);
|
||||
}
|
||||
|
||||
void Configuration::transceiver_tx_frequency (Frequency f)
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "Configuration::transceiver_tx_frequency:" << f << m_->cached_rig_state_;
|
||||
#endif
|
||||
|
||||
LOG_TRACE (f << ' ' << m_->cached_rig_state_);
|
||||
m_->transceiver_tx_frequency (f);
|
||||
}
|
||||
|
||||
void Configuration::transceiver_mode (MODE mode)
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "Configuration::transceiver_mode:" << mode << m_->cached_rig_state_;
|
||||
#endif
|
||||
|
||||
LOG_TRACE (mode << ' ' << m_->cached_rig_state_);
|
||||
m_->transceiver_mode (mode);
|
||||
}
|
||||
|
||||
void Configuration::transceiver_ptt (bool on)
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "Configuration::transceiver_ptt:" << on << m_->cached_rig_state_;
|
||||
#endif
|
||||
|
||||
LOG_TRACE (on << ' ' << m_->cached_rig_state_);
|
||||
m_->transceiver_ptt (on);
|
||||
}
|
||||
|
||||
void Configuration::sync_transceiver (bool force_signal, bool enforce_mode_and_split)
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "Configuration::sync_transceiver: force signal:" << force_signal << "enforce_mode_and_split:" << enforce_mode_and_split << m_->cached_rig_state_;
|
||||
#endif
|
||||
|
||||
LOG_TRACE ("force signal: " << force_signal << " enforce_mode_and_split: " << enforce_mode_and_split << ' ' << m_->cached_rig_state_);
|
||||
m_->sync_transceiver (force_signal);
|
||||
if (!enforce_mode_and_split)
|
||||
{
|
||||
@ -995,6 +995,8 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
|
||||
, transceiver_command_number_ {0}
|
||||
, degrade_ {0.} // initialize to zero each run, not
|
||||
// saved in settings
|
||||
, udp_server_name_edited_ {false}
|
||||
, dns_lookup_id_ {-1}
|
||||
{
|
||||
ui_->setupUi (this);
|
||||
|
||||
@ -1044,6 +1046,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
|
||||
// this must be done after the default paths above are set
|
||||
read_settings ();
|
||||
|
||||
// set up dynamic loading of audio devices
|
||||
connect (ui_->sound_input_combo_box, &LazyFillComboBox::about_to_show_popup, [this] () {
|
||||
QGuiApplication::setOverrideCursor (QCursor {Qt::WaitCursor});
|
||||
load_audio_devices (QAudio::AudioInput, ui_->sound_input_combo_box, &next_audio_input_device_);
|
||||
@ -1059,29 +1062,29 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
|
||||
QGuiApplication::restoreOverrideCursor ();
|
||||
});
|
||||
|
||||
// set up dynamic loading of network interfaces
|
||||
connect (ui_->udp_interfaces_combo_box, &LazyFillComboBox::about_to_show_popup, [this] () {
|
||||
QGuiApplication::setOverrideCursor (QCursor {Qt::WaitCursor});
|
||||
load_network_interfaces (ui_->udp_interfaces_combo_box, udp_interface_names_);
|
||||
QGuiApplication::restoreOverrideCursor ();
|
||||
});
|
||||
connect (ui_->udp_interfaces_combo_box, &QComboBox::currentTextChanged, this, &Configuration::impl::validate_network_interfaces);
|
||||
|
||||
// set up LoTW users CSV file fetching
|
||||
connect (&lotw_users_, &LotWUsers::load_finished, [this] () {
|
||||
ui_->LotW_CSV_fetch_push_button->setEnabled (true);
|
||||
});
|
||||
lotw_users_.set_local_file_path (writeable_data_dir_.absoluteFilePath ("lotw-user-activity.csv"));
|
||||
|
||||
// load the dictionary if it exists
|
||||
lotw_users_.load (ui_->LotW_CSV_URL_line_edit->text (), false);
|
||||
|
||||
//
|
||||
// validation
|
||||
//
|
||||
ui_->callsign_line_edit->setValidator (new CallsignValidator {this});
|
||||
ui_->grid_line_edit->setValidator (new MaidenheadLocatorValidator {this});
|
||||
ui_->add_macro_line_edit->setValidator (new QRegularExpressionValidator {message_alphabet, this});
|
||||
ui_->Field_Day_Exchange->setValidator (new QRegularExpressionValidator {field_day_exchange_re, this});
|
||||
ui_->RTTY_Exchange->setValidator (new QRegularExpressionValidator {RTTY_roundup_exchange_re, this});
|
||||
|
||||
ui_->udp_server_port_spin_box->setMinimum (1);
|
||||
ui_->udp_server_port_spin_box->setMaximum (std::numeric_limits<port_type>::max ());
|
||||
|
||||
ui_->n1mm_server_port_spin_box->setMinimum (1);
|
||||
ui_->n1mm_server_port_spin_box->setMaximum (std::numeric_limits<port_type>::max ());
|
||||
|
||||
//
|
||||
// assign ids to radio buttons
|
||||
//
|
||||
@ -1233,6 +1236,19 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
|
||||
audio_output_device_ = next_audio_output_device_;
|
||||
audio_output_channel_ = next_audio_output_channel_;
|
||||
|
||||
bool fetch_if_needed {false};
|
||||
for (auto const& item : decode_highlighing_model_.items ())
|
||||
{
|
||||
if (DecodeHighlightingModel::Highlight::LotW == item.type_)
|
||||
{
|
||||
fetch_if_needed = item.enabled_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// load the LoTW users dictionary if it exists, fetch and load if it
|
||||
// doesn't and we need it
|
||||
lotw_users_.load (ui_->LotW_CSV_URL_line_edit->text (), fetch_if_needed);
|
||||
|
||||
transceiver_thread_ = new QThread {this};
|
||||
transceiver_thread_->start ();
|
||||
}
|
||||
@ -1340,7 +1356,14 @@ void Configuration::impl::initialize_models ()
|
||||
ui_->CAT_poll_interval_spin_box->setValue (rig_params_.poll_interval);
|
||||
ui_->opCallEntry->setText (opCall_);
|
||||
ui_->udp_server_line_edit->setText (udp_server_name_);
|
||||
on_udp_server_line_edit_editingFinished ();
|
||||
ui_->udp_server_port_spin_box->setValue (udp_server_port_);
|
||||
load_network_interfaces (ui_->udp_interfaces_combo_box, udp_interface_names_);
|
||||
if (!udp_interface_names_.size ())
|
||||
{
|
||||
udp_interface_names_ = get_selected_network_interfaces (ui_->udp_interfaces_combo_box);
|
||||
}
|
||||
ui_->udp_TTL_spin_box->setValue (udp_TTL_);
|
||||
ui_->accept_udp_requests_check_box->setChecked (accept_udp_requests_);
|
||||
ui_->n1mm_server_name_line_edit->setText (n1mm_server_name_);
|
||||
ui_->n1mm_server_port_spin_box->setValue (n1mm_server_port_);
|
||||
@ -1518,6 +1541,8 @@ void Configuration::impl::read_settings ()
|
||||
rig_params_.split_mode = settings_->value ("SplitMode", QVariant::fromValue (TransceiverFactory::split_mode_none)).value<TransceiverFactory::SplitMode> ();
|
||||
opCall_ = settings_->value ("OpCall", "").toString ();
|
||||
udp_server_name_ = settings_->value ("UDPServer", "127.0.0.1").toString ();
|
||||
udp_interface_names_ = settings_->value ("UDPInterface").toStringList ();
|
||||
udp_TTL_ = settings_->value ("UDPTTL", 1).toInt ();
|
||||
udp_server_port_ = settings_->value ("UDPServerPort", 2237).toUInt ();
|
||||
n1mm_server_name_ = settings_->value ("N1MMServer", "127.0.0.1").toString ();
|
||||
n1mm_server_port_ = settings_->value ("N1MMServerPort", 2333).toUInt ();
|
||||
@ -1646,6 +1671,8 @@ void Configuration::impl::write_settings ()
|
||||
settings_->setValue ("OpCall", opCall_);
|
||||
settings_->setValue ("UDPServer", udp_server_name_);
|
||||
settings_->setValue ("UDPServerPort", udp_server_port_);
|
||||
settings_->setValue ("UDPInterface", QVariant::fromValue (udp_interface_names_));
|
||||
settings_->setValue ("UDPTTL", udp_TTL_);
|
||||
settings_->setValue ("N1MMServer", n1mm_server_name_);
|
||||
settings_->setValue ("N1MMServerPort", n1mm_server_port_);
|
||||
settings_->setValue ("BroadcastToN1MM", broadcast_to_n1mm_);
|
||||
@ -1848,6 +1875,12 @@ bool Configuration::impl::validate ()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dns_lookup_id_ > -1)
|
||||
{
|
||||
MessageBox::information_message (this, tr ("Pending DNS lookup, please try again later"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2066,20 +2099,30 @@ void Configuration::impl::accept ()
|
||||
pwrBandTxMemory_ = ui_->checkBoxPwrBandTxMemory->isChecked ();
|
||||
pwrBandTuneMemory_ = ui_->checkBoxPwrBandTuneMemory->isChecked ();
|
||||
opCall_=ui_->opCallEntry->text();
|
||||
auto new_server = ui_->udp_server_line_edit->text ();
|
||||
if (new_server != udp_server_name_)
|
||||
|
||||
auto new_server = ui_->udp_server_line_edit->text ().trimmed ();
|
||||
auto new_interfaces = get_selected_network_interfaces (ui_->udp_interfaces_combo_box);
|
||||
if (new_server != udp_server_name_ || new_interfaces != udp_interface_names_)
|
||||
{
|
||||
udp_server_name_ = new_server;
|
||||
Q_EMIT self_->udp_server_changed (new_server);
|
||||
udp_interface_names_ = new_interfaces;
|
||||
Q_EMIT self_->udp_server_changed (udp_server_name_, udp_interface_names_);
|
||||
}
|
||||
|
||||
auto new_port = ui_->udp_server_port_spin_box->value ();
|
||||
if (new_port != udp_server_port_)
|
||||
{
|
||||
udp_server_port_ = new_port;
|
||||
Q_EMIT self_->udp_server_port_changed (new_port);
|
||||
Q_EMIT self_->udp_server_port_changed (udp_server_port_);
|
||||
}
|
||||
|
||||
|
||||
auto new_TTL = ui_->udp_TTL_spin_box->value ();
|
||||
if (new_TTL != udp_TTL_)
|
||||
{
|
||||
udp_TTL_ = new_TTL;
|
||||
Q_EMIT self_->udp_TTL_changed (udp_TTL_);
|
||||
}
|
||||
|
||||
if (ui_->accept_udp_requests_check_box->isChecked () != accept_udp_requests_)
|
||||
{
|
||||
accept_udp_requests_ = ui_->accept_udp_requests_check_box->isChecked ();
|
||||
@ -2135,6 +2178,12 @@ void Configuration::impl::accept ()
|
||||
|
||||
void Configuration::impl::reject ()
|
||||
{
|
||||
if (dns_lookup_id_ > -1)
|
||||
{
|
||||
QHostInfo::abortHostLookup (dns_lookup_id_);
|
||||
dns_lookup_id_ = -1;
|
||||
}
|
||||
|
||||
initialize_models (); // reverts to settings as at exec ()
|
||||
|
||||
// check if the Transceiver instance changed, in which case we need
|
||||
@ -2349,6 +2398,72 @@ void Configuration::impl::on_add_macro_push_button_clicked (bool /* checked */)
|
||||
}
|
||||
}
|
||||
|
||||
void Configuration::impl::on_udp_server_line_edit_textChanged (QString const&)
|
||||
{
|
||||
udp_server_name_edited_ = true;
|
||||
}
|
||||
|
||||
void Configuration::impl::on_udp_server_line_edit_editingFinished ()
|
||||
{
|
||||
if (udp_server_name_edited_)
|
||||
{
|
||||
auto const& server = ui_->udp_server_line_edit->text ().trimmed ();
|
||||
QHostAddress ha {server};
|
||||
if (server.size () && ha.isNull ())
|
||||
{
|
||||
// queue a host address lookup
|
||||
// qDebug () << "server host DNS lookup:" << server;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
|
||||
dns_lookup_id_ = QHostInfo::lookupHost (server, this, &Configuration::impl::host_info_results);
|
||||
#else
|
||||
dns_lookup_id_ = QHostInfo::lookupHost (server, this, SLOT (host_info_results (QHostInfo)));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
check_multicast (ha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Configuration::impl::host_info_results (QHostInfo host_info)
|
||||
{
|
||||
if (host_info.lookupId () != dns_lookup_id_) return;
|
||||
dns_lookup_id_ = -1;
|
||||
if (QHostInfo::NoError != host_info.error ())
|
||||
{
|
||||
MessageBox::critical_message (this, tr ("UDP server DNS lookup failed"), host_info.errorString ());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const& server_addresses = host_info.addresses ();
|
||||
// qDebug () << "message server addresses:" << server_addresses;
|
||||
if (server_addresses.size ())
|
||||
{
|
||||
check_multicast (server_addresses[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Configuration::impl::check_multicast (QHostAddress const& ha)
|
||||
{
|
||||
auto is_multicast = is_multicast_address (ha);
|
||||
ui_->udp_interfaces_label->setVisible (is_multicast);
|
||||
ui_->udp_interfaces_combo_box->setVisible (is_multicast);
|
||||
ui_->udp_TTL_label->setVisible (is_multicast);
|
||||
ui_->udp_TTL_spin_box->setVisible (is_multicast);
|
||||
if (isVisible ())
|
||||
{
|
||||
if (is_MAC_ambiguous_multicast_address (ha))
|
||||
{
|
||||
MessageBox::warning_message (this, tr ("MAC-ambiguous multicast groups addresses not supported"));
|
||||
find_tab (ui_->udp_server_line_edit);
|
||||
ui_->udp_server_line_edit->clear ();
|
||||
}
|
||||
}
|
||||
udp_server_name_edited_ = false;
|
||||
}
|
||||
|
||||
void Configuration::impl::delete_frequencies ()
|
||||
{
|
||||
auto selection_model = ui_->frequencies_table_view->selectionModel ();
|
||||
@ -2723,9 +2838,7 @@ void Configuration::impl::sync_transceiver (bool /*force_signal*/)
|
||||
void Configuration::impl::handle_transceiver_update (TransceiverState const& state,
|
||||
unsigned sequence_number)
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "Configuration::handle_transceiver_update: Transceiver State #:" << sequence_number << state;
|
||||
#endif
|
||||
LOG_TRACE ("#: " << sequence_number << ' ' << state);
|
||||
|
||||
// only follow rig on some information, ignore other stuff
|
||||
cached_rig_state_.online (state.online ());
|
||||
@ -2773,10 +2886,7 @@ void Configuration::impl::handle_transceiver_update (TransceiverState const& sta
|
||||
|
||||
void Configuration::impl::handle_transceiver_failure (QString const& reason)
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "Configuration::handle_transceiver_failure: reason:" << reason;
|
||||
#endif
|
||||
|
||||
LOG_ERROR ("handle_transceiver_failure: reason: " << reason);
|
||||
close_rig ();
|
||||
ui_->test_PTT_push_button->setChecked (false);
|
||||
|
||||
@ -2873,6 +2983,85 @@ void Configuration::impl::load_audio_devices (QAudio::Mode mode, QComboBox * com
|
||||
combo_box->setCurrentIndex (current_index);
|
||||
}
|
||||
|
||||
// load the available network interfaces into the selection combo box
|
||||
void Configuration::impl::load_network_interfaces (CheckableItemComboBox * combo_box, QStringList current)
|
||||
{
|
||||
combo_box->clear ();
|
||||
for (auto const& net_if : QNetworkInterface::allInterfaces ())
|
||||
{
|
||||
auto flags = QNetworkInterface::IsUp | QNetworkInterface::CanMulticast;
|
||||
if ((net_if.flags () & flags) == flags)
|
||||
{
|
||||
if (net_if.flags () & QNetworkInterface::IsLoopBack)
|
||||
{
|
||||
loopback_interface_name_ = net_if.name ();
|
||||
}
|
||||
auto item = combo_box->addCheckItem (net_if.humanReadableName ()
|
||||
, net_if.name ()
|
||||
, current.contains (net_if.name ()) ? Qt::Checked : Qt::Unchecked);
|
||||
auto tip = QString {"name(index): %1(%2) - %3"}.arg (net_if.name ()).arg (net_if.index ())
|
||||
.arg (net_if.flags () & QNetworkInterface::IsUp ? "Up" : "Down");
|
||||
auto hw_addr = net_if.hardwareAddress ();
|
||||
if (hw_addr.size ())
|
||||
{
|
||||
tip += QString {"\nhw: %1"}.arg (net_if.hardwareAddress ());
|
||||
}
|
||||
auto aes = net_if.addressEntries ();
|
||||
if (aes.size ())
|
||||
{
|
||||
tip += "\naddresses:";
|
||||
for (auto const& ae : aes)
|
||||
{
|
||||
tip += QString {"\n ip: %1/%2"}.arg (ae.ip ().toString ()).arg (ae.prefixLength ());
|
||||
}
|
||||
}
|
||||
item->setToolTip (tip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get the select network interfaces from the selection combo box
|
||||
void Configuration::impl::validate_network_interfaces (QString const& /*text*/)
|
||||
{
|
||||
auto model = static_cast<QStandardItemModel *> (ui_->udp_interfaces_combo_box->model ());
|
||||
bool has_checked {false};
|
||||
int loopback_row {-1};
|
||||
for (int row = 0; row < model->rowCount (); ++row)
|
||||
{
|
||||
if (model->item (row)->data ().toString () == loopback_interface_name_)
|
||||
{
|
||||
loopback_row = row;
|
||||
}
|
||||
else if (Qt::Checked == model->item (row)->checkState ())
|
||||
{
|
||||
has_checked = true;
|
||||
}
|
||||
}
|
||||
if (loopback_row >= 0)
|
||||
{
|
||||
if (!has_checked)
|
||||
{
|
||||
model->item (loopback_row)->setCheckState (Qt::Checked);
|
||||
}
|
||||
model->item (loopback_row)->setEnabled (has_checked);
|
||||
}
|
||||
}
|
||||
|
||||
// get the select network interfaces from the selection combo box
|
||||
QStringList Configuration::impl::get_selected_network_interfaces (CheckableItemComboBox * combo_box)
|
||||
{
|
||||
QStringList interfaces;
|
||||
auto model = static_cast<QStandardItemModel *> (combo_box->model ());
|
||||
for (int row = 0; row < model->rowCount (); ++row)
|
||||
{
|
||||
if (Qt::Checked == model->item (row)->checkState ())
|
||||
{
|
||||
interfaces << model->item (row)->data ().toString ();
|
||||
}
|
||||
}
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
// enable only the channels that are supported by the selected audio device
|
||||
void Configuration::impl::update_audio_channels (QComboBox const * source_combo_box, int index, QComboBox * combo_box, bool allow_both)
|
||||
{
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QFont>
|
||||
#include <QString>
|
||||
|
||||
#include "Radio.hpp"
|
||||
#include "models/IARURegions.hpp"
|
||||
@ -14,14 +15,12 @@
|
||||
class QSettings;
|
||||
class QWidget;
|
||||
class QAudioDeviceInfo;
|
||||
class QString;
|
||||
class QDir;
|
||||
class QNetworkAccessManager;
|
||||
class Bands;
|
||||
class FrequencyList_v2;
|
||||
class StationList;
|
||||
class QStringListModel;
|
||||
class QHostAddress;
|
||||
class LotWUsers;
|
||||
class DecodeHighlightingModel;
|
||||
class LogBook;
|
||||
@ -152,6 +151,8 @@ public:
|
||||
void opCall (QString const&);
|
||||
QString udp_server_name () const;
|
||||
port_type udp_server_port () const;
|
||||
QStringList udp_interface_names () const;
|
||||
int udp_TTL () const;
|
||||
QString n1mm_server_name () const;
|
||||
port_type n1mm_server_port () const;
|
||||
bool valid_n1mm_info () const;
|
||||
@ -273,8 +274,9 @@ public:
|
||||
//
|
||||
// This signal is emitted when the UDP server changes
|
||||
//
|
||||
Q_SIGNAL void udp_server_changed (QString const& udp_server) const;
|
||||
Q_SIGNAL void udp_server_changed (QString& udp_server_name, QStringList const& network_interfaces) const;
|
||||
Q_SIGNAL void udp_server_port_changed (port_type server_port) const;
|
||||
Q_SIGNAL void udp_TTL_changed (int TTL) const;
|
||||
Q_SIGNAL void accept_udp_requests_changed (bool checked) const;
|
||||
|
||||
// signal updates to decode highlighting
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>554</width>
|
||||
<height>556</height>
|
||||
<height>560</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -1864,12 +1864,6 @@ and DX Grid fields when a 73 or free text message is sent.</string>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="udp_server_line_edit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Optional hostname of network service to receive decodes.</p><p>Formats:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 multicast group address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 multicast group address</li></ul><p>Clearing this field will disable the broadcasting of UDP status updates.</p></body></html></string>
|
||||
</property>
|
||||
@ -1891,16 +1885,53 @@ and DX Grid fields when a 73 or free text message is sent.</string>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="udp_server_port_spin_box">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Enter the service port number of the UDP server that WSJT-X should send updates to. If this is zero no updates will be broadcast.</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
<string><html><head/><body><p>Enter the service port number of the UDP server that WSJT-X should send updates to. If this is zero no updates will be sent.</p></body></html></string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65534</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="udp_interfaces_label">
|
||||
<property name="text">
|
||||
<string>Outgoing interfaces:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>udp_interfaces_combo_box</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="CheckableItemComboBox" name="udp_interfaces_combo_box">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>When sending updates to a multicast group address it is necessary to specify which network interface(s) to send them to. If the loop-back interface is multicast capable then at least that one will be selected.</p><p>For most users the loop-back interface is all that is needed, that will allow multiple other applications on the same machine to interoperate with WSJT-X. If applications running on other hosts are to receive status updates then a suitable network interface should be used.</p><p>On some Linux systems it may be necessary to enable multicast on the loop-back network interface.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="udp_TTL_spin_box">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Sets the number or router hops that multicast datagrams are allowed to make. Almost everyone should set this to 1 to keep outgoing multicast traffic withn the local subnet.</p></body></html></string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="udp_TTL_label">
|
||||
<property name="text">
|
||||
<string>Multicast TTL:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>udp_TTL_spin_box</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
@ -1988,6 +2019,9 @@ and DX Grid fields when a 73 or free text message is sent.</string>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Enter the port number that WSJT-X should use for UDP broadcasts of ADIF log information. For N1MM Logger+, this value should be 2333. If this is zero, no updates will be broadcast.</p></body></html></string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65534</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -3002,6 +3036,11 @@ Right click for insert and delete options.</string>
|
||||
<extends>QComboBox</extends>
|
||||
<header>widgets/LazyFillComboBox.hpp</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CheckableItemComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>widgets/CheckableItemComboBox.hpp</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>configuration_tabs</tabstop>
|
||||
@ -3084,6 +3123,8 @@ Right click for insert and delete options.</string>
|
||||
<tabstop>psk_reporter_tcpip_check_box</tabstop>
|
||||
<tabstop>udp_server_line_edit</tabstop>
|
||||
<tabstop>udp_server_port_spin_box</tabstop>
|
||||
<tabstop>udp_interfaces_combo_box</tabstop>
|
||||
<tabstop>udp_TTL_spin_box</tabstop>
|
||||
<tabstop>accept_udp_requests_check_box</tabstop>
|
||||
<tabstop>udpWindowToFront</tabstop>
|
||||
<tabstop>udpWindowRestore</tabstop>
|
||||
@ -3101,8 +3142,8 @@ Right click for insert and delete options.</string>
|
||||
<tabstop>include_WAE_check_box</tabstop>
|
||||
<tabstop>rescan_log_push_button</tabstop>
|
||||
<tabstop>LotW_CSV_URL_line_edit</tabstop>
|
||||
<tabstop>LotW_days_since_upload_spin_box</tabstop>
|
||||
<tabstop>LotW_CSV_fetch_push_button</tabstop>
|
||||
<tabstop>LotW_days_since_upload_spin_box</tabstop>
|
||||
<tabstop>sbNtrials</tabstop>
|
||||
<tabstop>sbAggressive</tabstop>
|
||||
<tabstop>cbTwoPass</tabstop>
|
||||
@ -3118,11 +3159,11 @@ Right click for insert and delete options.</string>
|
||||
<tabstop>rbHound</tabstop>
|
||||
<tabstop>rbNA_VHF_Contest</tabstop>
|
||||
<tabstop>rbField_Day</tabstop>
|
||||
<tabstop>Field_Day_Exchange</tabstop>
|
||||
<tabstop>rbEU_VHF_Contest</tabstop>
|
||||
<tabstop>rbRTTY_Roundup</tabstop>
|
||||
<tabstop>RTTY_Exchange</tabstop>
|
||||
<tabstop>rbWW_DIGI</tabstop>
|
||||
<tabstop>Field_Day_Exchange</tabstop>
|
||||
<tabstop>RTTY_Exchange</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
@ -3192,13 +3233,13 @@ Right click for insert and delete options.</string>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="PTT_method_button_group"/>
|
||||
<buttongroup name="CAT_data_bits_button_group"/>
|
||||
<buttongroup name="CAT_stop_bits_button_group"/>
|
||||
<buttongroup name="special_op_activity_button_group"/>
|
||||
<buttongroup name="TX_mode_button_group"/>
|
||||
<buttongroup name="TX_audio_source_button_group"/>
|
||||
<buttongroup name="CAT_stop_bits_button_group"/>
|
||||
<buttongroup name="CAT_handshake_button_group"/>
|
||||
<buttongroup name="CAT_data_bits_button_group"/>
|
||||
<buttongroup name="TX_mode_button_group"/>
|
||||
<buttongroup name="special_op_activity_button_group"/>
|
||||
<buttongroup name="PTT_method_button_group"/>
|
||||
<buttongroup name="split_mode_button_group"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
||||
@ -1,22 +1,41 @@
|
||||
Notes on WSJT-X Installation for Mac OS X
|
||||
-----------------------------------------
|
||||
|
||||
Important: If you are using the new Mac with the M1 chip then please read
|
||||
the section marked: BEGIN M1. Otherwise BEGIN INTEL applies.
|
||||
|
||||
If you have already downloaded a previous version of WSJT-X then I suggest
|
||||
you change the name in the Applications folder from WSJT-X to WSJT-X_previous
|
||||
before proceeding.
|
||||
|
||||
If you have installed a previous version of WSJT-X before, then there is no
|
||||
need to change anything on your system so proceed to NEXT. If you upgrade macOS
|
||||
it is possible that you might need to re-install the sysctl.conf file.
|
||||
I recommend that you follow the installation instructions especially if you
|
||||
are moving from v2.2 to v2.3 of WSJT-X or you have upgraded macOS.
|
||||
|
||||
BEGIN:
|
||||
BEGIN M1:
|
||||
|
||||
Double-click on the wsjtx-...-Darwin.dmg file you have downloaded from K1JT's web-site.
|
||||
|
||||
Now open a Terminal window by going to Applications->Utilities and clicking on Terminal.
|
||||
|
||||
There are two system variables that must be set manually since the M1 Macs do not recognise
|
||||
automatic parameter settings by means of the sysctl.conf file present in the download.
|
||||
Type these commands - you will be asked for your password which will not be echoed:
|
||||
|
||||
sudo sysctl -w kern.sysv.shmmax=104857600
|
||||
sudo sysctl -w kern.sysv.shmall=25600
|
||||
|
||||
It is important to note that these parameter settings will not survive a reboot. If you
|
||||
need to reboot your Mac, then these commands must be re-entered. Now proceed to NEXT.
|
||||
|
||||
BEGIN INTEL:
|
||||
|
||||
Double-click on the wsjtx-...-Darwin.dmg file you have downloaded from K1JT's web-site.
|
||||
|
||||
Now open a Terminal window by going to Applications->Utilities and clicking on Terminal.
|
||||
|
||||
Along with this ReadMe file there is a file: sysctl.conf which must be copied to a
|
||||
system area by typing this line in the Terminal window and then pressing the Return key.
|
||||
system area by typing these two lines in the Terminal window and then pressing the Return key
|
||||
after each line.
|
||||
|
||||
sudo cp /Volumes/WSJT-X/sysctl.conf /etc
|
||||
|
||||
@ -28,7 +47,7 @@ change has been made by typing:
|
||||
|
||||
sysctl -a | grep sysv.shm
|
||||
|
||||
If shmmax is not shown as 14680064 then contact me since WSJT-X will fail to load with
|
||||
If shmmax is not shown as 104857600 then contact me since WSJT-X will fail to load with
|
||||
an error message: "Unable to create shared memory segment".
|
||||
|
||||
You can now close the Terminal window. It will not be necessary to repeat this procedure
|
||||
@ -77,23 +96,20 @@ Please email me if you have problems.
|
||||
|
||||
--- John G4KLA (g4kla@rmnjmn.co.uk)
|
||||
|
||||
Addendum: Information about sysctl.conf and multiple instances of wsjt-x.
|
||||
Addendum: Information about sysctl.conf and multiple instances of WSJT-X.
|
||||
|
||||
WSJT-X makes use of a block of memory which is shared between different parts of
|
||||
the code. The normal allocation of shared memory on a Mac is insufficient and this
|
||||
has to be increased. The sysctl.conf file is used for this purpose. You can
|
||||
use a Mac editor to examine sysctl.conf. (Do not use another editor - the file
|
||||
would be probably be corrupted.)
|
||||
would probably be corrupted.)
|
||||
|
||||
There are two important parameters that you need to consider. shmmax determines the
|
||||
amount of shared memory that must be allocated for WSJT-X to operate. This is 14680064 (14MB)
|
||||
and this is defined in the sysctl.conf file and should not be changed.
|
||||
It is possible to run two instances of WSJT-X simultaneously. See "Section 16.2
|
||||
Frequently asked Questions" in the User Guide. If you wish to run more than two instances
|
||||
simultaneously, the sysctl.conf file needs to be modified. Please email me with your
|
||||
requirements and I will provide a replacement sysctl.conf to suit.
|
||||
|
||||
It is possible to run more than one instance of WSJT-X simultaneously. See
|
||||
"Section 16.2 Frequently asked Questions" in the User Guide. The second important parameter
|
||||
shmall=17920 determines how many instances are permitted. This is calculated as:
|
||||
(shmall x 4096/14680064) = 5.
|
||||
The sysctl.conf file is configured to permit up to 5 instances of wsjtx to run simultaneously.
|
||||
If this limitation is acceptable then you can continue to install the sysctl.conf file without making any
|
||||
alterations. Otherwise you must edit the file to increase shmall according to this calculation.
|
||||
|
||||
If two instances of WSJT-X are running, it is likely that you might need additional
|
||||
audio devices, from two rigs for example. Visit Audio MIDI Setup and create an Aggregate Device
|
||||
which will allow you to specific more than one interface. I recommend you consult Apple's guide
|
||||
on combining multiple audio interfaces which is at https://support.apple.com/en-us/HT202000.
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
SOURCES += Detector/Detector.cpp
|
||||
|
||||
HEADERS += Detector/Detector.hpp
|
||||
HEADERS += Detector/Detector.hpp
|
||||
|
||||
45
ExceptionCatchingApplication.hpp
Normal file
45
ExceptionCatchingApplication.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef EXCEPTION_CATCHING_APPLICATION_HPP__
|
||||
#define EXCEPTION_CATCHING_APPLICATION_HPP__
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "Logger.hpp"
|
||||
|
||||
class QObject;
|
||||
class QEvent;
|
||||
|
||||
//
|
||||
// We can't use the GUI after QApplication::exit() is called so
|
||||
// uncaught exceptions can get lost on Windows systems where there is
|
||||
// no console terminal, so here we override QApplication::notify() and
|
||||
// wrap the base class call with a try block to catch and display
|
||||
// exceptions in a message box.
|
||||
//
|
||||
class ExceptionCatchingApplication
|
||||
: public QApplication
|
||||
{
|
||||
public:
|
||||
explicit ExceptionCatchingApplication (int& argc, char * * argv)
|
||||
: QApplication {argc, argv}
|
||||
{
|
||||
}
|
||||
bool notify (QObject * receiver, QEvent * e) override
|
||||
{
|
||||
try
|
||||
{
|
||||
return QApplication::notify (receiver, e);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
LOG_FATAL (e.what ());
|
||||
throw;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_FATAL ("Unexpected fatal error");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
21
INSTALL
21
INSTALL
@ -23,10 +23,10 @@ Building from Source
|
||||
====================
|
||||
|
||||
On Linux systems some of the prerequisite libraries are available in
|
||||
the mainstream distribution repositories. They are Qt v5 and FFTW v3.
|
||||
For MS Windows see the section "Building from Source on MS Windows"
|
||||
below. For Apple Mac see the section "Building from Source on Apple
|
||||
Mac".
|
||||
the mainstream distribution repositories. They are Qt v5, FFTW v3, and
|
||||
the Boost C++ libraries. For MS Windows see the section "Building
|
||||
from Source on MS Windows" below. For Apple Mac see the section
|
||||
"Building from Source on Apple Mac".
|
||||
|
||||
Qt v5, preferably v5.9 or later is required to build WSJT-X.
|
||||
|
||||
@ -43,12 +43,13 @@ the libfftw library development package. Normally installing the
|
||||
library development package pulls in all the FFTW v3 libraries
|
||||
including the single precision variant.
|
||||
|
||||
The Hamlib library optionally requires the libusb-1.0-1 library, if
|
||||
the development version (libusb-1.0-0-dev) is available Hamlib will
|
||||
configure its custom USB device back end drivers. Most rigs do not
|
||||
require this so normally you can choose not to install libusb-1.0-dev
|
||||
but if you have a SoftRock USB or similar SDR that uses a custom USB
|
||||
interface then it is required.
|
||||
The Hamlib library requires the readline development package and
|
||||
optionally requires the libusb-1.0-1 library, if the development
|
||||
version (libusb-1.0-0-dev) is available Hamlib will configure its
|
||||
custom USB device back end drivers. Most rigs do not require this so
|
||||
normally you can choose not to install libusb-1.0-dev but if you have
|
||||
a SoftRock USB or similar SDR that uses a custom USB interface then it
|
||||
is required.
|
||||
|
||||
The Hamlib library is required. Currently WSJT-X needs to be built
|
||||
using a forked version of the Hamlib git master. This fork contains
|
||||
|
||||
@ -9,6 +9,9 @@
|
||||
#include <QRegularExpression>
|
||||
#include <QDebug>
|
||||
|
||||
#include "qt_helpers.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
#include "pimpl_impl.hpp"
|
||||
|
||||
class L10nLoader::impl final
|
||||
@ -60,11 +63,11 @@ public:
|
||||
L10nLoader::L10nLoader (QApplication * app, QLocale const& locale, QString const& language_override)
|
||||
: m_ {app}
|
||||
{
|
||||
qDebug () << QString {"locale: language: %1 script: %2 country: %3 ui-languages: %4"}
|
||||
LOG_INFO (QString {"locale: language: %1 script: %2 country: %3 ui-languages: %4"}
|
||||
.arg (QLocale::languageToString (locale.language ()))
|
||||
.arg (QLocale::scriptToString (locale.script ()))
|
||||
.arg (QLocale::countryToString (locale.country ()))
|
||||
.arg (locale.uiLanguages ().join (", "));
|
||||
.arg (locale.uiLanguages ().join (", ")));
|
||||
|
||||
// we don't load translators if the language override is 'en',
|
||||
// 'en_US', or 'en-US'. In these cases we assume the user is trying
|
||||
@ -78,10 +81,10 @@ L10nLoader::L10nLoader (QApplication * app, QLocale const& locale, QString const
|
||||
QString translations_dir {":/Translations"};
|
||||
if (!skip_locale)
|
||||
{
|
||||
qDebug () << "Looking for locale based Qt translations in resources filesystem";
|
||||
LOG_TRACE ("Looking for locale based Qt translations in resources filesystem");
|
||||
if (m_->load_translator (locale, "qt", "_", translations_dir))
|
||||
{
|
||||
qDebug () << "Loaded Qt translations for current locale from resources";
|
||||
LOG_INFO ("Loaded Qt translations for current locale from resources");
|
||||
}
|
||||
|
||||
// Default translations for releases use translations stored in
|
||||
@ -96,28 +99,28 @@ L10nLoader::L10nLoader (QApplication * app, QLocale const& locale, QString const
|
||||
// source control for translators to access and update.
|
||||
|
||||
// try and load the base translation
|
||||
qDebug () << "Looking for WSJT-X translations based on UI languages in the resources filesystem";
|
||||
LOG_TRACE ("Looking for WSJT-X translations based on UI languages in the resources filesystem");
|
||||
for (QString locale_name : locale.uiLanguages ())
|
||||
{
|
||||
auto language = locale_name.left (2);
|
||||
if (locale.uiLanguages ().front ().left (2) == language)
|
||||
{
|
||||
qDebug () << QString {"Trying %1"}.arg (language);
|
||||
LOG_TRACE (QString {"Trying %1"}.arg (language));
|
||||
if (m_->load_translator ("wsjtx_" + language, translations_dir))
|
||||
{
|
||||
qDebug () << QString {"Loaded WSJT-X base translation file from %1 based on language %2"}
|
||||
LOG_INFO (QString {"Loaded WSJT-X base translation file from %1 based on language %2"}
|
||||
.arg (translations_dir)
|
||||
.arg (language);
|
||||
.arg (language));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// now try and load the most specific translations (may be a
|
||||
// duplicate but we shouldn't care)
|
||||
qDebug () << "Looking for WSJT-X translations based on locale in the resources filesystem";
|
||||
LOG_TRACE ("Looking for WSJT-X translations based on locale in the resources filesystem");
|
||||
if (m_->load_translator (locale, "wsjtx", "_", translations_dir))
|
||||
{
|
||||
qDebug () << "Loaded WSJT-X translations for current locale from resources";
|
||||
LOG_INFO ("Loaded WSJT-X translations for current locale from resources");
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,21 +136,21 @@ L10nLoader::L10nLoader (QApplication * app, QLocale const& locale, QString const
|
||||
language.replace ('-', '_');
|
||||
// try and load the base translation
|
||||
auto base_language = language.left (2);
|
||||
qDebug () << "Looking for WSJT-X translations based on command line region override in the resources filesystem";
|
||||
LOG_TRACE ("Looking for WSJT-X translations based on command line region override in the resources filesystem");
|
||||
if (m_->load_translator ("wsjtx_" + base_language, translations_dir))
|
||||
{
|
||||
qDebug () << QString {"Loaded base translation file from %1 based on language %2"}
|
||||
LOG_INFO (QString {"Loaded base translation file from %1 based on language %2"}
|
||||
.arg (translations_dir)
|
||||
.arg (base_language);
|
||||
.arg (base_language));
|
||||
}
|
||||
// now load the requested translations (may be a duplicate
|
||||
// but we shouldn't care)
|
||||
qDebug () << "Looking for WSJT-X translations based on command line override country in the resources filesystem";
|
||||
LOG_TRACE ("Looking for WSJT-X translations based on command line override country in the resources filesystem");
|
||||
if (m_->load_translator ("wsjtx_" + language, translations_dir))
|
||||
{
|
||||
qDebug () << QString {"Loaded translation file from %1 based on language %2"}
|
||||
LOG_INFO (QString {"Loaded translation file from %1 based on language %2"}
|
||||
.arg (translations_dir)
|
||||
.arg (language);
|
||||
.arg (language));
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,16 +163,16 @@ L10nLoader::L10nLoader (QApplication * app, QLocale const& locale, QString const
|
||||
// the LANG environment variable on non-Windows system.
|
||||
|
||||
// try and load the base translation
|
||||
qDebug () << "Looking for WSJT-X translations based on command line override country in the current directory";
|
||||
LOG_TRACE ("Looking for WSJT-X translations based on command line override country in the current directory");
|
||||
for (QString locale_name : locale.uiLanguages ())
|
||||
{
|
||||
auto language = locale_name.left (2);
|
||||
if (locale.uiLanguages ().front ().left (2) == language)
|
||||
{
|
||||
qDebug () << QString {"Trying %1"}.arg (language);
|
||||
LOG_TRACE (QString {"Trying %1"}.arg (language));
|
||||
if (m_->load_translator ("wsjtx_" + language))
|
||||
{
|
||||
qDebug () << QString {"Loaded base translation file from $cwd based on language %1"}.arg (language);
|
||||
LOG_INFO (QString {"Loaded base translation file from $cwd based on language %1"}.arg (language));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -179,10 +182,10 @@ L10nLoader::L10nLoader (QApplication * app, QLocale const& locale, QString const
|
||||
{
|
||||
// now try and load the most specific translations (may be a
|
||||
// duplicate but we shouldn't care)
|
||||
qDebug () << "Looking for WSJT-X translations based on locale in the resources filesystem";
|
||||
LOG_TRACE ("Looking for WSJT-X translations based on locale in the resources filesystem");
|
||||
if (m_->load_translator (locale, "wsjtx", "_"))
|
||||
{
|
||||
qDebug () << "loaded translations for current locale from a file";
|
||||
LOG_INFO ("loaded translations for current locale from a file");
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,17 +201,17 @@ L10nLoader::L10nLoader (QApplication * app, QLocale const& locale, QString const
|
||||
language.replace ('-', '_');
|
||||
// try and load the base translation
|
||||
auto base_language = language.left (2);
|
||||
qDebug () << "Looking for WSJT-X translations based on command line override country in the current directory";
|
||||
LOG_TRACE ("Looking for WSJT-X translations based on command line override country in the current directory");
|
||||
if (m_->load_translator ("wsjtx_" + base_language))
|
||||
{
|
||||
qDebug () << QString {"Loaded base translation file from $cwd based on language %1"}.arg (base_language);
|
||||
LOG_INFO (QString {"Loaded base translation file from $cwd based on language %1"}.arg (base_language));
|
||||
}
|
||||
// now load the requested translations (may be a duplicate
|
||||
// but we shouldn't care)
|
||||
qDebug () << "Looking for WSJT-X translations based on command line region in the current directory";
|
||||
LOG_TRACE ("Looking for WSJT-X translations based on command line region in the current directory");
|
||||
if (m_->load_translator ("wsjtx_" + language))
|
||||
{
|
||||
qDebug () << QString {"loaded translation file from $cwd based on language %1"}.arg (language);
|
||||
LOG_INFO (QString {"loaded translation file from $cwd based on language %1"}.arg (language));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
185
Logger.cpp
Normal file
185
Logger.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
#include "Logger.hpp"
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/log/core.hpp>
|
||||
#include <boost/log/common.hpp>
|
||||
#include <boost/log/sinks.hpp>
|
||||
#include <boost/log/expressions.hpp>
|
||||
#include <boost/log/expressions/keyword.hpp>
|
||||
#include <boost/log/attributes.hpp>
|
||||
#include <boost/log/attributes/clock.hpp>
|
||||
#include <boost/log/attributes/counter.hpp>
|
||||
#include <boost/log/attributes/current_process_id.hpp>
|
||||
#include <boost/log/attributes/current_thread_id.hpp>
|
||||
#include <boost/log/utility/setup/console.hpp>
|
||||
#include <boost/log/utility/setup/filter_parser.hpp>
|
||||
#include <boost/log/utility/setup/from_stream.hpp>
|
||||
#include <boost/log/utility/setup/settings.hpp>
|
||||
#include <boost/log/sinks/sync_frontend.hpp>
|
||||
#include <boost/log/sinks/text_ostream_backend.hpp>
|
||||
#include <boost/log/support/date_time.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
namespace logging = boost::log;
|
||||
namespace srcs = logging::sources;
|
||||
namespace sinks = logging::sinks;
|
||||
namespace keywords = logging::keywords;
|
||||
namespace expr = logging::expressions;
|
||||
namespace attrs = logging::attributes;
|
||||
namespace ptime = boost::posix_time;
|
||||
|
||||
BOOST_LOG_GLOBAL_LOGGER_CTOR_ARGS (sys,
|
||||
srcs::severity_channel_logger_mt<logging::trivial::severity_level>,
|
||||
(keywords::channel = "SYSLOG"));
|
||||
BOOST_LOG_GLOBAL_LOGGER_CTOR_ARGS (data,
|
||||
srcs::severity_channel_logger_mt<logging::trivial::severity_level>,
|
||||
(keywords::channel = "DATALOG"));
|
||||
|
||||
namespace Logger
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// Custom formatter factory to add TimeStamp format support in config ini file.
|
||||
// Allows %TimeStamp(format=\"%Y.%m.%d %H:%M:%S.%f\")% to be used in ini config file for property Format.
|
||||
class TimeStampFormatterFactory
|
||||
: public logging::basic_formatter_factory<char, ptime::ptime>
|
||||
{
|
||||
public:
|
||||
formatter_type create_formatter (logging::attribute_name const& name, args_map const& args)
|
||||
{
|
||||
args_map::const_iterator it = args.find ("format");
|
||||
if (it != args.end ())
|
||||
{
|
||||
return expr::stream
|
||||
<< expr::format_date_time<ptime::ptime>
|
||||
(
|
||||
expr::attr<ptime::ptime> (name), it->second
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return expr::stream
|
||||
<< expr::attr<ptime::ptime> (name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Custom formatter factory to add Uptime format support in config ini file.
|
||||
// Allows %Uptime(format=\"%O:%M:%S.%f\")% to be used in ini config file for property Format.
|
||||
// attrs::timer value type is ptime::time_duration
|
||||
class UptimeFormatterFactory
|
||||
: public logging::basic_formatter_factory<char, ptime::time_duration>
|
||||
{
|
||||
public:
|
||||
formatter_type create_formatter (logging::attribute_name const& name, args_map const& args)
|
||||
{
|
||||
args_map::const_iterator it = args.find ("format");
|
||||
if (it != args.end ())
|
||||
{
|
||||
return expr::stream
|
||||
<< expr::format_date_time<ptime::time_duration>
|
||||
(
|
||||
expr::attr<ptime::time_duration> (name), it->second
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return expr::stream
|
||||
<< expr::attr<ptime::time_duration> (name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class CommonInitialization
|
||||
{
|
||||
public:
|
||||
CommonInitialization ()
|
||||
{
|
||||
// Add attributes: LineID, TimeStamp, ProcessID, ThreadID, and Uptime
|
||||
auto core = logging::core::get ();
|
||||
core->add_global_attribute ("LineID", attrs::counter<unsigned int> (1));
|
||||
core->add_global_attribute ("TimeStamp", attrs::utc_clock ());
|
||||
core->add_global_attribute ("ProcessID", attrs::current_process_id ());
|
||||
core->add_global_attribute ("ThreadID", attrs::current_thread_id ());
|
||||
core->add_global_attribute ("Uptime", attrs::timer ());
|
||||
|
||||
// Allows %Severity% to be used in ini config file for property Filter.
|
||||
logging::register_simple_filter_factory<logging::trivial::severity_level, char> ("Severity");
|
||||
// Allows %Severity% to be used in ini config file for property Format.
|
||||
logging::register_simple_formatter_factory<logging::trivial::severity_level, char> ("Severity");
|
||||
// Allows %TimeStamp(format=\"%Y.%m.%d %H:%M:%S.%f\")% to be used in ini config file for property Format.
|
||||
logging::register_formatter_factory ("TimeStamp", boost::make_shared<TimeStampFormatterFactory> ());
|
||||
// Allows %Uptime(format=\"%O:%M:%S.%f\")% to be used in ini config file for property Format.
|
||||
logging::register_formatter_factory ("Uptime", boost::make_shared<UptimeFormatterFactory> ());
|
||||
}
|
||||
~CommonInitialization ()
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void init ()
|
||||
{
|
||||
CommonInitialization ci;
|
||||
}
|
||||
|
||||
void init_from_config (std::wistream& stream)
|
||||
{
|
||||
CommonInitialization ci;
|
||||
try
|
||||
{
|
||||
// Still can throw even with the exception suppressor above.
|
||||
logging::init_from_stream (stream);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::string err = "Caught exception initializing boost logging: ";
|
||||
err += e.what ();
|
||||
// Since we cannot be sure of boost log state, output to cerr and cout.
|
||||
std::cerr << "ERROR: " << err << std::endl;
|
||||
std::cout << "ERROR: " << err << std::endl;
|
||||
LOG_ERROR (err);
|
||||
}
|
||||
}
|
||||
|
||||
void disable ()
|
||||
{
|
||||
logging::core::get ()->set_logging_enabled (false);
|
||||
}
|
||||
|
||||
void add_datafile_log (std::wstring const& log_file_name)
|
||||
{
|
||||
// Create a text file sink
|
||||
boost::shared_ptr<sinks::wtext_ostream_backend> backend
|
||||
(
|
||||
new sinks::wtext_ostream_backend()
|
||||
);
|
||||
backend->add_stream (boost::shared_ptr<std::wostream> (new fs::wofstream (log_file_name)));
|
||||
|
||||
// Flush after each log record
|
||||
backend->auto_flush (true);
|
||||
|
||||
// Create a sink for the backend
|
||||
typedef sinks::synchronous_sink<sinks::wtext_ostream_backend> sink_t;
|
||||
boost::shared_ptr<sink_t> sink (new sink_t (backend));
|
||||
|
||||
// The log output formatter
|
||||
sink->set_formatter (expr::format (L"[%1%][%2%] %3%")
|
||||
% expr::attr<ptime::ptime> ("TimeStamp")
|
||||
% logging::trivial::severity
|
||||
% expr::message
|
||||
);
|
||||
|
||||
// Filter by severity and by DATALOG channel
|
||||
sink->set_filter (logging::trivial::severity >= logging::trivial::info &&
|
||||
expr::attr<std::string> ("Channel") == "DATALOG");
|
||||
|
||||
// Add it to the core
|
||||
logging::core::get ()->add_sink (sink);
|
||||
}
|
||||
}
|
||||
58
Logger.hpp
Normal file
58
Logger.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef LOGGER_HPP__
|
||||
#define LOGGER_HPP__
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/sources/global_logger_storage.hpp>
|
||||
#include <boost/log/sources/severity_channel_logger.hpp>
|
||||
#include <boost/log/sources/record_ostream.hpp>
|
||||
#include <boost/log/attributes/mutable_constant.hpp>
|
||||
#include <boost/log/utility/manipulators/add_value.hpp>
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
BOOST_LOG_GLOBAL_LOGGER (sys,
|
||||
boost::log::sources::severity_channel_logger_mt<boost::log::trivial::severity_level>);
|
||||
BOOST_LOG_GLOBAL_LOGGER (data,
|
||||
boost::log::sources::severity_channel_logger_mt<boost::log::trivial::severity_level>);
|
||||
|
||||
namespace Logger
|
||||
{
|
||||
// trivial logging to console
|
||||
void init ();
|
||||
|
||||
// define logger(s) and sinks from a configuration stream
|
||||
void init_from_config (std::wistream& config_stream);
|
||||
|
||||
// disable logging - useful for unit testing etc.
|
||||
void disable ();
|
||||
|
||||
// add a new file sink for LOG_DATA_* for Severity >= INFO
|
||||
// this file sink will be used alongside any configured above
|
||||
void add_data_file_log (std::wstring const& log_file_name);
|
||||
}
|
||||
|
||||
#define LOG_LOG_LOCATION(LOGGER, LEVEL, ARG) \
|
||||
BOOST_LOG_SEV (LOGGER, boost::log::trivial::LEVEL) \
|
||||
<< boost::log::add_value ("Line", __LINE__) \
|
||||
<< boost::log::add_value ("File", __FILE__) \
|
||||
<< boost::log::add_value ("Function", __FUNCTION__) << ARG;
|
||||
|
||||
/// System Log macros.
|
||||
/// TRACE < DEBUG < INFO < WARN < ERROR < FATAL
|
||||
#define LOG_TRACE(ARG) LOG_LOG_LOCATION (sys::get(), trace, ARG);
|
||||
#define LOG_DEBUG(ARG) LOG_LOG_LOCATION (sys::get(), debug, ARG);
|
||||
#define LOG_INFO(ARG) LOG_LOG_LOCATION (sys::get(), info, ARG);
|
||||
#define LOG_WARN(ARG) LOG_LOG_LOCATION (sys::get(), warning, ARG);
|
||||
#define LOG_ERROR(ARG) LOG_LOG_LOCATION (sys::get(), error, ARG);
|
||||
#define LOG_FATAL(ARG) LOG_LOG_LOCATION (sys::get(), fatal, ARG);
|
||||
|
||||
/// Data Log macros. Does not include LINE, FILE, FUNCTION.
|
||||
/// TRACE < DEBUG < INFO < WARN < ERROR < FATAL
|
||||
#define LOG_DATA_TRACE(ARG) BOOST_LOG_SEV (data::get(), boost::log::trivial::trace) << ARG
|
||||
#define LOG_DATA_DEBUG(ARG) BOOST_LOG_SEV (data::get(), boost::log::trivial::debug) << ARG
|
||||
#define LOG_DATA_INFO(ARG) BOOST_LOG_SEV (data::get(), boost::log::trivial::info) << ARG
|
||||
#define LOG_DATA_WARN(ARG) BOOST_LOG_SEV (data::get(), boost::log::trivial::warning) << ARG
|
||||
#define LOG_DATA_ERROR(ARG) BOOST_LOG_SEV (data::get(), boost::log::trivial::error) << ARG
|
||||
#define LOG_DATA_FATAL(ARG) BOOST_LOG_SEV (data::get(), boost::log::trivial::fatal) << ARG
|
||||
|
||||
#endif
|
||||
@ -54,6 +54,7 @@ void register_types ()
|
||||
|
||||
// Frequency list model
|
||||
qRegisterMetaTypeStreamOperators<FrequencyList_v2::Item> ("Item_v2");
|
||||
QMetaType::registerConverter<FrequencyList_v2::Item, QString> (&FrequencyList_v2::Item::toString);
|
||||
qRegisterMetaTypeStreamOperators<FrequencyList_v2::FrequencyItems> ("FrequencyItems_v2");
|
||||
|
||||
// defunct old versions
|
||||
@ -69,6 +70,7 @@ void register_types ()
|
||||
|
||||
// Station details
|
||||
qRegisterMetaType<StationList::Station> ("Station");
|
||||
QMetaType::registerConverter<StationList::Station, QString> (&StationList::Station::toString);
|
||||
qRegisterMetaType<StationList::Stations> ("Stations");
|
||||
qRegisterMetaTypeStreamOperators<StationList::Station> ("Station");
|
||||
qRegisterMetaTypeStreamOperators<StationList::Stations> ("Stations");
|
||||
@ -92,5 +94,6 @@ void register_types ()
|
||||
|
||||
// DecodeHighlightingModel
|
||||
qRegisterMetaTypeStreamOperators<DecodeHighlightingModel::HighlightInfo> ("HighlightInfo");
|
||||
QMetaType::registerConverter<DecodeHighlightingModel::HighlightInfo, QString> (&DecodeHighlightingModel::HighlightInfo::toString);
|
||||
qRegisterMetaTypeStreamOperators<DecodeHighlightingModel::HighlightItems> ("HighlightItems");
|
||||
}
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
SOURCES += Modulator/Modulator.cpp
|
||||
|
||||
HEADERS += Modulator/Mpdulator.hpp
|
||||
HEADERS += Modulator/Modulator.hpp
|
||||
|
||||
@ -6,16 +6,16 @@
|
||||
#include <limits>
|
||||
|
||||
#include <QUdpSocket>
|
||||
#include <QNetworkInterface>
|
||||
#include <QHostInfo>
|
||||
#include <QTimer>
|
||||
#include <QQueue>
|
||||
#include <QByteArray>
|
||||
#include <QHostAddress>
|
||||
#include <QColor>
|
||||
#include <QDebug>
|
||||
|
||||
#include "NetworkMessage.hpp"
|
||||
|
||||
#include "qt_helpers.hpp"
|
||||
#include "pimpl_impl.hpp"
|
||||
|
||||
#include "moc_MessageClient.cpp"
|
||||
@ -34,14 +34,15 @@ class MessageClient::impl
|
||||
|
||||
public:
|
||||
impl (QString const& id, QString const& version, QString const& revision,
|
||||
port_type server_port, MessageClient * self)
|
||||
port_type server_port, int TTL, MessageClient * self)
|
||||
: self_ {self}
|
||||
, dns_lookup_id_ {0}
|
||||
, enabled_ {false}
|
||||
, id_ {id}
|
||||
, version_ {version}
|
||||
, revision_ {revision}
|
||||
, dns_lookup_id_ {-1}
|
||||
, server_port_ {server_port}
|
||||
, TTL_ {TTL}
|
||||
, schema_ {2} // use 2 prior to negotiation not 1 which is broken
|
||||
, heartbeat_timer_ {new QTimer {this}}
|
||||
{
|
||||
@ -49,47 +50,50 @@ public:
|
||||
connect (this, &QIODevice::readyRead, this, &impl::pending_datagrams);
|
||||
|
||||
heartbeat_timer_->start (NetworkMessage::pulse * 1000);
|
||||
|
||||
// bind to an ephemeral port
|
||||
bind ();
|
||||
}
|
||||
|
||||
~impl ()
|
||||
{
|
||||
closedown ();
|
||||
if (dns_lookup_id_ != -1)
|
||||
{
|
||||
QHostInfo::abortHostLookup (dns_lookup_id_);
|
||||
}
|
||||
}
|
||||
|
||||
enum StreamStatus {Fail, Short, OK};
|
||||
|
||||
void parse_message (QByteArray const& msg);
|
||||
void set_server (QString const& server_name, QStringList const& network_interface_names);
|
||||
Q_SLOT void host_info_results (QHostInfo);
|
||||
void start ();
|
||||
void parse_message (QByteArray const&);
|
||||
void pending_datagrams ();
|
||||
void heartbeat ();
|
||||
void closedown ();
|
||||
StreamStatus check_status (QDataStream const&) const;
|
||||
void send_message (QByteArray const&);
|
||||
void send_message (QDataStream const& out, QByteArray const& message)
|
||||
void send_message (QByteArray const&, bool queue_if_pending = true);
|
||||
void send_message (QDataStream const& out, QByteArray const& message, bool queue_if_pending = true)
|
||||
{
|
||||
if (OK == check_status (out))
|
||||
{
|
||||
send_message (message);
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_EMIT self_->error ("Error creating UDP message");
|
||||
}
|
||||
if (OK == check_status (out))
|
||||
{
|
||||
send_message (message, queue_if_pending);
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_EMIT self_->error ("Error creating UDP message");
|
||||
}
|
||||
}
|
||||
|
||||
Q_SLOT void host_info_results (QHostInfo);
|
||||
|
||||
MessageClient * self_;
|
||||
int dns_lookup_id_;
|
||||
bool enabled_;
|
||||
QString id_;
|
||||
QString version_;
|
||||
QString revision_;
|
||||
QString server_string_;
|
||||
port_type server_port_;
|
||||
int dns_lookup_id_;
|
||||
QHostAddress server_;
|
||||
port_type server_port_;
|
||||
int TTL_;
|
||||
std::vector<QNetworkInterface> network_interfaces_;
|
||||
quint32 schema_;
|
||||
QTimer * heartbeat_timer_;
|
||||
std::vector<QHostAddress> blocked_addresses_;
|
||||
@ -101,36 +105,99 @@ public:
|
||||
|
||||
#include "MessageClient.moc"
|
||||
|
||||
void MessageClient::impl::set_server (QString const& server_name, QStringList const& network_interface_names)
|
||||
{
|
||||
// qDebug () << "MessageClient server:" << server_name << "port:" << server_port_ << "interfaces:" << network_interface_names;
|
||||
server_.setAddress (server_name);
|
||||
network_interfaces_.clear ();
|
||||
for (auto const& net_if_name : network_interface_names)
|
||||
{
|
||||
network_interfaces_.push_back (QNetworkInterface::interfaceFromName (net_if_name));
|
||||
}
|
||||
|
||||
if (server_.isNull () && server_name.size ()) // DNS lookup required
|
||||
{
|
||||
// queue a host address lookup
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
|
||||
dns_lookup_id_ = QHostInfo::lookupHost (server_name, this, &MessageClient::impl::host_info_results);
|
||||
#else
|
||||
dns_lookup_id_ = QHostInfo::lookupHost (server_name, this, SLOT (host_info_results (QHostInfo)));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
start ();
|
||||
}
|
||||
}
|
||||
|
||||
void MessageClient::impl::host_info_results (QHostInfo host_info)
|
||||
{
|
||||
if (host_info.lookupId () != dns_lookup_id_) return;
|
||||
dns_lookup_id_ = -1;
|
||||
if (QHostInfo::NoError != host_info.error ())
|
||||
{
|
||||
Q_EMIT self_->error ("UDP server lookup failed:\n" + host_info.errorString ());
|
||||
pending_messages_.clear (); // discard
|
||||
Q_EMIT self_->error ("UDP server DNS lookup failed: " + host_info.errorString ());
|
||||
}
|
||||
else if (host_info.addresses ().size ())
|
||||
else
|
||||
{
|
||||
auto server = host_info.addresses ()[0];
|
||||
if (blocked_addresses_.end () == std::find (blocked_addresses_.begin (), blocked_addresses_.end (), server))
|
||||
auto const& server_addresses = host_info.addresses ();
|
||||
if (server_addresses.size ())
|
||||
{
|
||||
server_ = server;
|
||||
TRACE_UDP ("resulting server:" << server);
|
||||
|
||||
// send initial heartbeat which allows schema negotiation
|
||||
heartbeat ();
|
||||
|
||||
// clear any backlog
|
||||
while (pending_messages_.size ())
|
||||
{
|
||||
send_message (pending_messages_.dequeue ());
|
||||
}
|
||||
server_ = server_addresses[0];
|
||||
}
|
||||
else
|
||||
}
|
||||
start ();
|
||||
}
|
||||
|
||||
void MessageClient::impl::start ()
|
||||
{
|
||||
if (server_.isNull ())
|
||||
{
|
||||
Q_EMIT self_->close ();
|
||||
pending_messages_.clear (); // discard
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_broadcast_address (server_))
|
||||
{
|
||||
Q_EMIT self_->error ("IPv4 broadcast not supported, please specify the loop-back address, a server host address, or multicast group address");
|
||||
pending_messages_.clear (); // discard
|
||||
return;
|
||||
}
|
||||
|
||||
if (blocked_addresses_.end () != std::find (blocked_addresses_.begin (), blocked_addresses_.end (), server_))
|
||||
{
|
||||
Q_EMIT self_->error ("UDP server blocked, please try another");
|
||||
pending_messages_.clear (); // discard
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE_UDP ("Trying server:" << server_.toString ());
|
||||
QHostAddress interface_addr {IPv6Protocol == server_.protocol () ? QHostAddress::AnyIPv6 : QHostAddress::AnyIPv4};
|
||||
|
||||
if (localAddress () != interface_addr)
|
||||
{
|
||||
if (UnconnectedState != state () || state ())
|
||||
{
|
||||
Q_EMIT self_->error ("UDP server blocked, please try another");
|
||||
pending_messages_.clear (); // discard
|
||||
close ();
|
||||
}
|
||||
// bind to an ephemeral port on the selected interface and set
|
||||
// up for sending datagrams
|
||||
bind (interface_addr);
|
||||
// qDebug () << "Bound to UDP port:" << localPort () << "on:" << localAddress ();
|
||||
|
||||
// set multicast TTL to limit scope when sending to multicast
|
||||
// group addresses
|
||||
setSocketOption (MulticastTtlOption, TTL_);
|
||||
}
|
||||
|
||||
// send initial heartbeat which allows schema negotiation
|
||||
heartbeat ();
|
||||
|
||||
// clear any backlog
|
||||
while (pending_messages_.size ())
|
||||
{
|
||||
send_message (pending_messages_.dequeue (), false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -358,14 +425,11 @@ void MessageClient::impl::heartbeat ()
|
||||
if (server_port_ && !server_.isNull ())
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder hb {&message, NetworkMessage::Heartbeat, id_, schema_};
|
||||
hb << NetworkMessage::Builder::schema_number // maximum schema number accepted
|
||||
<< version_.toUtf8 () << revision_.toUtf8 ();
|
||||
if (OK == check_status (hb))
|
||||
{
|
||||
TRACE_UDP ("schema:" << schema_ << "max schema:" << NetworkMessage::Builder::schema_number << "version:" << version_ << "revision:" << revision_);
|
||||
writeDatagram (message, server_, server_port_);
|
||||
}
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Heartbeat, id_, schema_};
|
||||
out << NetworkMessage::Builder::schema_number // maximum schema number accepted
|
||||
<< version_.toUtf8 () << revision_.toUtf8 ();
|
||||
TRACE_UDP ("schema:" << schema_ << "max schema:" << NetworkMessage::Builder::schema_number << "version:" << version_ << "revision:" << revision_);
|
||||
send_message (out, message, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,15 +439,12 @@ void MessageClient::impl::closedown ()
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Close, id_, schema_};
|
||||
if (OK == check_status (out))
|
||||
{
|
||||
TRACE_UDP ("");
|
||||
writeDatagram (message, server_, server_port_);
|
||||
}
|
||||
TRACE_UDP ("");
|
||||
send_message (out, message, false);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageClient::impl::send_message (QByteArray const& message)
|
||||
void MessageClient::impl::send_message (QByteArray const& message, bool queue_if_pending)
|
||||
{
|
||||
if (server_port_)
|
||||
{
|
||||
@ -391,11 +452,25 @@ void MessageClient::impl::send_message (QByteArray const& message)
|
||||
{
|
||||
if (message != last_message_) // avoid duplicates
|
||||
{
|
||||
writeDatagram (message, server_, server_port_);
|
||||
if (is_multicast_address (server_))
|
||||
{
|
||||
// send datagram on each selected network interface
|
||||
std::for_each (network_interfaces_.begin (), network_interfaces_.end ()
|
||||
, [&] (QNetworkInterface const& net_if) {
|
||||
setMulticastInterface (net_if);
|
||||
// qDebug () << "Multicast UDP datagram sent to:" << server_ << "port:" << server_port_ << "on:" << multicastInterface ().humanReadableName ();
|
||||
writeDatagram (message, server_, server_port_);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// qDebug () << "Unicast UDP datagram sent to:" << server_ << "port:" << server_port_;
|
||||
writeDatagram (message, server_, server_port_);
|
||||
}
|
||||
last_message_ = message;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (queue_if_pending)
|
||||
{
|
||||
pending_messages_.enqueue (message);
|
||||
}
|
||||
@ -428,9 +503,11 @@ auto MessageClient::impl::check_status (QDataStream const& stream) const -> Stre
|
||||
}
|
||||
|
||||
MessageClient::MessageClient (QString const& id, QString const& version, QString const& revision,
|
||||
QString const& server, port_type server_port, QObject * self)
|
||||
QString const& server_name, port_type server_port,
|
||||
QStringList const& network_interface_names,
|
||||
int TTL, QObject * self)
|
||||
: QObject {self}
|
||||
, m_ {id, version, revision, server_port, this}
|
||||
, m_ {id, version, revision, server_port, TTL, this}
|
||||
{
|
||||
connect (&*m_
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||
@ -449,8 +526,8 @@ MessageClient::MessageClient (QString const& id, QString const& version, QString
|
||||
#endif
|
||||
Q_EMIT error (m_->errorString ());
|
||||
}
|
||||
});
|
||||
set_server (server);
|
||||
});
|
||||
m_->set_server (server_name, network_interface_names);
|
||||
}
|
||||
|
||||
QHostAddress MessageClient::server_address () const
|
||||
@ -463,20 +540,9 @@ auto MessageClient::server_port () const -> port_type
|
||||
return m_->server_port_;
|
||||
}
|
||||
|
||||
void MessageClient::set_server (QString const& server)
|
||||
void MessageClient::set_server (QString const& server_name, QStringList const& network_interface_names)
|
||||
{
|
||||
m_->server_.clear ();
|
||||
m_->server_string_ = server;
|
||||
if (server.size ())
|
||||
{
|
||||
// queue a host address lookup
|
||||
TRACE_UDP ("server host DNS lookup:" << server);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
|
||||
m_->dns_lookup_id_ = QHostInfo::lookupHost (server, &*m_, &MessageClient::impl::host_info_results);
|
||||
#else
|
||||
m_->dns_lookup_id_ = QHostInfo::lookupHost (server, &*m_, SLOT (host_info_results (QHostInfo)));
|
||||
#endif
|
||||
}
|
||||
m_->set_server (server_name, network_interface_names);
|
||||
}
|
||||
|
||||
void MessageClient::set_server_port (port_type server_port)
|
||||
@ -484,6 +550,12 @@ void MessageClient::set_server_port (port_type server_port)
|
||||
m_->server_port_ = server_port;
|
||||
}
|
||||
|
||||
void MessageClient::set_TTL (int TTL)
|
||||
{
|
||||
m_->TTL_ = TTL;
|
||||
m_->setSocketOption (QAbstractSocket::MulticastTtlOption, m_->TTL_);
|
||||
}
|
||||
|
||||
void MessageClient::enable (bool flag)
|
||||
{
|
||||
m_->enabled_ = flag;
|
||||
@ -499,7 +571,7 @@ void MessageClient::status_update (Frequency f, QString const& mode, QString con
|
||||
, quint32 frequency_tolerance, quint32 tr_period
|
||||
, QString const& configuration_name)
|
||||
{
|
||||
if (m_->server_port_ && !m_->server_string_.isEmpty ())
|
||||
if (m_->server_port_ && !m_->server_.isNull ())
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Status, m_->id_, m_->schema_};
|
||||
@ -516,7 +588,7 @@ void MessageClient::decode (bool is_new, QTime time, qint32 snr, float delta_tim
|
||||
, QString const& mode, QString const& message_text, bool low_confidence
|
||||
, bool off_air)
|
||||
{
|
||||
if (m_->server_port_ && !m_->server_string_.isEmpty ())
|
||||
if (m_->server_port_ && !m_->server_.isNull ())
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Decode, m_->id_, m_->schema_};
|
||||
@ -531,7 +603,7 @@ void MessageClient::WSPR_decode (bool is_new, QTime time, qint32 snr, float delt
|
||||
, qint32 drift, QString const& callsign, QString const& grid, qint32 power
|
||||
, bool off_air)
|
||||
{
|
||||
if (m_->server_port_ && !m_->server_string_.isEmpty ())
|
||||
if (m_->server_port_ && !m_->server_.isNull ())
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::WSPRDecode, m_->id_, m_->schema_};
|
||||
@ -544,7 +616,7 @@ void MessageClient::WSPR_decode (bool is_new, QTime time, qint32 snr, float delt
|
||||
|
||||
void MessageClient::decodes_cleared ()
|
||||
{
|
||||
if (m_->server_port_ && !m_->server_string_.isEmpty ())
|
||||
if (m_->server_port_ && !m_->server_.isNull ())
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Clear, m_->id_, m_->schema_};
|
||||
@ -561,7 +633,7 @@ void MessageClient::qso_logged (QDateTime time_off, QString const& dx_call, QStr
|
||||
, QString const& my_grid, QString const& exchange_sent
|
||||
, QString const& exchange_rcvd, QString const& propmode)
|
||||
{
|
||||
if (m_->server_port_ && !m_->server_string_.isEmpty ())
|
||||
if (m_->server_port_ && !m_->server_.isNull ())
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::QSOLogged, m_->id_, m_->schema_};
|
||||
@ -576,7 +648,7 @@ void MessageClient::qso_logged (QDateTime time_off, QString const& dx_call, QStr
|
||||
|
||||
void MessageClient::logged_ADIF (QByteArray const& ADIF_record)
|
||||
{
|
||||
if (m_->server_port_ && !m_->server_string_.isEmpty ())
|
||||
if (m_->server_port_ && !m_->server_.isNull ())
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::LoggedADIF, m_->id_, m_->schema_};
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <QTime>
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
#include <QHostAddress>
|
||||
|
||||
#include "Radio.hpp"
|
||||
#include "pimpl_h.hpp"
|
||||
@ -34,19 +35,25 @@ public:
|
||||
//
|
||||
// messages will be silently dropped until a server host lookup is complete
|
||||
MessageClient (QString const& id, QString const& version, QString const& revision,
|
||||
QString const& server, port_type server_port, QObject * parent = nullptr);
|
||||
QString const& server_name, port_type server_port,
|
||||
QStringList const& network_interface_names,
|
||||
int TTL, QObject * parent = nullptr);
|
||||
|
||||
// query server details
|
||||
QHostAddress server_address () const;
|
||||
port_type server_port () const;
|
||||
|
||||
// initiate a new server host lookup or is the server name is empty
|
||||
// the sending of messages is disabled
|
||||
Q_SLOT void set_server (QString const& server = QString {});
|
||||
// initiate a new server host lookup or if the server name is empty
|
||||
// the sending of messages is disabled, if an interface is specified
|
||||
// then that interface is used for outgoing datagrams
|
||||
Q_SLOT void set_server (QString const& server_name, QStringList const& network_interface_names);
|
||||
|
||||
// change the server port messages are sent to
|
||||
Q_SLOT void set_server_port (port_type server_port = 0u);
|
||||
|
||||
// change the server port messages are sent to
|
||||
Q_SLOT void set_TTL (int TTL);
|
||||
|
||||
// enable incoming messages
|
||||
Q_SLOT void enable (bool);
|
||||
|
||||
|
||||
@ -28,13 +28,13 @@ namespace NetworkMessage
|
||||
{
|
||||
setVersion (QDataStream::Qt_5_0); // Qt schema version
|
||||
}
|
||||
#if QT_VERSION >= 0x050200
|
||||
#if QT_VERSION >= QT_VERSION_CHECK (5, 2, 0)
|
||||
else if (schema <= 2)
|
||||
{
|
||||
setVersion (QDataStream::Qt_5_2); // Qt schema version
|
||||
}
|
||||
#endif
|
||||
#if QT_VERSION >= 0x050400
|
||||
#if QT_VERSION >= QT_VERSION_CHECK (5, 4, 0)
|
||||
else if (schema <= 3)
|
||||
{
|
||||
setVersion (QDataStream::Qt_5_4); // Qt schema version
|
||||
@ -73,13 +73,13 @@ namespace NetworkMessage
|
||||
{
|
||||
parent->setVersion (QDataStream::Qt_5_0);
|
||||
}
|
||||
#if QT_VERSION >= 0x050200
|
||||
#if QT_VERSION >= QT_VERSION_CHECK (5, 2, 0)
|
||||
else if (schema_ <= 2)
|
||||
{
|
||||
parent->setVersion (QDataStream::Qt_5_2);
|
||||
}
|
||||
#endif
|
||||
#if QT_VERSION >= 0x050400
|
||||
#if QT_VERSION >= QT_VERSION_CHECK (5, 4, 0)
|
||||
else if (schema_ <= 3)
|
||||
{
|
||||
parent->setVersion (QDataStream::Qt_5_4);
|
||||
|
||||
@ -540,9 +540,9 @@ namespace NetworkMessage
|
||||
|
||||
// increment this if a newer Qt schema is required and add decode
|
||||
// logic to the Builder and Reader class implementations
|
||||
#if QT_VERSION >= 0x050400
|
||||
#if QT_VERSION >= QT_VERSION_CHECK (5, 4, 0)
|
||||
static quint32 constexpr schema_number {3};
|
||||
#elif QT_VERSION >= 0x050200
|
||||
#elif QT_VERSION >= QT_VERSION_CHECK (5, 2, 0)
|
||||
static quint32 constexpr schema_number {2};
|
||||
#else
|
||||
// Schema 1 (Qt_5_0) is broken
|
||||
|
||||
@ -84,7 +84,7 @@ public:
|
||||
{
|
||||
if (!socket_
|
||||
|| QAbstractSocket::UnconnectedState == socket_->state ()
|
||||
|| (socket_->socketType () != config_->psk_reporter_tcpip () ? QAbstractSocket::TcpSocket : QAbstractSocket::UdpSocket))
|
||||
|| (socket_->socketType () != (config_->psk_reporter_tcpip () ? QAbstractSocket::TcpSocket : QAbstractSocket::UdpSocket)))
|
||||
{
|
||||
// we need to create the appropriate socket
|
||||
if (socket_
|
||||
|
||||
@ -86,26 +86,29 @@ void WSPRNet::upload (QString const& call, QString const& grid, QString const& r
|
||||
m_file = fileName;
|
||||
|
||||
// Open the wsprd.out file
|
||||
QFile wsprdOutFile (fileName);
|
||||
if (!wsprdOutFile.open (QIODevice::ReadOnly | QIODevice::Text) || !wsprdOutFile.size ())
|
||||
if (m_uploadType != 3)
|
||||
{
|
||||
spot_queue_.enqueue (urlEncodeNoSpot ());
|
||||
m_uploadType = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read the contents
|
||||
while (!wsprdOutFile.atEnd())
|
||||
QFile wsprdOutFile (fileName);
|
||||
if (!wsprdOutFile.open (QIODevice::ReadOnly | QIODevice::Text) || !wsprdOutFile.size ())
|
||||
{
|
||||
SpotQueue::value_type query;
|
||||
if (decodeLine (wsprdOutFile.readLine(), query))
|
||||
spot_queue_.enqueue (urlEncodeNoSpot ());
|
||||
m_uploadType = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read the contents
|
||||
while (!wsprdOutFile.atEnd())
|
||||
{
|
||||
// Prevent reporting data ouside of the current frequency band
|
||||
float f = fabs (m_rfreq.toFloat() - query.queryItemValue ("tqrg", QUrl::FullyDecoded).toFloat());
|
||||
if (f < 0.0002)
|
||||
SpotQueue::value_type query;
|
||||
if (decodeLine (wsprdOutFile.readLine(), query))
|
||||
{
|
||||
spot_queue_.enqueue(urlEncodeSpot (query));
|
||||
m_uploadType = 2;
|
||||
// Prevent reporting data ouside of the current frequency band
|
||||
float f = fabs (m_rfreq.toFloat() - query.queryItemValue ("tqrg", QUrl::FullyDecoded).toFloat());
|
||||
if (f < 0.01) // MHz
|
||||
{
|
||||
spot_queue_.enqueue(urlEncodeSpot (query));
|
||||
m_uploadType = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -133,10 +136,8 @@ void WSPRNet::post (QString const& call, QString const& grid, QString const& rfr
|
||||
if (!spot_queue_.size ())
|
||||
{
|
||||
spot_queue_.enqueue (urlEncodeNoSpot ());
|
||||
m_uploadType = 1;
|
||||
m_uploadType = 3;
|
||||
}
|
||||
spots_to_send_ = spot_queue_.size ();
|
||||
upload_timer_.start (200);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -144,9 +145,11 @@ void WSPRNet::post (QString const& call, QString const& grid, QString const& rfr
|
||||
if (match.hasMatch ())
|
||||
{
|
||||
SpotQueue::value_type query;
|
||||
// Prevent reporting data ouside of the current frequency band
|
||||
// Prevent reporting data ouside of the current frequency
|
||||
// band - removed by G4WJS to accommodate FST4W spots
|
||||
// outside of WSPR segments
|
||||
auto tqrg = match.captured ("freq").toInt ();
|
||||
if (tqrg >= 1400 && tqrg <= 1600)
|
||||
// if (tqrg >= 1400 && tqrg <= 1600)
|
||||
{
|
||||
query.addQueryItem ("function", "wspr");
|
||||
// use time as at 3/4 of T/R period before current to
|
||||
@ -208,7 +211,7 @@ void WSPRNet::networkReply (QNetworkReply * reply)
|
||||
}
|
||||
}
|
||||
|
||||
bool WSPRNet::decodeLine (QString const& line, SpotQueue::value_type& query)
|
||||
bool WSPRNet::decodeLine (QString const& line, SpotQueue::value_type& query) const
|
||||
{
|
||||
auto const& rx_match = wspr_re.match (line);
|
||||
if (rx_match.hasMatch ()) {
|
||||
@ -268,7 +271,23 @@ bool WSPRNet::decodeLine (QString const& line, SpotQueue::value_type& query)
|
||||
return true;
|
||||
}
|
||||
|
||||
auto WSPRNet::urlEncodeNoSpot () -> SpotQueue::value_type
|
||||
QString WSPRNet::encode_mode () const
|
||||
{
|
||||
if (m_mode == "WSPR") return "2";
|
||||
if (m_mode == "WSPR-15") return "15";
|
||||
if (m_mode == "FST4W")
|
||||
{
|
||||
auto tr = static_cast<int> ((TR_period_ / 60.)+.5);
|
||||
if (2 == tr || 15 == tr)
|
||||
{
|
||||
tr += 1; // distinguish from WSPR-2 and WSPR-15
|
||||
}
|
||||
return QString::number (tr);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
auto WSPRNet::urlEncodeNoSpot () const -> SpotQueue::value_type
|
||||
{
|
||||
SpotQueue::value_type query;
|
||||
query.addQueryItem ("function", "wsprstat");
|
||||
@ -279,28 +298,18 @@ auto WSPRNet::urlEncodeNoSpot () -> SpotQueue::value_type
|
||||
query.addQueryItem ("tqrg", m_tfreq);
|
||||
query.addQueryItem ("dbm", m_dbm);
|
||||
query.addQueryItem ("version", m_vers);
|
||||
if (m_mode == "WSPR") query.addQueryItem ("mode", "2");
|
||||
if (m_mode == "WSPR-15") query.addQueryItem ("mode", "15");
|
||||
if (m_mode == "FST4W")
|
||||
{
|
||||
query.addQueryItem ("mode", QString::number (static_cast<int> ((TR_period_ / 60.)+.5)));
|
||||
}
|
||||
query.addQueryItem ("mode", encode_mode ());
|
||||
return query;;
|
||||
}
|
||||
|
||||
auto WSPRNet::urlEncodeSpot (SpotQueue::value_type& query) -> SpotQueue::value_type
|
||||
auto WSPRNet::urlEncodeSpot (SpotQueue::value_type& query) const -> SpotQueue::value_type
|
||||
{
|
||||
query.addQueryItem ("version", m_vers);
|
||||
query.addQueryItem ("rcall", m_call);
|
||||
query.addQueryItem ("rgrid", m_grid);
|
||||
query.addQueryItem ("rqrg", m_rfreq);
|
||||
if (m_mode == "WSPR") query.addQueryItem ("mode", "2");
|
||||
if (m_mode == "WSPR-15") query.addQueryItem ("mode", "15");
|
||||
if (m_mode == "FST4W")
|
||||
{
|
||||
query.addQueryItem ("mode", QString::number (static_cast<int> ((TR_period_ / 60.)+.5)));
|
||||
}
|
||||
return query;
|
||||
query.addQueryItem ("mode", encode_mode ());
|
||||
return query;
|
||||
}
|
||||
|
||||
void WSPRNet::work()
|
||||
|
||||
@ -34,9 +34,10 @@ public slots:
|
||||
void abortOutstandingRequests ();
|
||||
|
||||
private:
|
||||
bool decodeLine (QString const& line, SpotQueue::value_type& query);
|
||||
SpotQueue::value_type urlEncodeNoSpot ();
|
||||
SpotQueue::value_type urlEncodeSpot (SpotQueue::value_type& spot);
|
||||
bool decodeLine (QString const& line, SpotQueue::value_type& query) const;
|
||||
SpotQueue::value_type urlEncodeNoSpot () const;
|
||||
SpotQueue::value_type urlEncodeSpot (SpotQueue::value_type& spot) const;
|
||||
QString encode_mode () const;
|
||||
|
||||
QNetworkAccessManager * network_manager_;
|
||||
QList<QNetworkReply *> m_outstandingRequests;
|
||||
|
||||
116
NonInheritingProcess.cpp
Normal file
116
NonInheritingProcess.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
#include "NonInheritingProcess.hpp"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif
|
||||
#ifdef _WIN32_WINNT
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
#define _WIN32_WINNT 0x0601
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#include "pimpl_impl.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
struct start_info_deleter
|
||||
{
|
||||
void operator () (STARTUPINFOEXW * si)
|
||||
{
|
||||
if (si->lpAttributeList)
|
||||
{
|
||||
::DeleteProcThreadAttributeList (si->lpAttributeList);
|
||||
}
|
||||
delete si;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
class NonInheritingProcess::impl
|
||||
{
|
||||
public:
|
||||
#ifdef Q_OS_WIN
|
||||
void extend_CreateProcessArguments (QProcess::CreateProcessArguments * args)
|
||||
{
|
||||
//
|
||||
// Here we modify the CreateProcessArguments structure to use a
|
||||
// STARTUPINFOEX extended argument to CreateProcess. In that we
|
||||
// set up a list of handles for the new process to inherit. By
|
||||
// doing this we stop all inherited handles from being
|
||||
// inherited. Unfortunately UpdateProcThreadAttribute does not let
|
||||
// us set up an empty handle list, so we populate the list with
|
||||
// the three standard stream handles that QProcess::start has set
|
||||
// up as Pipes to do IPC. Even though these Pipe handles are
|
||||
// created with inheritance disabled, UpdateProcThreadAtribute and
|
||||
// CreateProcess don't seem to mind, which suits us fine.
|
||||
//
|
||||
// Note: that we cannot just clear the inheritHandles flag as that
|
||||
// stops the standard stream handles being inherited which breaks
|
||||
// our IPC using std(in|out|err). Only be using a
|
||||
// PROC_THREAD_ATTRIBUTE_HANDLE_LIST attribute in a STARTUPINFOEX
|
||||
// structure can we avoid the all or nothing behaviour of
|
||||
// CreateProcess /w respect to handle inheritance.
|
||||
//
|
||||
BOOL fSuccess;
|
||||
SIZE_T size {0};
|
||||
LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = nullptr;
|
||||
::InitializeProcThreadAttributeList (nullptr, 1, 0, &size);
|
||||
lpAttributeList = reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST> (::HeapAlloc (::GetProcessHeap (), 0, size));
|
||||
fSuccess = !!lpAttributeList;
|
||||
if (fSuccess)
|
||||
{
|
||||
fSuccess = ::InitializeProcThreadAttributeList (lpAttributeList, 1, 0, &size);
|
||||
}
|
||||
if (fSuccess)
|
||||
{
|
||||
// empty list of handles
|
||||
fSuccess = ::UpdateProcThreadAttribute (lpAttributeList, 0,
|
||||
PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
|
||||
&args->startupInfo->hStdInput, 3 * sizeof (HANDLE),
|
||||
nullptr, 0);
|
||||
}
|
||||
if (fSuccess)
|
||||
{
|
||||
start_info_.reset (new STARTUPINFOEXW);
|
||||
start_info_->StartupInfo = *args->startupInfo;
|
||||
start_info_->StartupInfo.cb = sizeof (STARTUPINFOEXW);
|
||||
start_info_->lpAttributeList = lpAttributeList;
|
||||
args->startupInfo = reinterpret_cast<Q_STARTUPINFO*> (start_info_.get ());
|
||||
args->flags |= EXTENDED_STARTUPINFO_PRESENT;
|
||||
}
|
||||
}
|
||||
|
||||
using start_info_type = std::unique_ptr<STARTUPINFOEXW, start_info_deleter>;
|
||||
start_info_type start_info_;
|
||||
#endif
|
||||
};
|
||||
|
||||
NonInheritingProcess::NonInheritingProcess (QObject * parent)
|
||||
: QProcess {parent}
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
using namespace std::placeholders;
|
||||
|
||||
// enable cleanup after process starts or fails to start
|
||||
connect (this, &QProcess::started, [this] {m_->start_info_.reset ();});
|
||||
connect (this, &QProcess::errorOccurred, [this] (QProcess::ProcessError) {m_->start_info_.reset ();});
|
||||
setCreateProcessArgumentsModifier (std::bind (&NonInheritingProcess::impl::extend_CreateProcessArguments, &*m_, _1));
|
||||
#endif
|
||||
}
|
||||
|
||||
NonInheritingProcess::~NonInheritingProcess ()
|
||||
{
|
||||
}
|
||||
35
NonInheritingProcess.hpp
Normal file
35
NonInheritingProcess.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef NON_INHERITING_PROCESS_HPP__
|
||||
#define NON_INHERITING_PROCESS_HPP__
|
||||
|
||||
#include <QProcess>
|
||||
#include "pimpl_h.hpp"
|
||||
|
||||
class QObject;
|
||||
|
||||
//
|
||||
// class NonInheritingProcess - Manage a process without it inheriting
|
||||
// all inheritable handles
|
||||
//
|
||||
// On MS Windows QProcess creates sub-processes which inherit all
|
||||
// inheritable handles, and handles on Windows are inheritable by
|
||||
// default. This can cause the lifetime of objects to be unexpectedly
|
||||
// extended, which in turn can cause unexpected errors. The motivation
|
||||
// for this class was implementing log file rotation using the Boost
|
||||
// log library. The current log file's handle gets inherited by any
|
||||
// long running sub-process started by QProcess and that causes a
|
||||
// sharing violation when attempting to rename the log file on
|
||||
// rotation, even though the log library closes the current log file
|
||||
// before trying to rename it.
|
||||
//
|
||||
class NonInheritingProcess
|
||||
: public QProcess
|
||||
{
|
||||
public:
|
||||
NonInheritingProcess (QObject * parent = nullptr);
|
||||
~NonInheritingProcess ();
|
||||
|
||||
private:
|
||||
class impl;
|
||||
pimpl<impl> m_;
|
||||
};
|
||||
#endif
|
||||
12
Radio.cpp
12
Radio.cpp
@ -14,10 +14,16 @@ namespace Radio
|
||||
double constexpr MHz_factor {1.e6};
|
||||
int constexpr frequency_precsion {6};
|
||||
|
||||
// valid callsign alphabet
|
||||
QRegularExpression callsign_alphabet_re {R"(^[A-Z0-9/]{3,11}$)"};
|
||||
|
||||
// very loose validation - callsign must contain a letter next to
|
||||
// a number
|
||||
QRegularExpression valid_callsign_regexp {R"(\d[[:alpha:]]|[[:alpha:]]\d)"};
|
||||
|
||||
// standard callsign
|
||||
QRegularExpression strict_standard_callsign_re {R"(^([A-Z][0-9]?|[0-9A-Z][A-Z])[0-9][A-Z]{0,3}$)"};
|
||||
|
||||
// suffixes that are often used and should not be interpreted as a
|
||||
// DXCC Entity prefix used as a suffix
|
||||
QRegularExpression non_prefix_suffix {R"(\A([0-9AMPQR]|QRP|F[DF]|[AM]M|L[HT]|LGT)\z)"};
|
||||
@ -112,6 +118,12 @@ namespace Radio
|
||||
return callsign.contains ('/');
|
||||
}
|
||||
|
||||
bool is_77bit_nonstandard_callsign (QString const& callsign)
|
||||
{
|
||||
return callsign.contains (callsign_alphabet_re)
|
||||
&& !callsign.contains (strict_standard_callsign_re);
|
||||
}
|
||||
|
||||
// split on first '/' and return the larger portion or the whole if
|
||||
// there is no '/'
|
||||
QString base_callsign (QString callsign)
|
||||
|
||||
@ -53,6 +53,7 @@ namespace Radio
|
||||
//
|
||||
bool UDP_EXPORT is_callsign (QString const&);
|
||||
bool UDP_EXPORT is_compound_callsign (QString const&);
|
||||
bool is_77bit_nonstandard_callsign (QString const&);
|
||||
QString UDP_EXPORT base_callsign (QString);
|
||||
QString UDP_EXPORT effective_prefix (QString);
|
||||
}
|
||||
|
||||
@ -13,6 +13,38 @@
|
||||
Copyright 2001 - 2020 by Joe Taylor, K1JT.
|
||||
|
||||
|
||||
Release: WSJT-X 2.3.0-rc2
|
||||
Nov 16, 2020
|
||||
-------------------------
|
||||
|
||||
WSJT-X 2.3.0 Release Candidate 2 fixes issues found in RC1 and
|
||||
includes some new functionality that missed the RC1 cut off deadline.
|
||||
|
||||
- Dropped audio samples message box removed, warnings and errors for
|
||||
these are now sent to the WSJT-X system log.
|
||||
|
||||
- FST4W spots to WSPRNet.org will be augmented such that the server
|
||||
can distinguish the mode being spotted. Spots to WSPRNet.org will
|
||||
no longer be restricted to WSPR sub-bands.
|
||||
|
||||
- A new internal system and data logging facility used to provide
|
||||
trace, debug, information, warning, error, and fatal error
|
||||
messages. The verbosity and filtering of messages is user definable
|
||||
via a configuration file. Without a configuration file a basic log
|
||||
is written with information, warning and error messages only. Log
|
||||
files are automatically rotated to limit disk usage.
|
||||
|
||||
- Due to some users using inappropriate multicast IP addresses for
|
||||
their interoperating severs the default behaviour now is to only
|
||||
send multicast UDP datagrams to the loop-back network interface.
|
||||
Users who require WSJT-X UDP Message Protocol datagrams to reach
|
||||
other hosts will now have to configure WSJT-X to send on an
|
||||
appropriate network interface, and use an appropriately scoped
|
||||
multicast group address for their server applications. If you are
|
||||
not sure then 224.0.0.1 (or ff02::1 if IPv6 is desired) is a safe
|
||||
choice.
|
||||
|
||||
|
||||
Release: WSJT-X 2.3.0-rc1
|
||||
Sept 28, 2020
|
||||
-------------------------
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <QThread>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "qt_helpers.hpp"
|
||||
#include "Network/NetworkServerLookup.hpp"
|
||||
|
||||
#include "moc_DXLabSuiteCommanderTransceiver.cpp"
|
||||
@ -36,15 +37,18 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::register_transceivers (TransceiverFactory::Transceivers * registry, int id)
|
||||
void DXLabSuiteCommanderTransceiver::register_transceivers (logger_type * /*logger*/,
|
||||
TransceiverFactory::Transceivers * registry,
|
||||
int id)
|
||||
{
|
||||
(*registry)[commander_transceiver_name] = TransceiverFactory::Capabilities {id, TransceiverFactory::Capabilities::network, true};
|
||||
}
|
||||
|
||||
DXLabSuiteCommanderTransceiver::DXLabSuiteCommanderTransceiver (std::unique_ptr<TransceiverBase> wrapped,
|
||||
DXLabSuiteCommanderTransceiver::DXLabSuiteCommanderTransceiver (logger_type * logger,
|
||||
std::unique_ptr<TransceiverBase> wrapped,
|
||||
QString const& address, bool use_for_ptt,
|
||||
int poll_interval, QObject * parent)
|
||||
: PollingTransceiver {poll_interval, parent}
|
||||
: PollingTransceiver {logger, poll_interval, parent}
|
||||
, wrapped_ {std::move (wrapped)}
|
||||
, use_for_ptt_ {use_for_ptt}
|
||||
, server_ {address}
|
||||
@ -54,7 +58,7 @@ DXLabSuiteCommanderTransceiver::DXLabSuiteCommanderTransceiver (std::unique_ptr<
|
||||
|
||||
int DXLabSuiteCommanderTransceiver::do_start ()
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "starting");
|
||||
CAT_TRACE ("starting");
|
||||
if (wrapped_) wrapped_->start (0);
|
||||
|
||||
auto server_details = network_server_lookup (server_, 52002u, QHostAddress::LocalHost, QAbstractSocket::IPv4Protocol);
|
||||
@ -67,7 +71,7 @@ int DXLabSuiteCommanderTransceiver::do_start ()
|
||||
commander_->connectToHost (std::get<0> (server_details), std::get<1> (server_details));
|
||||
if (!commander_->waitForConnected ())
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "failed to connect" << commander_->errorString ());
|
||||
CAT_ERROR ("failed to connect" << commander_->errorString ());
|
||||
throw error {tr ("Failed to connect to DX Lab Suite Commander\n") + commander_->errorString ()};
|
||||
}
|
||||
|
||||
@ -123,7 +127,7 @@ int DXLabSuiteCommanderTransceiver::do_start ()
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "get frequency unexpected response" << reply);
|
||||
CAT_ERROR ("get frequency unexpected response" << reply);
|
||||
throw error {tr ("DX Lab Suite Commander didn't respond correctly reading frequency: ") + reply};
|
||||
}
|
||||
|
||||
@ -140,12 +144,12 @@ void DXLabSuiteCommanderTransceiver::do_stop ()
|
||||
}
|
||||
|
||||
if (wrapped_) wrapped_->stop ();
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "stopped");
|
||||
CAT_TRACE ("stopped");
|
||||
}
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::do_ptt (bool on)
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", on << state ());
|
||||
CAT_TRACE (on << state ());
|
||||
if (use_for_ptt_)
|
||||
{
|
||||
simple_command (on ? "<command:5>CmdTX<parameters:0>" : "<command:5>CmdRX<parameters:0>");
|
||||
@ -170,13 +174,13 @@ void DXLabSuiteCommanderTransceiver::do_ptt (bool on)
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "unexpected TX state" << state);
|
||||
CAT_ERROR ("unexpected TX state" << state);
|
||||
throw error {tr ("DX Lab Suite Commander sent an unrecognised TX state: ") + state};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "get TX unexpected response" << reply);
|
||||
CAT_ERROR ("get TX unexpected response" << reply);
|
||||
throw error {tr ("DX Lab Suite Commander didn't respond correctly polling TX status: ") + reply};
|
||||
}
|
||||
if (tx != on) QThread::msleep (10); // don't thrash Commander
|
||||
@ -184,7 +188,7 @@ void DXLabSuiteCommanderTransceiver::do_ptt (bool on)
|
||||
update_PTT (tx);
|
||||
if (tx != on)
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "rig failed to respond to PTT: " << on);
|
||||
CAT_ERROR ("rig failed to respond to PTT: " << on);
|
||||
throw error {tr ("DX Lab Suite Commander rig did not respond to PTT: ") + (on ? "ON" : "OFF")};
|
||||
}
|
||||
}
|
||||
@ -200,7 +204,7 @@ void DXLabSuiteCommanderTransceiver::do_ptt (bool on)
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::do_frequency (Frequency f, MODE m, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", f << state ());
|
||||
CAT_TRACE (f << state ());
|
||||
auto f_string = frequency_to_string (f);
|
||||
if (UNK != m && m != get_mode ())
|
||||
{
|
||||
@ -219,7 +223,7 @@ void DXLabSuiteCommanderTransceiver::do_frequency (Frequency f, MODE m, bool /*n
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::do_tx_frequency (Frequency tx, MODE mode, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", tx << state ());
|
||||
CAT_TRACE (tx << state ());
|
||||
if (tx)
|
||||
{
|
||||
auto f_string = frequency_to_string (tx);
|
||||
@ -240,7 +244,7 @@ void DXLabSuiteCommanderTransceiver::do_tx_frequency (Frequency tx, MODE mode, b
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::do_mode (MODE m)
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", m << state ());
|
||||
CAT_TRACE (m << state ());
|
||||
auto m_string = map_mode (m);
|
||||
auto params = ("<1:%1>" + m_string).arg (m_string.size ());
|
||||
simple_command (("<command:10>CmdSetMode<parameters:%1>" + params).arg (params.size ()));
|
||||
@ -249,13 +253,7 @@ void DXLabSuiteCommanderTransceiver::do_mode (MODE m)
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::do_poll ()
|
||||
{
|
||||
#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS
|
||||
bool quiet {false};
|
||||
#else
|
||||
bool quiet {true};
|
||||
#endif
|
||||
|
||||
auto reply = command_with_reply ("<command:10>CmdGetFreq<parameters:0>", quiet);
|
||||
auto reply = command_with_reply ("<command:10>CmdGetFreq<parameters:0>");
|
||||
if (0 == reply.indexOf ("<CmdFreq:"))
|
||||
{
|
||||
auto f = string_to_frequency (reply.mid (reply.indexOf ('>') + 1));
|
||||
@ -270,13 +268,13 @@ void DXLabSuiteCommanderTransceiver::do_poll ()
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "get frequency unexpected response" << reply);
|
||||
CAT_ERROR ("get frequency unexpected response" << reply);
|
||||
throw error {tr ("DX Lab Suite Commander didn't respond correctly polling frequency: ") + reply};
|
||||
}
|
||||
|
||||
if (state ().split ())
|
||||
{
|
||||
reply = command_with_reply ("<command:12>CmdGetTXFreq<parameters:0>", quiet);
|
||||
reply = command_with_reply ("<command:12>CmdGetTXFreq<parameters:0>");
|
||||
if (0 == reply.indexOf ("<CmdTXFreq:"))
|
||||
{
|
||||
auto f = string_to_frequency (reply.mid (reply.indexOf ('>') + 1));
|
||||
@ -291,12 +289,12 @@ void DXLabSuiteCommanderTransceiver::do_poll ()
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "get tx frequency unexpected response" << reply);
|
||||
CAT_ERROR ("get tx frequency unexpected response" << reply);
|
||||
throw error {tr ("DX Lab Suite Commander didn't respond correctly polling TX frequency: ") + reply};
|
||||
}
|
||||
}
|
||||
|
||||
reply = command_with_reply ("<command:12>CmdSendSplit<parameters:0>", quiet);
|
||||
reply = command_with_reply ("<command:12>CmdSendSplit<parameters:0>");
|
||||
if (0 == reply.indexOf ("<CmdSplit:"))
|
||||
{
|
||||
auto split = reply.mid (reply.indexOf ('>') + 1);
|
||||
@ -310,23 +308,23 @@ void DXLabSuiteCommanderTransceiver::do_poll ()
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "unexpected split state" << split);
|
||||
CAT_ERROR ("unexpected split state" << split);
|
||||
throw error {tr ("DX Lab Suite Commander sent an unrecognised split state: ") + split};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "get split mode unexpected response" << reply);
|
||||
CAT_ERROR ("get split mode unexpected response" << reply);
|
||||
throw error {tr ("DX Lab Suite Commander didn't respond correctly polling split status: ") + reply};
|
||||
}
|
||||
|
||||
get_mode (quiet);
|
||||
get_mode ();
|
||||
}
|
||||
|
||||
auto DXLabSuiteCommanderTransceiver::get_mode (bool no_debug) -> MODE
|
||||
auto DXLabSuiteCommanderTransceiver::get_mode () -> MODE
|
||||
{
|
||||
MODE m {UNK};
|
||||
auto reply = command_with_reply ("<command:11>CmdSendMode<parameters:0>", no_debug);
|
||||
auto reply = command_with_reply ("<command:11>CmdSendMode<parameters:0>");
|
||||
if (0 == reply.indexOf ("<CmdMode:"))
|
||||
{
|
||||
auto mode = reply.mid (reply.indexOf ('>') + 1);
|
||||
@ -372,42 +370,39 @@ auto DXLabSuiteCommanderTransceiver::get_mode (bool no_debug) -> MODE
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "unexpected mode name" << mode);
|
||||
CAT_ERROR ("unexpected mode name" << mode);
|
||||
throw error {tr ("DX Lab Suite Commander sent an unrecognised mode: \"") + mode + '"'};
|
||||
}
|
||||
update_mode (m);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "unexpected response" << reply);
|
||||
CAT_ERROR ("unexpected response" << reply);
|
||||
throw error {tr ("DX Lab Suite Commander didn't respond correctly polling mode: ") + reply};
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::simple_command (QString const& cmd, bool no_debug)
|
||||
void DXLabSuiteCommanderTransceiver::simple_command (QString const& cmd)
|
||||
{
|
||||
Q_ASSERT (commander_);
|
||||
|
||||
if (!no_debug)
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", cmd);
|
||||
}
|
||||
CAT_TRACE (cmd);
|
||||
|
||||
if (!write_to_port (cmd))
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "failed:" << commander_->errorString ());
|
||||
CAT_ERROR ("failed:" << commander_->errorString ());
|
||||
throw error {tr ("DX Lab Suite Commander send command failed\n") + commander_->errorString ()};
|
||||
}
|
||||
}
|
||||
|
||||
QString DXLabSuiteCommanderTransceiver::command_with_reply (QString const& cmd, bool no_debug)
|
||||
QString DXLabSuiteCommanderTransceiver::command_with_reply (QString const& cmd)
|
||||
{
|
||||
Q_ASSERT (commander_);
|
||||
|
||||
if (!write_to_port (cmd))
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "failed to send command:" << commander_->errorString ());
|
||||
CAT_ERROR ("failed to send command:" << commander_->errorString ());
|
||||
throw error {
|
||||
tr ("DX Lab Suite Commander send command failed \"%1\": %2\n")
|
||||
.arg (cmd)
|
||||
@ -424,7 +419,7 @@ QString DXLabSuiteCommanderTransceiver::command_with_reply (QString const& cmd,
|
||||
replied = commander_->waitForReadyRead ();
|
||||
if (!replied && commander_->error () != commander_->SocketTimeoutError)
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", cmd << "failed to read reply:" << commander_->errorString ());
|
||||
CAT_ERROR (cmd << "failed to read reply:" << commander_->errorString ());
|
||||
throw error {
|
||||
tr ("DX Lab Suite Commander send command \"%1\" read reply failed: %2\n")
|
||||
.arg (cmd)
|
||||
@ -435,7 +430,7 @@ QString DXLabSuiteCommanderTransceiver::command_with_reply (QString const& cmd,
|
||||
|
||||
if (!replied)
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", cmd << "retries exhausted");
|
||||
CAT_ERROR (cmd << "retries exhausted");
|
||||
throw error {
|
||||
tr ("DX Lab Suite Commander retries exhausted sending command \"%1\"")
|
||||
.arg (cmd)
|
||||
@ -449,11 +444,7 @@ QString DXLabSuiteCommanderTransceiver::command_with_reply (QString const& cmd,
|
||||
// qDebug () << i << ":" << hex << int (result[i]);
|
||||
// }
|
||||
|
||||
if (!no_debug)
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", cmd << "->" << result);
|
||||
}
|
||||
|
||||
CAT_TRACE (cmd << "->" << QString {result});
|
||||
return result; // converting raw UTF-8 bytes to QString
|
||||
}
|
||||
|
||||
|
||||
@ -24,10 +24,10 @@ class DXLabSuiteCommanderTransceiver final
|
||||
Q_OBJECT; // for translation context
|
||||
|
||||
public:
|
||||
static void register_transceivers (TransceiverFactory::Transceivers *, int id);
|
||||
static void register_transceivers (logger_type *, TransceiverFactory::Transceivers *, int id);
|
||||
|
||||
// takes ownership of wrapped Transceiver
|
||||
explicit DXLabSuiteCommanderTransceiver (std::unique_ptr<TransceiverBase> wrapped,
|
||||
explicit DXLabSuiteCommanderTransceiver (logger_type *, std::unique_ptr<TransceiverBase> wrapped,
|
||||
QString const& address, bool use_for_ptt,
|
||||
int poll_interval, QObject * parent = nullptr);
|
||||
|
||||
@ -42,9 +42,9 @@ protected:
|
||||
void do_poll () override;
|
||||
|
||||
private:
|
||||
MODE get_mode (bool no_debug = false);
|
||||
void simple_command (QString const&, bool no_debug = false);
|
||||
QString command_with_reply (QString const&, bool no_debug = false);
|
||||
MODE get_mode ();
|
||||
void simple_command (QString const&);
|
||||
QString command_with_reply (QString const&);
|
||||
bool write_to_port (QString const&);
|
||||
QString frequency_to_string (Frequency) const;
|
||||
Frequency string_to_frequency (QString) const;
|
||||
|
||||
@ -2,8 +2,10 @@
|
||||
|
||||
#include "moc_EmulateSplitTransceiver.cpp"
|
||||
|
||||
EmulateSplitTransceiver::EmulateSplitTransceiver (std::unique_ptr<Transceiver> wrapped, QObject * parent)
|
||||
: Transceiver {parent}
|
||||
EmulateSplitTransceiver::EmulateSplitTransceiver (logger_type * logger,
|
||||
std::unique_ptr<Transceiver> wrapped,
|
||||
QObject * parent)
|
||||
: Transceiver {logger, parent}
|
||||
, wrapped_ {std::move (wrapped)}
|
||||
, rx_frequency_ {0}
|
||||
, tx_frequency_ {0}
|
||||
|
||||
@ -31,7 +31,8 @@ class EmulateSplitTransceiver final
|
||||
|
||||
public:
|
||||
// takes ownership of wrapped Transceiver
|
||||
explicit EmulateSplitTransceiver (std::unique_ptr<Transceiver> wrapped,
|
||||
explicit EmulateSplitTransceiver (logger_type *,
|
||||
std::unique_ptr<Transceiver> wrapped,
|
||||
QObject * parent = nullptr);
|
||||
|
||||
void set (TransceiverState const&,
|
||||
|
||||
@ -23,7 +23,9 @@ namespace
|
||||
|
||||
#include "moc_HRDTransceiver.cpp"
|
||||
|
||||
void HRDTransceiver::register_transceivers (TransceiverFactory::Transceivers * registry, int id)
|
||||
void HRDTransceiver::register_transceivers (logger_type *,
|
||||
TransceiverFactory::Transceivers * registry,
|
||||
int id)
|
||||
{
|
||||
(*registry)[HRD_transceiver_name] = TransceiverFactory::Capabilities (id, TransceiverFactory::Capabilities::network, true, true /* maybe */);
|
||||
}
|
||||
@ -70,13 +72,14 @@ struct HRDMessage
|
||||
static qint32 constexpr magic_2_value_ = 0xABCD1234;
|
||||
};
|
||||
|
||||
HRDTransceiver::HRDTransceiver (std::unique_ptr<TransceiverBase> wrapped
|
||||
HRDTransceiver::HRDTransceiver (logger_type * logger
|
||||
, std::unique_ptr<TransceiverBase> wrapped
|
||||
, QString const& server
|
||||
, bool use_for_ptt
|
||||
, TransceiverFactory::TXAudioSource audio_source
|
||||
, int poll_interval
|
||||
, QObject * parent)
|
||||
: PollingTransceiver {poll_interval, parent}
|
||||
: PollingTransceiver {logger, poll_interval, parent}
|
||||
, wrapped_ {std::move (wrapped)}
|
||||
, use_for_ptt_ {use_for_ptt}
|
||||
, audio_source_ {audio_source}
|
||||
@ -111,7 +114,7 @@ HRDTransceiver::HRDTransceiver (std::unique_ptr<TransceiverBase> wrapped
|
||||
|
||||
int HRDTransceiver::do_start ()
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", "starting");
|
||||
CAT_TRACE ("starting");
|
||||
if (wrapped_) wrapped_->start (0);
|
||||
|
||||
auto server_details = network_server_lookup (server_, 7809u);
|
||||
@ -122,7 +125,7 @@ int HRDTransceiver::do_start ()
|
||||
hrd_->connectToHost (std::get<0> (server_details), std::get<1> (server_details));
|
||||
if (!hrd_->waitForConnected ())
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", "failed to connect:" << hrd_->errorString ());
|
||||
CAT_ERROR ("failed to connect:" << hrd_->errorString ());
|
||||
throw error {tr ("Failed to connect to Ham Radio Deluxe\n") + hrd_->errorString ()};
|
||||
}
|
||||
|
||||
@ -147,7 +150,7 @@ int HRDTransceiver::do_start ()
|
||||
hrd_->connectToHost (std::get<0> (server_details), std::get<1> (server_details));
|
||||
if (!hrd_->waitForConnected ())
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", "failed to connect:" << hrd_->errorString ());
|
||||
CAT_ERROR ("failed to connect:" << hrd_->errorString ());
|
||||
throw error {tr ("Failed to connect to Ham Radio Deluxe\n") + hrd_->errorString ()};
|
||||
}
|
||||
|
||||
@ -164,14 +167,14 @@ int HRDTransceiver::do_start ()
|
||||
auto id = send_command ("get id", false, false);
|
||||
auto version = send_command ("get version", false, false);
|
||||
|
||||
TRACE_CAT ("HRDTransceiver", "Id:" << id << "Version:" << version);
|
||||
CAT_INFO ("Id: " << id << "Version: " << version);
|
||||
HRD_info << "Id: " << id << "\n";
|
||||
HRD_info << "Version: " << version << "\n";
|
||||
|
||||
auto radios = send_command ("get radios", false, false).trimmed ().split (',', SkipEmptyParts);
|
||||
if (radios.isEmpty ())
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", "no rig found");
|
||||
CAT_ERROR ("no rig found");
|
||||
throw error {tr ("Ham Radio Deluxe: no rig found")};
|
||||
}
|
||||
|
||||
@ -183,48 +186,46 @@ int HRDTransceiver::do_start ()
|
||||
radios_.push_back (std::forward_as_tuple (entries[0].toUInt (), entries[1]));
|
||||
}
|
||||
|
||||
#if WSJT_TRACE_CAT
|
||||
TRACE_CAT ("HRDTransceiver", "radios:-");
|
||||
CAT_TRACE ("radios:-");
|
||||
Q_FOREACH (auto const& radio, radios_)
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", "\t[" << std::get<0> (radio) << "] " << std::get<1> (radio));
|
||||
CAT_TRACE ("\t[" << std::get<0> (radio) << "] " << std::get<1> (radio));
|
||||
}
|
||||
#endif
|
||||
|
||||
auto current_radio_name = send_command ("get radio", false, false, true);
|
||||
auto current_radio_name = send_command ("get radio", false, false);
|
||||
HRD_info << "Current radio: " << current_radio_name << "\n";
|
||||
if (current_radio_name.isEmpty ())
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", "no rig found");
|
||||
CAT_ERROR ("no rig found");
|
||||
throw error {tr ("Ham Radio Deluxe: no rig found")};
|
||||
}
|
||||
|
||||
vfo_count_ = send_command ("get vfo-count").toUInt ();
|
||||
HRD_info << "VFO count: " << vfo_count_ << "\n";
|
||||
TRACE_CAT ("HRDTransceiver", "vfo count:" << vfo_count_);
|
||||
CAT_TRACE ("vfo count:" << vfo_count_);
|
||||
|
||||
buttons_ = send_command ("get buttons").trimmed ().split (',', SkipEmptyParts).replaceInStrings (" ", "~");
|
||||
TRACE_CAT ("HRDTransceiver", "HRD Buttons: " << buttons_);
|
||||
CAT_TRACE ("HRD Buttons: " << buttons_.join (", "));
|
||||
HRD_info << "Buttons: {" << buttons_.join (", ") << "}\n";
|
||||
|
||||
dropdown_names_ = send_command ("get dropdowns").trimmed ().split (',', SkipEmptyParts);
|
||||
TRACE_CAT ("HRDTransceiver", "Dropdowns:");
|
||||
CAT_TRACE ("Dropdowns:");
|
||||
HRD_info << "Dropdowns:\n";
|
||||
Q_FOREACH (auto const& dd, dropdown_names_)
|
||||
{
|
||||
auto selections = send_command ("get dropdown-list {" + dd + "}").trimmed ().split (',');
|
||||
TRACE_CAT ("HRDTransceiver", "\t" << dd << ": {" << selections.join (", ") << "}");
|
||||
CAT_TRACE ("\t" << dd << ": {" << selections.join (", ") << "}");
|
||||
HRD_info << "\t" << dd << ": {" << selections.join (", ") << "}\n";
|
||||
dropdowns_[dd] = selections;
|
||||
}
|
||||
|
||||
slider_names_ = send_command ("get sliders").trimmed ().split (',', SkipEmptyParts).replaceInStrings (" ", "~");
|
||||
TRACE_CAT ("HRDTransceiver", "Sliders:-");
|
||||
CAT_TRACE ("Sliders:-");
|
||||
HRD_info << "Sliders:\n";
|
||||
Q_FOREACH (auto const& s, slider_names_)
|
||||
{
|
||||
auto range = send_command ("get slider-range " + current_radio_name + " " + s).trimmed ().split (',', SkipEmptyParts);
|
||||
TRACE_CAT ("HRDTransceiver", "\t" << s << ": {" << range.join (", ") << "}");
|
||||
CAT_TRACE ("\t" << s << ": {" << range.join (", ") << "}");
|
||||
HRD_info << "\t" << s << ": {" << range.join (", ") << "}\n";
|
||||
sliders_[s] = range;
|
||||
}
|
||||
@ -358,7 +359,7 @@ void HRDTransceiver::do_stop ()
|
||||
}
|
||||
|
||||
if (wrapped_) wrapped_->stop ();
|
||||
TRACE_CAT ("HRDTransceiver", "stopped" << state () << "reversed" << reversed_);
|
||||
CAT_TRACE ("stopped" << state () << "reversed" << reversed_);
|
||||
}
|
||||
|
||||
int HRDTransceiver::find_button (QRegExp const& re) const
|
||||
@ -405,14 +406,12 @@ void HRDTransceiver::map_modes (int dropdown, ModeMap *map)
|
||||
map->push_back (std::forward_as_tuple (FM, find_dropdown_selection (dropdown, QRegExp ("^(FM|FM\\(N\\)|FM-N|WFM)$"))));
|
||||
map->push_back (std::forward_as_tuple (DIG_FM, find_dropdown_selection (dropdown, QRegExp ("^(PKT-FM|PKT|DATA\\(FM\\)|FM)$"))));
|
||||
|
||||
#if WSJT_TRACE_CAT
|
||||
TRACE_CAT ("HRDTransceiver", "for dropdown" << dropdown_names_[dropdown]);
|
||||
CAT_TRACE ("for dropdown" << dropdown_names_[dropdown]);
|
||||
std::for_each (map->begin (), map->end (), [this, dropdown] (ModeMap::value_type const& item)
|
||||
{
|
||||
auto const& rhs = std::get<1> (item);
|
||||
TRACE_CAT ("HRDTransceiver", '\t' << std::get<0> (item) << "<->" << (rhs.size () ? dropdowns_[dropdown_names_[dropdown]][rhs.front ()] : "None"));
|
||||
CAT_TRACE ('\t' << std::get<0> (item) << "<->" << (rhs.size () ? dropdowns_[dropdown_names_[dropdown]][rhs.front ()] : "None"));
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
int HRDTransceiver::lookup_mode (MODE mode, ModeMap const& map) const
|
||||
@ -444,7 +443,7 @@ auto HRDTransceiver::lookup_mode (int mode, ModeMap const& map) const -> MODE
|
||||
return std::get<0> (*it);
|
||||
}
|
||||
|
||||
int HRDTransceiver::get_dropdown (int dd, bool no_debug)
|
||||
int HRDTransceiver::get_dropdown (int dd)
|
||||
{
|
||||
if (dd < 0)
|
||||
{
|
||||
@ -452,7 +451,7 @@ int HRDTransceiver::get_dropdown (int dd, bool no_debug)
|
||||
}
|
||||
|
||||
auto dd_name = dropdown_names_.value (dd);
|
||||
auto reply = send_command ("get dropdown-text {" + dd_name + "}", no_debug);
|
||||
auto reply = send_command ("get dropdown-text {" + dd_name + "}");
|
||||
auto colon_index = reply.indexOf (':');
|
||||
|
||||
if (colon_index < 0)
|
||||
@ -473,14 +472,14 @@ void HRDTransceiver::set_dropdown (int dd, int value)
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", "item" << value << "not found in" << dd_name);
|
||||
CAT_ERROR ("item" << value << "not found in" << dd_name);
|
||||
throw error {tr ("Ham Radio Deluxe: item not found in %1 dropdown list").arg (dd_name)};
|
||||
}
|
||||
}
|
||||
|
||||
void HRDTransceiver::do_ptt (bool on)
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", on);
|
||||
CAT_TRACE (on);
|
||||
if (use_for_ptt_)
|
||||
{
|
||||
if (alt_ptt_button_ >= 0 && TransceiverFactory::TX_audio_source_rear == audio_source_)
|
||||
@ -517,7 +516,7 @@ void HRDTransceiver::set_button (int button_index, bool checked)
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", "invalid button");
|
||||
CAT_ERROR ("invalid button");
|
||||
throw error {tr ("Ham Radio Deluxe: button not available")};
|
||||
}
|
||||
}
|
||||
@ -570,12 +569,12 @@ void HRDTransceiver::set_data_mode (MODE m)
|
||||
}
|
||||
}
|
||||
|
||||
auto HRDTransceiver::get_data_mode (MODE m, bool quiet) -> MODE
|
||||
auto HRDTransceiver::get_data_mode (MODE m) -> MODE
|
||||
{
|
||||
if (data_mode_dropdown_ >= 0
|
||||
&& data_mode_dropdown_selection_off_.size ())
|
||||
{
|
||||
auto selection = get_dropdown (data_mode_dropdown_, quiet);
|
||||
auto selection = get_dropdown (data_mode_dropdown_);
|
||||
// can't check for on here as there may be multiple on values so
|
||||
// we must rely on the initial parse finding valid on values
|
||||
if (selection >= 0 && selection != data_mode_dropdown_selection_off_.front ())
|
||||
@ -594,7 +593,7 @@ auto HRDTransceiver::get_data_mode (MODE m, bool quiet) -> MODE
|
||||
|
||||
void HRDTransceiver::do_frequency (Frequency f, MODE m, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", f << "reversed" << reversed_);
|
||||
CAT_TRACE (f << "reversed" << reversed_);
|
||||
if (UNK != m)
|
||||
{
|
||||
do_mode (m);
|
||||
@ -614,7 +613,7 @@ void HRDTransceiver::do_frequency (Frequency f, MODE m, bool /*no_ignore*/)
|
||||
|
||||
void HRDTransceiver::do_tx_frequency (Frequency tx, MODE mode, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", tx << "reversed" << reversed_);
|
||||
CAT_TRACE (tx << "reversed" << reversed_);
|
||||
|
||||
// re-check if reversed VFOs
|
||||
bool rx_A {true};
|
||||
@ -781,7 +780,7 @@ void HRDTransceiver::do_tx_frequency (Frequency tx, MODE mode, bool /*no_ignore*
|
||||
|
||||
void HRDTransceiver::do_mode (MODE mode)
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", mode);
|
||||
CAT_TRACE (mode);
|
||||
if (reversed_ && mode_B_dropdown_ >= 0)
|
||||
{
|
||||
set_dropdown (mode_B_dropdown_, lookup_mode (mode, mode_B_map_));
|
||||
@ -873,17 +872,17 @@ void HRDTransceiver::do_mode (MODE mode)
|
||||
update_mode (mode);
|
||||
}
|
||||
|
||||
bool HRDTransceiver::is_button_checked (int button_index, bool no_debug)
|
||||
bool HRDTransceiver::is_button_checked (int button_index)
|
||||
{
|
||||
if (button_index < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto reply = send_command ("get button-select " + buttons_.value (button_index), no_debug);
|
||||
auto reply = send_command ("get button-select " + buttons_.value (button_index));
|
||||
if ("1" != reply && "0" != reply)
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", "bad response");
|
||||
CAT_ERROR ("bad response");
|
||||
throw error {tr ("Ham Radio Deluxe didn't respond as expected")};
|
||||
}
|
||||
return "1" == reply;
|
||||
@ -891,10 +890,8 @@ bool HRDTransceiver::is_button_checked (int button_index, bool no_debug)
|
||||
|
||||
void HRDTransceiver::do_poll ()
|
||||
{
|
||||
#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS
|
||||
bool quiet {false};
|
||||
qDebug () << "+++++++ poll dump +++++++";
|
||||
qDebug () << "reversed:" << reversed_;
|
||||
CAT_TRACE ("+++++++ poll dump +++++++");
|
||||
CAT_TRACE ("reversed:" << reversed_);
|
||||
is_button_checked (vfo_A_button_);
|
||||
is_button_checked (vfo_B_button_);
|
||||
is_button_checked (vfo_toggle_button_);
|
||||
@ -922,10 +919,7 @@ void HRDTransceiver::do_poll ()
|
||||
{
|
||||
get_dropdown (split_mode_dropdown_);
|
||||
}
|
||||
qDebug () << "------- poll dump -------";
|
||||
#else
|
||||
bool quiet {true};
|
||||
#endif
|
||||
CAT_TRACE ("------- poll dump -------");
|
||||
|
||||
if (split_off_button_ >= 0)
|
||||
{
|
||||
@ -933,13 +927,13 @@ void HRDTransceiver::do_poll ()
|
||||
}
|
||||
else if (split_mode_button_ >= 0 && !(tx_A_button_ >= 0 && tx_B_button_ >= 0))
|
||||
{
|
||||
update_split (is_button_checked (split_mode_button_, quiet));
|
||||
update_split (is_button_checked (split_mode_button_));
|
||||
}
|
||||
else if (split_mode_dropdown_ >= 0)
|
||||
{
|
||||
if (!split_mode_dropdown_write_only_)
|
||||
{
|
||||
auto selection = get_dropdown (split_mode_dropdown_, quiet);
|
||||
auto selection = get_dropdown (split_mode_dropdown_);
|
||||
if (selection >= 0
|
||||
&& split_mode_dropdown_selection_off_.size ())
|
||||
{
|
||||
@ -958,7 +952,7 @@ void HRDTransceiver::do_poll ()
|
||||
bool rx_A {true}; // no Rx taken as not reversed
|
||||
bool rx_B {false};
|
||||
|
||||
auto tx_A = is_button_checked (tx_A_button_, quiet);
|
||||
auto tx_A = is_button_checked (tx_A_button_);
|
||||
|
||||
// some rigs have dual Rx, we take VFO A/MAIN receiving as
|
||||
// normal and only say reversed when only VFO B/SUB is active
|
||||
@ -974,10 +968,10 @@ void HRDTransceiver::do_poll ()
|
||||
}
|
||||
else if (vfo_B_button_ >= 0 || rx_B_button_ >= 0)
|
||||
{
|
||||
rx_A = is_button_checked (rx_A_button_ >= 0 ? rx_A_button_ : vfo_A_button_, quiet);
|
||||
rx_A = is_button_checked (rx_A_button_ >= 0 ? rx_A_button_ : vfo_A_button_);
|
||||
if (!rx_A)
|
||||
{
|
||||
rx_B = is_button_checked (rx_B_button_ >= 0 ? rx_B_button_ : vfo_B_button_, quiet);
|
||||
rx_B = is_button_checked (rx_B_button_ >= 0 ? rx_B_button_ : vfo_B_button_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -987,7 +981,7 @@ void HRDTransceiver::do_poll ()
|
||||
|
||||
if (vfo_count_ > 1)
|
||||
{
|
||||
auto frequencies = send_command ("get frequencies", quiet).trimmed ().split ('-', SkipEmptyParts);
|
||||
auto frequencies = send_command ("get frequencies").trimmed ().split ('-', SkipEmptyParts);
|
||||
update_rx_frequency (frequencies[reversed_ ? 1 : 0].toUInt ());
|
||||
update_other_frequency (frequencies[reversed_ ? 0 : 1].toUInt ());
|
||||
}
|
||||
@ -997,7 +991,7 @@ void HRDTransceiver::do_poll ()
|
||||
// while transmitting
|
||||
if (!state ().ptt ())
|
||||
{
|
||||
update_rx_frequency (send_command ("get frequency", quiet).toUInt ());
|
||||
update_rx_frequency (send_command ("get frequency").toUInt ());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1005,11 +999,11 @@ void HRDTransceiver::do_poll ()
|
||||
// transmitting
|
||||
if (vfo_count_ > 1 || !state ().ptt ())
|
||||
{
|
||||
update_mode (get_data_mode (lookup_mode (get_dropdown (mode_A_dropdown_, quiet), mode_A_map_), quiet));
|
||||
update_mode (get_data_mode (lookup_mode (get_dropdown (mode_A_dropdown_), mode_A_map_)));
|
||||
}
|
||||
}
|
||||
|
||||
QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool prepend_context, bool recurse)
|
||||
QString HRDTransceiver::send_command (QString const& cmd, bool prepend_context, bool recurse)
|
||||
{
|
||||
Q_ASSERT (hrd_);
|
||||
|
||||
@ -1024,7 +1018,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
|
||||
if (!recurse && prepend_context)
|
||||
{
|
||||
auto radio_name = send_command ("get radio", true, current_radio_, true);
|
||||
auto radio_name = send_command ("get radio", current_radio_, true);
|
||||
qDebug () << "HRDTransceiver::send_command: radio_name:" << radio_name;
|
||||
auto radio_iter = std::find_if (radios_.begin (), radios_.end (), [&radio_name] (RadioMap::value_type const& radio)
|
||||
{
|
||||
@ -1032,7 +1026,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
});
|
||||
if (radio_iter == radios_.end ())
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", "rig disappeared or changed");
|
||||
CAT_TRACE ("rig disappeared or changed");
|
||||
throw error {tr ("Ham Radio Deluxe: rig has disappeared or changed")};
|
||||
}
|
||||
|
||||
@ -1046,7 +1040,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
|
||||
if (QTcpSocket::ConnectedState != hrd_->state ())
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", cmd << "failed" << hrd_->errorString ());
|
||||
CAT_ERROR (cmd << "failed" << hrd_->errorString ());
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe send command \"%1\" failed %2\n")
|
||||
.arg (cmd)
|
||||
@ -1059,7 +1053,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
auto message = ((prepend_context ? context + cmd : cmd) + "\r").toLocal8Bit ();
|
||||
if (!write_to_port (message.constData (), message.size ()))
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", "failed to write command" << cmd << "to HRD");
|
||||
CAT_ERROR ("failed to write command" << cmd << "to HRD");
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe: failed to write command \"%1\"")
|
||||
.arg (cmd)
|
||||
@ -1072,7 +1066,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
QScopedPointer<HRDMessage> message {new (string) HRDMessage};
|
||||
if (!write_to_port (reinterpret_cast<char const *> (message.data ()), message->size_))
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", "failed to write command" << cmd << "to HRD");
|
||||
CAT_ERROR ("failed to write command" << cmd << "to HRD");
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe: failed to write command \"%1\"")
|
||||
.arg (cmd)
|
||||
@ -1089,7 +1083,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
HRDMessage const * reply {new (buffer) HRDMessage};
|
||||
if (reply->magic_1_value_ != reply->magic_1_ && reply->magic_2_value_ != reply->magic_2_)
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", cmd << "invalid reply");
|
||||
CAT_ERROR (cmd << "invalid reply");
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe sent an invalid reply to our command \"%1\"")
|
||||
.arg (cmd)
|
||||
@ -1099,20 +1093,14 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
// keep reading until expected size arrives
|
||||
while (buffer.size () - offsetof (HRDMessage, size_) < reply->size_)
|
||||
{
|
||||
if (!no_debug)
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", cmd << "reading more reply data");
|
||||
}
|
||||
CAT_TRACE (cmd << "reading more reply data");
|
||||
buffer += read_reply (cmd);
|
||||
reply = new (buffer) HRDMessage;
|
||||
}
|
||||
|
||||
result = QString {reply->payload_}; // this is not a memory leak (honest!)
|
||||
}
|
||||
if (!no_debug)
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", cmd << " ->" << result);
|
||||
}
|
||||
CAT_TRACE (cmd << " ->" << result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1143,7 +1131,7 @@ QByteArray HRDTransceiver::read_reply (QString const& cmd)
|
||||
replied = hrd_->waitForReadyRead ();
|
||||
if (!replied && hrd_->error () != hrd_->SocketTimeoutError)
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", cmd << "failed to reply" << hrd_->errorString ());
|
||||
CAT_ERROR (cmd << "failed to reply" << hrd_->errorString ());
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe failed to reply to command \"%1\" %2\n")
|
||||
.arg (cmd)
|
||||
@ -1153,7 +1141,7 @@ QByteArray HRDTransceiver::read_reply (QString const& cmd)
|
||||
}
|
||||
if (!replied)
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", cmd << "retries exhausted");
|
||||
CAT_ERROR (cmd << "retries exhausted");
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe retries exhausted sending command \"%1\"")
|
||||
.arg (cmd)
|
||||
@ -1162,11 +1150,11 @@ QByteArray HRDTransceiver::read_reply (QString const& cmd)
|
||||
return hrd_->readAll ();
|
||||
}
|
||||
|
||||
void HRDTransceiver::send_simple_command (QString const& command, bool no_debug)
|
||||
void HRDTransceiver::send_simple_command (QString const& command)
|
||||
{
|
||||
if ("OK" != send_command (command, no_debug))
|
||||
if ("OK" != send_command (command))
|
||||
{
|
||||
TRACE_CAT ("HRDTransceiver", command << "unexpected response");
|
||||
CAT_ERROR (command << "unexpected response");
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe didn't respond to command \"%1\" as expected")
|
||||
.arg (command)
|
||||
|
||||
@ -30,10 +30,11 @@ class HRDTransceiver final
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static void register_transceivers (TransceiverFactory::Transceivers *, int id);
|
||||
static void register_transceivers (logger_type *, TransceiverFactory::Transceivers *, int id);
|
||||
|
||||
// takes ownership of wrapped Transceiver
|
||||
explicit HRDTransceiver (std::unique_ptr<TransceiverBase> wrapped
|
||||
explicit HRDTransceiver (logger_type *
|
||||
, std::unique_ptr<TransceiverBase> wrapped
|
||||
, QString const& server
|
||||
, bool use_for_ptt
|
||||
, TransceiverFactory::TXAudioSource
|
||||
@ -53,17 +54,17 @@ protected:
|
||||
void do_poll () override;
|
||||
|
||||
private:
|
||||
QString send_command (QString const&, bool no_debug = false, bool prepend_context = true, bool recurse = false);
|
||||
QString send_command (QString const&, bool prepend_context = true, bool recurse = false);
|
||||
QByteArray read_reply (QString const& command);
|
||||
void send_simple_command (QString const&, bool no_debug = false);
|
||||
void send_simple_command (QString const&);
|
||||
bool write_to_port (char const *, qint64 length);
|
||||
int find_button (QRegExp const&) const;
|
||||
int find_dropdown (QRegExp const&) const;
|
||||
std::vector<int> find_dropdown_selection (int dropdown, QRegExp const&) const;
|
||||
int get_dropdown (int, bool no_debug = false);
|
||||
int get_dropdown (int);
|
||||
void set_dropdown (int, int);
|
||||
void set_button (int button_index, bool checked = true);
|
||||
bool is_button_checked (int button_index, bool no_debug = false);
|
||||
bool is_button_checked (int button_index);
|
||||
|
||||
// This dictionary type maps Transceiver::MODE to a list of mode
|
||||
// drop down selection indexes that equate to that mode. It is used
|
||||
@ -75,7 +76,7 @@ private:
|
||||
int lookup_mode (MODE, ModeMap const&) const;
|
||||
MODE lookup_mode (int, ModeMap const&) const;
|
||||
void set_data_mode (MODE);
|
||||
MODE get_data_mode (MODE, bool no_debug = false);
|
||||
MODE get_data_mode (MODE);
|
||||
|
||||
// An alternate TransceiverBase instance that can be used to drive
|
||||
// PTT if required.
|
||||
|
||||
@ -34,35 +34,6 @@ namespace
|
||||
// As an ultimate workaround make sure the user always has the
|
||||
// option to skip mode setting altogether.
|
||||
|
||||
// reroute Hamlib diagnostic messages to Qt
|
||||
int debug_callback (enum rig_debug_level_e level, rig_ptr_t /* arg */, char const * format, va_list ap)
|
||||
{
|
||||
QString message;
|
||||
static char constexpr fmt[] = "Hamlib: %s";
|
||||
message = message.vasprintf (format, ap).trimmed ();
|
||||
|
||||
switch (level)
|
||||
{
|
||||
case RIG_DEBUG_BUG:
|
||||
qFatal (fmt, message.toLocal8Bit ().data ());
|
||||
break;
|
||||
|
||||
case RIG_DEBUG_ERR:
|
||||
qCritical (fmt, message.toLocal8Bit ().data ());
|
||||
break;
|
||||
|
||||
case RIG_DEBUG_WARN:
|
||||
qWarning (fmt, message.toLocal8Bit ().data ());
|
||||
break;
|
||||
|
||||
default:
|
||||
qDebug (fmt, message.toLocal8Bit ().data ());
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// callback function that receives transceiver capabilities from the
|
||||
// hamlib libraries
|
||||
int register_callback (rig_caps const * caps, void * callback_data)
|
||||
@ -161,22 +132,35 @@ namespace
|
||||
freq_t HamlibTransceiver::dummy_frequency_;
|
||||
rmode_t HamlibTransceiver::dummy_mode_ {RIG_MODE_NONE};
|
||||
|
||||
void HamlibTransceiver::register_transceivers (TransceiverFactory::Transceivers * registry)
|
||||
// reroute Hamlib diagnostic messages to Qt
|
||||
int HamlibTransceiver::debug_callback (enum rig_debug_level_e level, rig_ptr_t arg, char const * format, va_list ap)
|
||||
{
|
||||
rig_set_debug_callback (debug_callback, nullptr);
|
||||
auto logger = reinterpret_cast<logger_type *> (arg);
|
||||
auto message = QString::vasprintf (format, ap);
|
||||
va_end (ap);
|
||||
auto severity = boost::log::trivial::trace;
|
||||
switch (level)
|
||||
{
|
||||
case RIG_DEBUG_BUG: severity = boost::log::trivial::fatal; break;
|
||||
case RIG_DEBUG_ERR: severity = boost::log::trivial::error; break;
|
||||
case RIG_DEBUG_WARN: severity = boost::log::trivial::warning; break;
|
||||
case RIG_DEBUG_VERBOSE: severity = boost::log::trivial::debug; break;
|
||||
case RIG_DEBUG_TRACE: severity = boost::log::trivial::trace; break;
|
||||
default: break;
|
||||
};
|
||||
if (level != RIG_DEBUG_NONE) // no idea what level NONE means so
|
||||
// ignore it
|
||||
{
|
||||
BOOST_LOG_SEV (*logger, severity) << message.trimmed ().toStdString ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if WSJT_HAMLIB_TRACE
|
||||
#if WSJT_HAMLIB_VERBOSE_TRACE
|
||||
void HamlibTransceiver::register_transceivers (logger_type * logger,
|
||||
TransceiverFactory::Transceivers * registry)
|
||||
{
|
||||
rig_set_debug_callback (debug_callback, logger);
|
||||
rig_set_debug (RIG_DEBUG_TRACE);
|
||||
#else
|
||||
rig_set_debug (RIG_DEBUG_VERBOSE);
|
||||
#endif
|
||||
#elif defined (NDEBUG)
|
||||
rig_set_debug (RIG_DEBUG_ERR);
|
||||
#else
|
||||
rig_set_debug (RIG_DEBUG_WARN);
|
||||
#endif
|
||||
|
||||
rig_load_all_backends ();
|
||||
rig_list_foreach (register_callback, registry);
|
||||
}
|
||||
@ -195,9 +179,10 @@ void HamlibTransceiver::RIGDeleter::cleanup (RIG * rig)
|
||||
}
|
||||
}
|
||||
|
||||
HamlibTransceiver::HamlibTransceiver (TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port,
|
||||
HamlibTransceiver::HamlibTransceiver (logger_type * logger,
|
||||
TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port,
|
||||
QObject * parent)
|
||||
: PollingTransceiver {0, parent}
|
||||
: PollingTransceiver {logger, 0, parent}
|
||||
, rig_ {rig_init (RIG_MODEL_DUMMY)}
|
||||
, ptt_only_ {true}
|
||||
, back_ptt_port_ {false}
|
||||
@ -249,9 +234,11 @@ HamlibTransceiver::HamlibTransceiver (TransceiverFactory::PTTMethod ptt_type, QS
|
||||
}
|
||||
}
|
||||
|
||||
HamlibTransceiver::HamlibTransceiver (int model_number, TransceiverFactory::ParameterPack const& params,
|
||||
HamlibTransceiver::HamlibTransceiver (logger_type * logger,
|
||||
int model_number,
|
||||
TransceiverFactory::ParameterPack const& params,
|
||||
QObject * parent)
|
||||
: PollingTransceiver {params.poll_interval, parent}
|
||||
: PollingTransceiver {logger, params.poll_interval, parent}
|
||||
, rig_ {rig_init (model_number)}
|
||||
, ptt_only_ {false}
|
||||
, back_ptt_port_ {TransceiverFactory::TX_audio_source_rear == params.audio_source}
|
||||
@ -272,53 +259,53 @@ HamlibTransceiver::HamlibTransceiver (int model_number, TransceiverFactory::Para
|
||||
|
||||
// rig_->state.obj = this;
|
||||
|
||||
if (!is_dummy_)
|
||||
//
|
||||
// user defined Hamlib settings
|
||||
//
|
||||
auto settings_file_name = QStandardPaths::locate (QStandardPaths::AppConfigLocation
|
||||
, "hamlib_settings.json");
|
||||
if (!settings_file_name.isEmpty ())
|
||||
{
|
||||
//
|
||||
// user defined Hamlib settings
|
||||
//
|
||||
auto settings_file_name = QStandardPaths::locate (QStandardPaths::AppConfigLocation
|
||||
, "hamlib_settings.json");
|
||||
if (!settings_file_name.isEmpty ())
|
||||
QFile settings_file {settings_file_name};
|
||||
qDebug () << "Using Hamlib settings file:" << settings_file_name;
|
||||
if (settings_file.open (QFile::ReadOnly))
|
||||
{
|
||||
QFile settings_file {settings_file_name};
|
||||
qDebug () << "Using Hamlib settings file:" << settings_file_name;
|
||||
if (settings_file.open (QFile::ReadOnly))
|
||||
QJsonParseError status;
|
||||
auto settings_doc = QJsonDocument::fromJson (settings_file.readAll (), &status);
|
||||
if (status.error)
|
||||
{
|
||||
QJsonParseError status;
|
||||
auto settings_doc = QJsonDocument::fromJson (settings_file.readAll (), &status);
|
||||
if (status.error)
|
||||
{
|
||||
throw error {tr ("Hamlib settings file error: %1 at character offset %2")
|
||||
.arg (status.errorString ()).arg (status.offset)};
|
||||
}
|
||||
qDebug () << "Hamlib settings JSON:" << settings_doc.toJson ();
|
||||
if (!settings_doc.isObject ())
|
||||
{
|
||||
throw error {tr ("Hamlib settings file error: top level must be a JSON object")};
|
||||
}
|
||||
auto const& settings = settings_doc.object ();
|
||||
throw error {tr ("Hamlib settings file error: %1 at character offset %2")
|
||||
.arg (status.errorString ()).arg (status.offset)};
|
||||
}
|
||||
qDebug () << "Hamlib settings JSON:" << settings_doc.toJson ();
|
||||
if (!settings_doc.isObject ())
|
||||
{
|
||||
throw error {tr ("Hamlib settings file error: top level must be a JSON object")};
|
||||
}
|
||||
auto const& settings = settings_doc.object ();
|
||||
|
||||
//
|
||||
// configuration settings
|
||||
//
|
||||
auto const& config = settings["config"];
|
||||
if (!config.isUndefined ())
|
||||
//
|
||||
// configuration settings
|
||||
//
|
||||
auto const& config = settings["config"];
|
||||
if (!config.isUndefined ())
|
||||
{
|
||||
if (!config.isObject ())
|
||||
{
|
||||
if (!config.isObject ())
|
||||
{
|
||||
throw error {tr ("Hamlib settings file error: config must be a JSON object")};
|
||||
}
|
||||
auto const& config_list = config.toObject ();
|
||||
for (auto item = config_list.constBegin (); item != config_list.constEnd (); ++item)
|
||||
{
|
||||
set_conf (item.key ().toLocal8Bit ().constData ()
|
||||
, (*item).toVariant ().toString ().toLocal8Bit ().constData ());
|
||||
}
|
||||
throw error {tr ("Hamlib settings file error: config must be a JSON object")};
|
||||
}
|
||||
auto const& config_list = config.toObject ();
|
||||
for (auto item = config_list.constBegin (); item != config_list.constEnd (); ++item)
|
||||
{
|
||||
set_conf (item.key ().toLocal8Bit ().constData ()
|
||||
, (*item).toVariant ().toString ().toLocal8Bit ().constData ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_dummy_)
|
||||
{
|
||||
switch (rig_->caps->port_type)
|
||||
{
|
||||
case RIG_PORT_SERIAL:
|
||||
@ -424,16 +411,15 @@ void HamlibTransceiver::error_check (int ret_code, QString const& doing) const
|
||||
{
|
||||
if (RIG_OK != ret_code)
|
||||
{
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "error:" << rigerror (ret_code));
|
||||
CAT_ERROR ("error: " << rigerror (ret_code));
|
||||
throw error {tr ("Hamlib error: %1 while %2").arg (rigerror (ret_code)).arg (doing)};
|
||||
}
|
||||
}
|
||||
|
||||
int HamlibTransceiver::do_start ()
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver",
|
||||
QString::fromLatin1 (rig_->caps->mfg_name).trimmed ()
|
||||
<< QString::fromLatin1 (rig_->caps->model_name).trimmed ());
|
||||
CAT_TRACE ("starting: " << rig_->caps->mfg_name
|
||||
<< ": " << rig_->caps->model_name);
|
||||
|
||||
error_check (rig_open (rig_.data ()), tr ("opening connection to rig"));
|
||||
|
||||
@ -484,25 +470,25 @@ int HamlibTransceiver::do_start ()
|
||||
// here. We also gather/set other initial state.
|
||||
error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &f1), tr ("getting current frequency"));
|
||||
f1 = std::round (f1);
|
||||
TRACE_CAT ("HamlibTransceiver", "current frequency =" << f1);
|
||||
CAT_TRACE ("current frequency=" << f1);
|
||||
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, &m, &w), tr ("getting current mode"));
|
||||
TRACE_CAT ("HamlibTransceiver", "current mode =" << rig_strrmode (m) << "bw =" << w);
|
||||
CAT_TRACE ("current mode=" << rig_strrmode (m) << " bw=" << w);
|
||||
|
||||
if (!rig_->caps->set_vfo)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_vfo_op TOGGLE");
|
||||
CAT_TRACE ("rig_vfo_op TOGGLE");
|
||||
rc = rig_vfo_op (rig_.data (), RIG_VFO_CURR, RIG_OP_TOGGLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_vfo to other VFO");
|
||||
CAT_TRACE ("rig_set_vfo to other VFO");
|
||||
rc = rig_set_vfo (rig_.data (), rig_->state.vfo_list & RIG_VFO_B ? RIG_VFO_B : RIG_VFO_SUB);
|
||||
if (-RIG_ENAVAIL == rc || -RIG_ENIMPL == rc)
|
||||
{
|
||||
// if we are talking to netrigctl then toggle VFO op
|
||||
// may still work
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_vfo_op TOGGLE");
|
||||
CAT_TRACE ("rig_vfo_op TOGGLE");
|
||||
rc = rig_vfo_op (rig_.data (), RIG_VFO_CURR, RIG_OP_TOGGLE);
|
||||
}
|
||||
}
|
||||
@ -525,21 +511,21 @@ int HamlibTransceiver::do_start ()
|
||||
// need to execute this block
|
||||
error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &f2), tr ("getting other VFO frequency"));
|
||||
f2 = std::round (f2);
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_freq other frequency =" << f2);
|
||||
CAT_TRACE ("rig_get_freq other frequency=" << f2);
|
||||
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, &mb, &wb), tr ("getting other VFO mode"));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode other mode =" << rig_strrmode (mb) << "bw =" << wb);
|
||||
CAT_TRACE ("rig_get_mode other mode=" << rig_strrmode (mb) << " bw=" << wb);
|
||||
|
||||
update_other_frequency (f2);
|
||||
|
||||
if (!rig_->caps->set_vfo)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_vfo_op TOGGLE");
|
||||
CAT_TRACE ("rig_vfo_op TOGGLE");
|
||||
error_check (rig_vfo_op (rig_.data (), RIG_VFO_CURR, RIG_OP_TOGGLE), tr ("exchanging VFOs"));
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_vfo A/MAIN");
|
||||
CAT_TRACE ("rig_set_vfo A/MAIN");
|
||||
error_check (rig_set_vfo (rig_.data (), rig_->state.vfo_list & RIG_VFO_A ? RIG_VFO_A : RIG_VFO_MAIN), tr ("setting current VFO"));
|
||||
}
|
||||
|
||||
@ -551,16 +537,16 @@ int HamlibTransceiver::do_start ()
|
||||
{
|
||||
error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &f1), tr ("getting frequency"));
|
||||
f1 = std::round (f1);
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_freq frequency =" << f1);
|
||||
CAT_TRACE ("rig_get_freq frequency=" << f1);
|
||||
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, &m, &w), tr ("getting mode"));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode mode =" << rig_strrmode (m) << "bw =" << w);
|
||||
CAT_TRACE ("rig_get_mode mode=" << rig_strrmode (m) << " bw=" << w);
|
||||
|
||||
update_rx_frequency (f1);
|
||||
}
|
||||
}
|
||||
|
||||
// TRACE_CAT ("HamlibTransceiver", "rig_set_split_vfo split off");
|
||||
// TRACE_CAT ("rig_set_split_vfo split off");
|
||||
// error_check (rig_set_split_vfo (rig_.data (), RIG_VFO_CURR, RIG_SPLIT_OFF, RIG_VFO_CURR), tr ("setting split off"));
|
||||
// update_split (false);
|
||||
}
|
||||
@ -571,7 +557,7 @@ int HamlibTransceiver::do_start ()
|
||||
if (get_vfo_works_ && rig_->caps->get_vfo)
|
||||
{
|
||||
error_check (rig_get_vfo (rig_.data (), &v), tr ("getting current VFO")); // has side effect of establishing current VFO inside hamlib
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_vfo current VFO = " << rig_strvfo (v));
|
||||
CAT_TRACE ("rig_get_vfo current VFO=" << rig_strvfo (v));
|
||||
}
|
||||
|
||||
reversed_ = RIG_VFO_B == v;
|
||||
@ -580,7 +566,7 @@ int HamlibTransceiver::do_start ()
|
||||
{
|
||||
if (RIG_OK == rig_get_mode (rig_.data (), RIG_VFO_CURR, &m, &w))
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode current mode =" << rig_strrmode (m) << "bw =" << w);
|
||||
CAT_TRACE ("rig_get_mode current mode=" << rig_strrmode (m) << " bw=" << w);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -588,7 +574,7 @@ int HamlibTransceiver::do_start ()
|
||||
// Some rigs (HDSDR) don't have a working way of
|
||||
// reporting MODE so we give up on mode queries -
|
||||
// sets will still cause an error
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode can't do on this rig");
|
||||
CAT_TRACE ("rig_get_mode can't do on this rig");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -664,7 +650,7 @@ int HamlibTransceiver::do_start ()
|
||||
|
||||
do_poll ();
|
||||
|
||||
TRACE_CAT ("HamlibTransceiver", "exit" << state () << "reversed =" << reversed_ << "resolution = " << resolution);
|
||||
CAT_TRACE ("finished start " << state () << " reversed=" << reversed_ << " resolution=" << resolution);
|
||||
return resolution;
|
||||
}
|
||||
|
||||
@ -685,7 +671,7 @@ void HamlibTransceiver::do_stop ()
|
||||
rig_close (rig_.data ());
|
||||
}
|
||||
|
||||
TRACE_CAT ("HamlibTransceiver", "state:" << state () << "reversed =" << reversed_);
|
||||
CAT_TRACE ("state: " << state () << " reversed=" << reversed_);
|
||||
}
|
||||
|
||||
std::tuple<vfo_t, vfo_t> HamlibTransceiver::get_vfos (bool for_split) const
|
||||
@ -694,7 +680,7 @@ std::tuple<vfo_t, vfo_t> HamlibTransceiver::get_vfos (bool for_split) const
|
||||
{
|
||||
vfo_t v;
|
||||
error_check (rig_get_vfo (rig_.data (), &v), tr ("getting current VFO")); // has side effect of establishing current VFO inside hamlib
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_vfo VFO = " << rig_strvfo (v));
|
||||
CAT_TRACE ("rig_get_vfo VFO=" << rig_strvfo (v));
|
||||
|
||||
reversed_ = RIG_VFO_B == v;
|
||||
}
|
||||
@ -704,7 +690,7 @@ std::tuple<vfo_t, vfo_t> HamlibTransceiver::get_vfos (bool for_split) const
|
||||
// frequency if split since these type of radios can only
|
||||
// support this way around
|
||||
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_vfo VFO = A/MAIN");
|
||||
CAT_TRACE ("rig_set_vfo VFO=A/MAIN");
|
||||
error_check (rig_set_vfo (rig_.data (), rig_->state.vfo_list & RIG_VFO_A ? RIG_VFO_A : RIG_VFO_MAIN), tr ("setting current VFO"));
|
||||
}
|
||||
// else only toggle available but VFOs should be substitutable
|
||||
@ -715,17 +701,17 @@ std::tuple<vfo_t, vfo_t> HamlibTransceiver::get_vfos (bool for_split) const
|
||||
: rx_vfo;
|
||||
if (reversed_)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "reversing VFOs");
|
||||
CAT_TRACE ("reversing VFOs");
|
||||
std::swap (rx_vfo, tx_vfo);
|
||||
}
|
||||
|
||||
TRACE_CAT ("HamlibTransceiver", "RX VFO = " << rig_strvfo (rx_vfo) << " TX VFO = " << rig_strvfo (tx_vfo));
|
||||
CAT_TRACE ("RX VFO=" << rig_strvfo (rx_vfo) << " TX VFO=" << rig_strvfo (tx_vfo));
|
||||
return std::make_tuple (rx_vfo, tx_vfo);
|
||||
}
|
||||
|
||||
void HamlibTransceiver::do_frequency (Frequency f, MODE m, bool no_ignore)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", f << "mode:" << m << "reversed:" << reversed_);
|
||||
CAT_TRACE ("f: " << f << " mode: " << m << " reversed: " << reversed_);
|
||||
|
||||
// only change when receiving or simplex or direct VFO addressing
|
||||
// unavailable or forced
|
||||
@ -742,11 +728,11 @@ void HamlibTransceiver::do_frequency (Frequency f, MODE m, bool no_ignore)
|
||||
pbwidth_t current_width;
|
||||
auto new_mode = map_mode (m);
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting current VFO mode"));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode mode = " << rig_strrmode (current_mode) << "bw =" << current_width);
|
||||
CAT_TRACE ("rig_get_mode mode=" << rig_strrmode (current_mode) << " bw=" << current_width);
|
||||
|
||||
if (new_mode != current_mode)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_mode mode = " << rig_strrmode (new_mode));
|
||||
CAT_TRACE ("rig_set_mode mode=" << rig_strrmode (new_mode));
|
||||
error_check (rig_set_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting current VFO mode"));
|
||||
|
||||
// for the 2nd time because a mode change may have caused a
|
||||
@ -755,7 +741,7 @@ void HamlibTransceiver::do_frequency (Frequency f, MODE m, bool no_ignore)
|
||||
|
||||
// for the second time because some rigs change mode according
|
||||
// to frequency such as the TS-2000 auto mode setting
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_mode mode = " << rig_strrmode (new_mode));
|
||||
CAT_TRACE ("rig_set_mode mode=" << rig_strrmode (new_mode));
|
||||
error_check (rig_set_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting current VFO mode"));
|
||||
}
|
||||
update_mode (m);
|
||||
@ -765,7 +751,7 @@ void HamlibTransceiver::do_frequency (Frequency f, MODE m, bool no_ignore)
|
||||
|
||||
void HamlibTransceiver::do_tx_frequency (Frequency tx, MODE mode, bool no_ignore)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", tx << "reversed:" << reversed_);
|
||||
CAT_TRACE ("txf: " << tx << " reversed: " << reversed_);
|
||||
|
||||
if (WSJT_RIG_NONE_CAN_SPLIT || !is_dummy_) // split is meaningless if you can't see it
|
||||
{
|
||||
@ -789,7 +775,7 @@ void HamlibTransceiver::do_tx_frequency (Frequency tx, MODE mode, bool no_ignore
|
||||
// much we can do since the Hamlib Library needs this
|
||||
// call at least once to establish the Tx VFO. Best we
|
||||
// can do is only do this once per session.
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_vfo split =" << split);
|
||||
CAT_TRACE ("rig_set_split_vfo split=" << split);
|
||||
auto rc = rig_set_split_vfo (rig_.data (), RIG_VFO_CURR, split, tx_vfo);
|
||||
if (tx || (-RIG_ENAVAIL != rc && -RIG_ENIMPL != rc))
|
||||
{
|
||||
@ -809,7 +795,7 @@ void HamlibTransceiver::do_tx_frequency (Frequency tx, MODE mode, bool no_ignore
|
||||
// addressing
|
||||
if (state ().ptt () && one_VFO_)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_vfo split =" << split);
|
||||
CAT_TRACE ("rig_set_split_vfo split=" << split);
|
||||
error_check (rig_set_split_vfo (rig_.data (), RIG_VFO_CURR, split, tx_vfo), tr ("setting split mode"));
|
||||
|
||||
error_check (rig_set_freq (rig_.data (), RIG_VFO_CURR, tx), tr ("setting frequency"));
|
||||
@ -820,11 +806,11 @@ void HamlibTransceiver::do_tx_frequency (Frequency tx, MODE mode, bool no_ignore
|
||||
pbwidth_t current_width;
|
||||
auto new_mode = map_mode (mode);
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting current VFO mode"));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode mode = " << rig_strrmode (current_mode) << "bw =" << current_width);
|
||||
CAT_TRACE ("rig_get_mode mode=" << rig_strrmode (current_mode) << " bw=" << current_width);
|
||||
|
||||
if (new_mode != current_mode)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_mode mode = " << rig_strrmode (new_mode));
|
||||
CAT_TRACE ("rig_set_mode mode=" << rig_strrmode (new_mode));
|
||||
error_check (rig_set_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting current VFO mode"));
|
||||
}
|
||||
}
|
||||
@ -836,20 +822,20 @@ void HamlibTransceiver::do_tx_frequency (Frequency tx, MODE mode, bool no_ignore
|
||||
if (UNK != mode)
|
||||
{
|
||||
auto new_mode = map_mode (mode);
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_freq_mode freq = " << tx
|
||||
CAT_TRACE ("rig_set_split_freq_mode freq=" << tx
|
||||
<< " mode = " << rig_strrmode (new_mode));
|
||||
error_check (rig_set_split_freq_mode (rig_.data (), RIG_VFO_CURR, tx, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting split TX frequency and mode"));
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_freq freq = " << tx);
|
||||
CAT_TRACE ("rig_set_split_freq freq=" << tx);
|
||||
error_check (rig_set_split_freq (rig_.data (), RIG_VFO_CURR, tx), tr ("setting split TX frequency"));
|
||||
}
|
||||
// Enable split last since some rigs (Kenwood for one) come out
|
||||
// of split when you switch RX VFO (to set split mode above for
|
||||
// example). Also the Elecraft K3 will refuse to go to split
|
||||
// with certain VFO A/B mode combinations.
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_vfo split =" << split);
|
||||
CAT_TRACE ("rig_set_split_vfo split=" << split);
|
||||
error_check (rig_set_split_vfo (rig_.data (), RIG_VFO_CURR, split, tx_vfo), tr ("setting split mode"));
|
||||
update_other_frequency (tx);
|
||||
update_split (tx);
|
||||
@ -858,7 +844,7 @@ void HamlibTransceiver::do_tx_frequency (Frequency tx, MODE mode, bool no_ignore
|
||||
else
|
||||
{
|
||||
// Disable split
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_vfo split =" << split);
|
||||
CAT_TRACE ("rig_set_split_vfo split=" << split);
|
||||
auto rc = rig_set_split_vfo (rig_.data (), RIG_VFO_CURR, split, tx_vfo);
|
||||
if (tx || (-RIG_ENAVAIL != rc && -RIG_ENIMPL != rc))
|
||||
{
|
||||
@ -878,7 +864,7 @@ void HamlibTransceiver::do_tx_frequency (Frequency tx, MODE mode, bool no_ignore
|
||||
|
||||
void HamlibTransceiver::do_mode (MODE mode)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", mode);
|
||||
CAT_TRACE (mode);
|
||||
|
||||
auto vfos = get_vfos (state ().split ());
|
||||
// auto rx_vfo = std::get<0> (vfos);
|
||||
@ -892,11 +878,11 @@ void HamlibTransceiver::do_mode (MODE mode)
|
||||
if (!(state ().ptt () && state ().split () && one_VFO_))
|
||||
{
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting current VFO mode"));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode mode = " << rig_strrmode (current_mode) << "bw =" << current_width);
|
||||
CAT_TRACE ("rig_get_mode mode=" << rig_strrmode (current_mode) << " bw=" << current_width);
|
||||
|
||||
if (new_mode != current_mode)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_mode mode = " << rig_strrmode (new_mode));
|
||||
CAT_TRACE ("rig_set_mode mode=" << rig_strrmode (new_mode));
|
||||
error_check (rig_set_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting current VFO mode"));
|
||||
}
|
||||
}
|
||||
@ -905,22 +891,22 @@ void HamlibTransceiver::do_mode (MODE mode)
|
||||
if (state ().ptt () && state ().split () && one_VFO_)
|
||||
{
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting current VFO mode"));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode mode = " << rig_strrmode (current_mode) << "bw =" << current_width);
|
||||
CAT_TRACE ("rig_get_mode mode=" << rig_strrmode (current_mode) << " bw=" << current_width);
|
||||
|
||||
if (new_mode != current_mode)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_mode mode = " << rig_strrmode (new_mode));
|
||||
CAT_TRACE ("rig_set_mode mode=" << rig_strrmode (new_mode));
|
||||
error_check (rig_set_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting current VFO mode"));
|
||||
}
|
||||
}
|
||||
else if (state ().split () && !one_VFO_)
|
||||
{
|
||||
error_check (rig_get_split_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting split TX VFO mode"));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_split_mode mode = " << rig_strrmode (current_mode) << "bw =" << current_width);
|
||||
CAT_TRACE ("rig_get_split_mode mode=" << rig_strrmode (current_mode) << " bw=" << current_width);
|
||||
|
||||
if (new_mode != current_mode)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_mode mode = " << rig_strrmode (new_mode));
|
||||
CAT_TRACE ("rig_set_split_mode mode=" << rig_strrmode (new_mode));
|
||||
hamlib_tx_vfo_fixup fixup (rig_.data (), tx_vfo);
|
||||
error_check (rig_set_split_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting split TX VFO mode"));
|
||||
}
|
||||
@ -930,14 +916,6 @@ void HamlibTransceiver::do_mode (MODE mode)
|
||||
|
||||
void HamlibTransceiver::do_poll ()
|
||||
{
|
||||
#if !WSJT_TRACE_CAT_POLLS
|
||||
#if defined (NDEBUG)
|
||||
rig_set_debug (RIG_DEBUG_ERR);
|
||||
#else
|
||||
rig_set_debug (RIG_DEBUG_WARN);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
freq_t f;
|
||||
rmode_t m;
|
||||
pbwidth_t w;
|
||||
@ -947,7 +925,7 @@ void HamlibTransceiver::do_poll ()
|
||||
{
|
||||
vfo_t v;
|
||||
error_check (rig_get_vfo (rig_.data (), &v), tr ("getting current VFO")); // has side effect of establishing current VFO inside hamlib
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "VFO =" << rig_strvfo (v));
|
||||
CAT_TRACE ("VFO=" << rig_strvfo (v));
|
||||
reversed_ = RIG_VFO_B == v;
|
||||
}
|
||||
|
||||
@ -958,7 +936,7 @@ void HamlibTransceiver::do_poll ()
|
||||
auto rc = rig_get_split_vfo (rig_.data (), RIG_VFO_CURR, &s, &v);
|
||||
if (-RIG_OK == rc && RIG_SPLIT_ON == s)
|
||||
{
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_split_vfo split = " << s << " VFO = " << rig_strvfo (v));
|
||||
CAT_TRACE ("rig_get_split_vfo split=" << s << " VFO=" << rig_strvfo (v));
|
||||
update_split (true);
|
||||
// if (RIG_VFO_A == v)
|
||||
// {
|
||||
@ -967,14 +945,14 @@ void HamlibTransceiver::do_poll ()
|
||||
}
|
||||
else if (-RIG_OK == rc) // not split
|
||||
{
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_split_vfo split = " << s << " VFO = " << rig_strvfo (v));
|
||||
CAT_TRACE ("rig_get_split_vfo split=" << s << " VFO=" << rig_strvfo (v));
|
||||
update_split (false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Some rigs (Icom) don't have a way of reporting SPLIT
|
||||
// mode
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_split_vfo can't do on this rig");
|
||||
CAT_TRACE ("rig_get_split_vfo can't do on this rig");
|
||||
// just report how we see it based on prior commands
|
||||
split_query_works_ = false;
|
||||
}
|
||||
@ -987,7 +965,7 @@ void HamlibTransceiver::do_poll ()
|
||||
{
|
||||
error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &f), tr ("getting current VFO frequency"));
|
||||
f = std::round (f);
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_freq frequency =" << f);
|
||||
CAT_TRACE ("rig_get_freq frequency=" << f);
|
||||
update_rx_frequency (f);
|
||||
}
|
||||
|
||||
@ -1008,7 +986,7 @@ void HamlibTransceiver::do_poll ()
|
||||
: (rig_->state.vfo_list & RIG_VFO_B ? RIG_VFO_B : RIG_VFO_SUB)
|
||||
, &f), tr ("getting other VFO frequency"));
|
||||
f = std::round (f);
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_freq other VFO =" << f);
|
||||
CAT_TRACE ("rig_get_freq other VFO=" << f);
|
||||
update_other_frequency (f);
|
||||
}
|
||||
}
|
||||
@ -1026,12 +1004,12 @@ void HamlibTransceiver::do_poll ()
|
||||
auto rc = rig_get_mode (rig_.data (), RIG_VFO_CURR, &m, &w);
|
||||
if (RIG_OK == rc)
|
||||
{
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_mode mode =" << rig_strrmode (m) << "bw =" << w);
|
||||
CAT_TRACE ("rig_get_mode mode=" << rig_strrmode (m) << " bw=" << w);
|
||||
update_mode (map_mode (m));
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_mode mode failed with rc:" << rc << "ignoring");
|
||||
CAT_TRACE ("rig_get_mode mode failed with rc: " << rc << " ignoring");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1044,34 +1022,20 @@ void HamlibTransceiver::do_poll ()
|
||||
// support command
|
||||
{
|
||||
error_check (rc, tr ("getting PTT state"));
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_ptt PTT =" << p);
|
||||
CAT_TRACE ("rig_get_ptt PTT=" << p);
|
||||
update_PTT (!(RIG_PTT_OFF == p));
|
||||
}
|
||||
}
|
||||
|
||||
#if !WSJT_TRACE_CAT_POLLS
|
||||
#if WSJT_HAMLIB_TRACE
|
||||
#if WSJT_HAMLIB_VERBOSE_TRACE
|
||||
rig_set_debug (RIG_DEBUG_TRACE);
|
||||
#else
|
||||
rig_set_debug (RIG_DEBUG_VERBOSE);
|
||||
#endif
|
||||
#elif defined (NDEBUG)
|
||||
rig_set_debug (RIG_DEBUG_ERR);
|
||||
#else
|
||||
rig_set_debug (RIG_DEBUG_WARN);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void HamlibTransceiver::do_ptt (bool on)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", on << state () << "reversed =" << reversed_);
|
||||
CAT_TRACE ("PTT: " << on << " " << state () << " reversed=" << reversed_);
|
||||
if (on)
|
||||
{
|
||||
if (RIG_PTT_NONE != rig_->state.pttport.type.ptt)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_ptt PTT = true");
|
||||
CAT_TRACE ("rig_set_ptt PTT=true");
|
||||
error_check (rig_set_ptt (rig_.data (), RIG_VFO_CURR
|
||||
, RIG_PTT_RIG_MICDATA == rig_->caps->ptt_type && back_ptt_port_
|
||||
? RIG_PTT_ON_DATA : RIG_PTT_ON), tr ("setting PTT on"));
|
||||
@ -1081,7 +1045,7 @@ void HamlibTransceiver::do_ptt (bool on)
|
||||
{
|
||||
if (RIG_PTT_NONE != rig_->state.pttport.type.ptt)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_ptt PTT = false");
|
||||
CAT_TRACE ("rig_set_ptt PTT=false");
|
||||
error_check (rig_set_ptt (rig_.data (), RIG_VFO_CURR, RIG_PTT_OFF), tr ("setting PTT off"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,15 +17,15 @@ class HamlibTransceiver final
|
||||
Q_OBJECT // for translation context
|
||||
|
||||
public:
|
||||
static void register_transceivers (TransceiverFactory::Transceivers *);
|
||||
static void register_transceivers (logger_type *, TransceiverFactory::Transceivers *);
|
||||
static void unregister_transceivers ();
|
||||
|
||||
explicit HamlibTransceiver (int model_number, TransceiverFactory::ParameterPack const&,
|
||||
explicit HamlibTransceiver (logger_type *, int model_number, TransceiverFactory::ParameterPack const&,
|
||||
QObject * parent = nullptr);
|
||||
explicit HamlibTransceiver (TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port,
|
||||
explicit HamlibTransceiver (logger_type *, TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port,
|
||||
QObject * parent = nullptr);
|
||||
|
||||
private:
|
||||
private:
|
||||
int do_start () override;
|
||||
void do_stop () override;
|
||||
void do_frequency (Frequency, MODE, bool no_ignore) override;
|
||||
@ -65,6 +65,8 @@ public:
|
||||
// establish the Tx VFO
|
||||
bool get_vfo_works_; // Net rigctl promises what it can't deliver
|
||||
bool set_vfo_works_; // More rigctl promises which it can't deliver
|
||||
|
||||
static int debug_callback (enum rig_debug_level_e level, rig_ptr_t arg, char const * format, va_list ap);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -49,7 +49,7 @@ auto OmniRigTransceiver::map_mode (OmniRig::RigParamX param) -> MODE
|
||||
{
|
||||
return FM;
|
||||
}
|
||||
TRACE_CAT ("OmniRigTransceiver", "unrecognized mode");
|
||||
CAT_ERROR ("unrecognized mode");
|
||||
throw_qstring (tr ("OmniRig: unrecognized mode"));
|
||||
return UNK;
|
||||
}
|
||||
@ -74,7 +74,9 @@ OmniRig::RigParamX OmniRigTransceiver::map_mode (MODE mode)
|
||||
return OmniRig::PM_SSB_U; // quieten compiler grumble
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::register_transceivers (TransceiverFactory::Transceivers * registry, int id1, int id2)
|
||||
void OmniRigTransceiver::register_transceivers (logger_type *,
|
||||
TransceiverFactory::Transceivers * registry,
|
||||
int id1, int id2)
|
||||
{
|
||||
(*registry)[OmniRig_transceiver_one_name] = TransceiverFactory::Capabilities {
|
||||
id1
|
||||
@ -94,10 +96,11 @@ void OmniRigTransceiver::register_transceivers (TransceiverFactory::Transceivers
|
||||
};
|
||||
}
|
||||
|
||||
OmniRigTransceiver::OmniRigTransceiver (std::unique_ptr<TransceiverBase> wrapped,
|
||||
OmniRigTransceiver::OmniRigTransceiver (logger_type * logger,
|
||||
std::unique_ptr<TransceiverBase> wrapped,
|
||||
RigNumber n, TransceiverFactory::PTTMethod ptt_type,
|
||||
QString const& ptt_port, QObject * parent)
|
||||
: TransceiverBase {parent}
|
||||
: TransceiverBase {logger, parent}
|
||||
, wrapped_ {std::move (wrapped)}
|
||||
, use_for_ptt_ {TransceiverFactory::PTT_method_CAT == ptt_type || ("CAT" == ptt_port && (TransceiverFactory::PTT_method_RTS == ptt_type || TransceiverFactory::PTT_method_DTR == ptt_type))}
|
||||
, ptt_type_ {ptt_type}
|
||||
@ -126,14 +129,14 @@ bool OmniRigTransceiver::await_notification_with_timeout (int timeout)
|
||||
|
||||
int OmniRigTransceiver::do_start ()
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "starting");
|
||||
CAT_TRACE ("starting");
|
||||
|
||||
if (wrapped_) wrapped_->start (0);
|
||||
|
||||
omni_rig_.reset (new OmniRig::OmniRigX {this});
|
||||
if (omni_rig_->isNull ())
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "failed to start COM server");
|
||||
CAT_ERROR ("failed to start COM server");
|
||||
throw_qstring (tr ("Failed to start OmniRig COM server"));
|
||||
}
|
||||
|
||||
@ -149,8 +152,8 @@ int OmniRigTransceiver::do_start ()
|
||||
, SIGNAL (CustomReply (int, QVariant const&, QVariant const&))
|
||||
, this, SLOT (handle_custom_reply (int, QVariant const&, QVariant const&)));
|
||||
|
||||
TRACE_CAT ("OmniRigTransceiver", "OmniRig s/w version:" << QString::number (omni_rig_->SoftwareVersion ()).toLocal8Bit ()
|
||||
<< "i/f version:" << QString::number (omni_rig_->InterfaceVersion ()).toLocal8Bit ());
|
||||
CAT_INFO ("OmniRig s/w version: " << omni_rig_->SoftwareVersion ()
|
||||
<< "i/f version: " << omni_rig_->InterfaceVersion ());
|
||||
|
||||
// fetch the interface of the RigX CoClass and instantiate a proxy object
|
||||
switch (rig_number_)
|
||||
@ -182,12 +185,12 @@ int OmniRigTransceiver::do_start ()
|
||||
// COM/OLE exceptions get signaled
|
||||
connect (&*port_, SIGNAL (exception (int, QString, QString, QString)), this, SLOT (handle_COM_exception (int, QString, QString, QString)));
|
||||
|
||||
TRACE_CAT ("OmniRigTransceiver", "OmniRig RTS state:" << port_->Rts ());
|
||||
CAT_TRACE ("OmniRig RTS state: " << port_->Rts ());
|
||||
|
||||
// remove locking because it doesn't seem to work properly
|
||||
// if (!port_->Lock ()) // try to take exclusive use of the OmniRig serial port for PTT
|
||||
// {
|
||||
// TRACE_CAT ("OmniRigTransceiver", "Failed to get exclusive use of serial port for PTT from OmniRig");
|
||||
// CAT_WARNING ("Failed to get exclusive use of serial port for PTT from OmniRig");
|
||||
// }
|
||||
|
||||
// start off so we don't accidentally key the radio
|
||||
@ -205,11 +208,11 @@ int OmniRigTransceiver::do_start ()
|
||||
readable_params_ = rig_->ReadableParams ();
|
||||
writable_params_ = rig_->WriteableParams ();
|
||||
|
||||
TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig initial rig type: %1 readable params = 0x%2 writable params = 0x%3 for rig %4"}
|
||||
CAT_INFO (QString {"OmniRig initial rig type: %1 readable params=0x%2 writable params=0x%3 for rig %4"}
|
||||
.arg (rig_type_)
|
||||
.arg (readable_params_, 8, 16, QChar ('0'))
|
||||
.arg (writable_params_, 8, 16, QChar ('0'))
|
||||
.arg (rig_number_).toLocal8Bit ());
|
||||
.arg (rig_number_));
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
if (OmniRig::ST_ONLINE == rig_->Status ())
|
||||
@ -261,7 +264,7 @@ int OmniRigTransceiver::do_start ()
|
||||
}
|
||||
if (!await_notification_with_timeout (1000))
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "do_start 1: wait timed out");
|
||||
CAT_ERROR ("do_start 1: wait timed out");
|
||||
throw_qstring (tr ("OmniRig: timeout waiting for update from rig"));
|
||||
}
|
||||
switch (rig_->GetRxFrequency () - test_frequency)
|
||||
@ -289,7 +292,7 @@ int OmniRigTransceiver::do_start ()
|
||||
}
|
||||
if (!await_notification_with_timeout (2000))
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "do_start 2: wait timed out");
|
||||
CAT_ERROR ("do_start 2: wait timed out");
|
||||
throw_qstring (tr ("OmniRig: timeout waiting for update from rig"));
|
||||
}
|
||||
if (9 == rig_->GetRxFrequency () - test_frequency)
|
||||
@ -341,45 +344,45 @@ void OmniRigTransceiver::do_stop ()
|
||||
|
||||
if (wrapped_) wrapped_->stop ();
|
||||
|
||||
TRACE_CAT ("OmniRigTransceiver", "stopped");
|
||||
CAT_TRACE ("stopped");
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_COM_exception (int code, QString source, QString desc, QString help)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", QString::number (code) + " at " + source + ": " + desc + " (" + help + ')');
|
||||
CAT_ERROR ((QString::number (code) + " at " + source + ": " + desc + " (" + help + ')'));
|
||||
throw_qstring (tr ("OmniRig COM/OLE error: %1 at %2: %3 (%4)").arg (QString::number (code)).arg (source). arg (desc). arg (help));
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_visible_change ()
|
||||
{
|
||||
if (!omni_rig_ || omni_rig_->isNull ()) return;
|
||||
TRACE_CAT ("OmniRigTransceiver", "visibility change: visibility =" << omni_rig_->DialogVisible ());
|
||||
CAT_TRACE ("visibility change: visibility =" << omni_rig_->DialogVisible ());
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_rig_type_change (int rig_number)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "rig type change: rig =" << rig_number);
|
||||
CAT_TRACE ("rig type change: rig =" << rig_number);
|
||||
if (rig_number_ == rig_number)
|
||||
{
|
||||
if (!rig_ || rig_->isNull ()) return;
|
||||
readable_params_ = rig_->ReadableParams ();
|
||||
writable_params_ = rig_->WriteableParams ();
|
||||
TRACE_CAT ("OmniRigTransceiver", QString {"rig type change to: %1 readable params = 0x%2 writable params = 0x%3 for rig %4"}
|
||||
CAT_INFO (QString {"rig type change to: %1 readable params = 0x%2 writable params = 0x%3 for rig %4"}
|
||||
.arg (rig_->RigType ())
|
||||
.arg (readable_params_, 8, 16, QChar ('0'))
|
||||
.arg (writable_params_, 8, 16, QChar ('0'))
|
||||
.arg (rig_number).toLocal8Bit ());
|
||||
.arg (rig_number));
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_status_change (int rig_number)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", QString {"status change for rig %1"}.arg (rig_number).toLocal8Bit ());
|
||||
CAT_TRACE (QString {"status change for rig %1"}.arg (rig_number));
|
||||
if (rig_number_ == rig_number)
|
||||
{
|
||||
if (!rig_ || rig_->isNull ()) return;
|
||||
auto const& status = rig_->StatusStr ().toLocal8Bit ();
|
||||
TRACE_CAT ("OmniRigTransceiver", "OmniRig status change: new status = " << status);
|
||||
auto const& status = rig_->StatusStr ();
|
||||
CAT_TRACE ("OmniRig status change: new status = " << status);
|
||||
if (OmniRig::ST_ONLINE != rig_->Status ())
|
||||
{
|
||||
if (!offline_timer_->isActive ())
|
||||
@ -399,16 +402,16 @@ void OmniRigTransceiver::handle_status_change (int rig_number)
|
||||
// {
|
||||
// update_rx_frequency (rig_->GetRxFrequency ());
|
||||
// update_complete ();
|
||||
// TRACE_CAT ("OmniRigTransceiver", "frequency:" << state ().frequency ());
|
||||
// CAT_TRACE ("frequency:" << state ().frequency ());
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", QString {"params change: params = 0x%1 for rig %2"}
|
||||
CAT_TRACE (QString {"params change: params=0x%1 for rig %2"}
|
||||
.arg (params, 8, 16, QChar ('0'))
|
||||
.arg (rig_number).toLocal8Bit ()
|
||||
.arg (rig_number)
|
||||
<< "state before:" << state ());
|
||||
if (rig_number_ == rig_number)
|
||||
{
|
||||
@ -419,7 +422,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
|
||||
if (params & OmniRig::PM_VFOAA)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "VFOAA");
|
||||
CAT_TRACE ("VFOAA");
|
||||
update_split (false);
|
||||
reversed_ = false;
|
||||
update_rx_frequency (rig_->FreqA ());
|
||||
@ -427,7 +430,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
}
|
||||
if (params & OmniRig::PM_VFOAB)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "VFOAB");
|
||||
CAT_TRACE ("VFOAB");
|
||||
update_split (true);
|
||||
reversed_ = false;
|
||||
update_rx_frequency (rig_->FreqA ());
|
||||
@ -435,7 +438,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
}
|
||||
if (params & OmniRig::PM_VFOBA)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "VFOBA");
|
||||
CAT_TRACE ("VFOBA");
|
||||
update_split (true);
|
||||
reversed_ = true;
|
||||
update_other_frequency (rig_->FreqA ());
|
||||
@ -443,7 +446,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
}
|
||||
if (params & OmniRig::PM_VFOBB)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "VFOBB");
|
||||
CAT_TRACE ("VFOBB");
|
||||
update_split (false);
|
||||
reversed_ = true;
|
||||
update_other_frequency (rig_->FreqA ());
|
||||
@ -451,26 +454,26 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
}
|
||||
if (params & OmniRig::PM_VFOA)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "VFOA");
|
||||
CAT_TRACE ("VFOA");
|
||||
reversed_ = false;
|
||||
need_frequency = true;
|
||||
}
|
||||
if (params & OmniRig::PM_VFOB)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "VFOB");
|
||||
CAT_TRACE ("VFOB");
|
||||
reversed_ = true;
|
||||
need_frequency = true;
|
||||
}
|
||||
|
||||
if (params & OmniRig::PM_FREQ)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "FREQ");
|
||||
CAT_TRACE ("FREQ");
|
||||
need_frequency = true;
|
||||
}
|
||||
if (params & OmniRig::PM_FREQA)
|
||||
{
|
||||
auto f = rig_->FreqA ();
|
||||
TRACE_CAT ("OmniRigTransceiver", "FREQA = " << f);
|
||||
CAT_TRACE ("FREQA = " << f);
|
||||
if (reversed_)
|
||||
{
|
||||
update_other_frequency (f);
|
||||
@ -483,7 +486,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
if (params & OmniRig::PM_FREQB)
|
||||
{
|
||||
auto f = rig_->FreqB ();
|
||||
TRACE_CAT ("OmniRigTransceiver", "FREQB = " << f);
|
||||
CAT_TRACE ("FREQB = " << f);
|
||||
if (reversed_)
|
||||
{
|
||||
update_rx_frequency (f);
|
||||
@ -500,7 +503,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
auto f = rig_->FreqA ();
|
||||
if (f)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "FREQA = " << f);
|
||||
CAT_TRACE ("FREQA = " << f);
|
||||
if (reversed_)
|
||||
{
|
||||
update_other_frequency (f);
|
||||
@ -516,7 +519,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
auto f = rig_->FreqB ();
|
||||
if (f)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "FREQB = " << f);
|
||||
CAT_TRACE ("FREQB = " << f);
|
||||
if (reversed_)
|
||||
{
|
||||
update_rx_frequency (f);
|
||||
@ -532,35 +535,35 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
auto f = rig_->Freq ();
|
||||
if (f)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "FREQ = " << f);
|
||||
CAT_TRACE ("FREQ = " << f);
|
||||
update_rx_frequency (f);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (params & OmniRig::PM_PITCH)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "PITCH");
|
||||
CAT_TRACE ("PITCH");
|
||||
}
|
||||
if (params & OmniRig::PM_RITOFFSET)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "RITOFFSET");
|
||||
CAT_TRACE ("RITOFFSET");
|
||||
}
|
||||
if (params & OmniRig::PM_RIT0)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "RIT0");
|
||||
CAT_TRACE ("RIT0");
|
||||
}
|
||||
if (params & OmniRig::PM_VFOEQUAL)
|
||||
{
|
||||
auto f = readable_params_ & OmniRig::PM_FREQA ? rig_->FreqA () : rig_->Freq ();
|
||||
auto m = map_mode (rig_->Mode ());
|
||||
TRACE_CAT ("OmniRigTransceiver", QString {"VFOEQUAL f=%1 m=%2"}.arg (f).arg (m));
|
||||
CAT_TRACE (QString {"VFOEQUAL f=%1 m=%2"}.arg (f).arg (m));
|
||||
update_rx_frequency (f);
|
||||
update_other_frequency (f);
|
||||
update_mode (m);
|
||||
}
|
||||
if (params & OmniRig::PM_VFOSWAP)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "VFOSWAP");
|
||||
CAT_TRACE ("VFOSWAP");
|
||||
auto f = state ().tx_frequency ();
|
||||
update_other_frequency (state ().frequency ());
|
||||
update_rx_frequency (f);
|
||||
@ -568,78 +571,78 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
}
|
||||
if (params & OmniRig::PM_SPLITON)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "SPLITON");
|
||||
CAT_TRACE ("SPLITON");
|
||||
update_split (true);
|
||||
}
|
||||
if (params & OmniRig::PM_SPLITOFF)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "SPLITOFF");
|
||||
CAT_TRACE ("SPLITOFF");
|
||||
update_split (false);
|
||||
}
|
||||
if (params & OmniRig::PM_RITON)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "RITON");
|
||||
CAT_TRACE ("RITON");
|
||||
}
|
||||
if (params & OmniRig::PM_RITOFF)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "RITOFF");
|
||||
CAT_TRACE ("RITOFF");
|
||||
}
|
||||
if (params & OmniRig::PM_XITON)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "XITON");
|
||||
CAT_TRACE ("XITON");
|
||||
}
|
||||
if (params & OmniRig::PM_XITOFF)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "XITOFF");
|
||||
CAT_TRACE ("XITOFF");
|
||||
}
|
||||
if (params & OmniRig::PM_RX)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "RX");
|
||||
CAT_TRACE ("RX");
|
||||
update_PTT (false);
|
||||
}
|
||||
if (params & OmniRig::PM_TX)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "TX");
|
||||
CAT_TRACE ("TX");
|
||||
update_PTT ();
|
||||
}
|
||||
if (params & OmniRig::PM_CW_U)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "CW-R");
|
||||
CAT_TRACE ("CW-R");
|
||||
update_mode (CW_R);
|
||||
}
|
||||
if (params & OmniRig::PM_CW_L)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "CW");
|
||||
CAT_TRACE ("CW");
|
||||
update_mode (CW);
|
||||
}
|
||||
if (params & OmniRig::PM_SSB_U)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "USB");
|
||||
CAT_TRACE ("USB");
|
||||
update_mode (USB);
|
||||
}
|
||||
if (params & OmniRig::PM_SSB_L)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "LSB");
|
||||
CAT_TRACE ("LSB");
|
||||
update_mode (LSB);
|
||||
}
|
||||
if (params & OmniRig::PM_DIG_U)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "DATA-U");
|
||||
CAT_TRACE ("DATA-U");
|
||||
update_mode (DIG_U);
|
||||
}
|
||||
if (params & OmniRig::PM_DIG_L)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "DATA-L");
|
||||
CAT_TRACE ("DATA-L");
|
||||
update_mode (DIG_L);
|
||||
}
|
||||
if (params & OmniRig::PM_AM)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "AM");
|
||||
CAT_TRACE ("AM");
|
||||
update_mode (AM);
|
||||
}
|
||||
if (params & OmniRig::PM_FM)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "FM");
|
||||
CAT_TRACE ("FM");
|
||||
update_mode (FM);
|
||||
}
|
||||
|
||||
@ -648,7 +651,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
update_complete ();
|
||||
send_update_signal_ = false;
|
||||
}
|
||||
TRACE_CAT ("OmniRigTransceiver", "OmniRig params change: state after:" << state ());
|
||||
CAT_TRACE ("OmniRig params change: state after:" << state ());
|
||||
}
|
||||
Q_EMIT notified ();
|
||||
}
|
||||
@ -661,19 +664,19 @@ void OmniRigTransceiver::handle_custom_reply (int rig_number, QVariant const& co
|
||||
if (rig_number_ == rig_number)
|
||||
{
|
||||
if (!rig_ || rig_->isNull ()) return;
|
||||
TRACE_CAT ("OmniRigTransceiver", "custom command" << command.toString ().toLocal8Bit ()
|
||||
<< "with reply" << reply.toString ().toLocal8Bit ()
|
||||
<< QString ("for rig %1").arg (rig_number).toLocal8Bit ());
|
||||
TRACE_CAT ("OmniRigTransceiver", "rig number:" << rig_number_ << ':' << state ());
|
||||
CAT_TRACE ("custom command" << command.toString ()
|
||||
<< "with reply" << reply.toString ()
|
||||
<< QString ("for rig %1").arg (rig_number));
|
||||
CAT_TRACE ("rig number:" << rig_number_ << ':' << state ());
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_ptt (bool on)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", on << state ());
|
||||
CAT_TRACE (on << state ());
|
||||
if (use_for_ptt_ && TransceiverFactory::PTT_method_CAT == ptt_type_)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "set PTT");
|
||||
CAT_TRACE ("set PTT");
|
||||
if (rig_ && !rig_->isNull ())
|
||||
{
|
||||
rig_->SetTx (on ? OmniRig::PM_TX : OmniRig::PM_RX);
|
||||
@ -685,18 +688,18 @@ void OmniRigTransceiver::do_ptt (bool on)
|
||||
{
|
||||
if (TransceiverFactory::PTT_method_RTS == ptt_type_)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "set RTS");
|
||||
CAT_TRACE ("set RTS");
|
||||
port_->SetRts (on);
|
||||
}
|
||||
else // "DTR"
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "set DTR");
|
||||
CAT_TRACE ("set DTR");
|
||||
port_->SetDtr (on);
|
||||
}
|
||||
}
|
||||
else if (wrapped_)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "set PTT using basic transceiver");
|
||||
CAT_TRACE ("set PTT using basic transceiver");
|
||||
TransceiverState new_state {wrapped_->state ()};
|
||||
new_state.ptt (on);
|
||||
wrapped_->set (new_state, 0);
|
||||
@ -707,7 +710,7 @@ void OmniRigTransceiver::do_ptt (bool on)
|
||||
|
||||
void OmniRigTransceiver::do_frequency (Frequency f, MODE m, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", f << state ());
|
||||
CAT_TRACE (f << state ());
|
||||
if (!rig_ || rig_->isNull ()) return;
|
||||
if (UNK != m)
|
||||
{
|
||||
@ -736,7 +739,7 @@ void OmniRigTransceiver::do_frequency (Frequency f, MODE m, bool /*no_ignore*/)
|
||||
|
||||
void OmniRigTransceiver::do_tx_frequency (Frequency tx, MODE m, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", tx << state ());
|
||||
CAT_TRACE (tx << state ());
|
||||
if (!rig_ || rig_->isNull ()) return;
|
||||
bool split {tx != 0};
|
||||
if (split)
|
||||
@ -766,14 +769,14 @@ void OmniRigTransceiver::do_tx_frequency (Frequency tx, MODE m, bool /*no_ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE_CAT ("OmniRigTransceiver", "set SPLIT mode on");
|
||||
CAT_TRACE ("set SPLIT mode on");
|
||||
rig_->SetSplitMode (state ().frequency (), tx);
|
||||
update_other_frequency (tx);
|
||||
update_split (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "set SPLIT mode off");
|
||||
CAT_TRACE ("set SPLIT mode off");
|
||||
rig_->SetSimplexMode (state ().frequency ());
|
||||
update_split (false);
|
||||
}
|
||||
@ -788,7 +791,7 @@ void OmniRigTransceiver::do_tx_frequency (Frequency tx, MODE m, bool /*no_ignore
|
||||
}
|
||||
if (!((OmniRig::PM_VFOAB | OmniRig::PM_VFOBA | OmniRig::PM_SPLITON) & readable_params_))
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "setting SPLIT manually");
|
||||
CAT_TRACE ("setting SPLIT manually");
|
||||
update_split (split); // we can't read it so just set and
|
||||
// hope op doesn't change it
|
||||
notify = true;
|
||||
@ -801,7 +804,7 @@ void OmniRigTransceiver::do_tx_frequency (Frequency tx, MODE m, bool /*no_ignore
|
||||
|
||||
void OmniRigTransceiver::do_mode (MODE mode)
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", mode << state ());
|
||||
CAT_TRACE (mode << state ());
|
||||
if (!rig_ || rig_->isNull ()) return;
|
||||
// TODO: G4WJS OmniRig doesn't seem to have any capability of tracking/setting VFO B mode
|
||||
auto mapped = map_mode (mode);
|
||||
|
||||
@ -26,12 +26,14 @@ class OmniRigTransceiver final
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
static void register_transceivers (TransceiverFactory::Transceivers *, int id1, int id2);
|
||||
static void register_transceivers (logger_type *, TransceiverFactory::Transceivers *, int id1, int id2);
|
||||
|
||||
enum RigNumber {One = 1, Two};
|
||||
|
||||
// takes ownership of wrapped Transceiver
|
||||
explicit OmniRigTransceiver (std::unique_ptr<TransceiverBase> wrapped, RigNumber, TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port, QObject * parent = nullptr);
|
||||
explicit OmniRigTransceiver (logger_type *, std::unique_ptr<TransceiverBase> wrapped,
|
||||
RigNumber, TransceiverFactory::PTTMethod ptt_type,
|
||||
QString const& ptt_port, QObject * parent = nullptr);
|
||||
~OmniRigTransceiver ();
|
||||
|
||||
int do_start () override;
|
||||
@ -52,8 +54,8 @@ private:
|
||||
Q_SLOT void handle_params_change (int rig_number, int params);
|
||||
Q_SLOT void handle_custom_reply (int, QVariant const& command, QVariant const& reply);
|
||||
|
||||
static MODE map_mode (OmniRig::RigParamX param);
|
||||
static OmniRig::RigParamX map_mode (MODE mode);
|
||||
MODE map_mode (OmniRig::RigParamX param);
|
||||
OmniRig::RigParamX map_mode (MODE mode);
|
||||
|
||||
std::unique_ptr<TransceiverBase> wrapped_; // may be null
|
||||
bool use_for_ptt_;
|
||||
|
||||
@ -13,8 +13,8 @@ namespace
|
||||
unsigned const polls_to_stabilize {3};
|
||||
}
|
||||
|
||||
PollingTransceiver::PollingTransceiver (int poll_interval, QObject * parent)
|
||||
: TransceiverBase {parent}
|
||||
PollingTransceiver::PollingTransceiver (logger_type * logger, int poll_interval, QObject * parent)
|
||||
: TransceiverBase {logger, parent}
|
||||
, interval_ {poll_interval * 1000}
|
||||
, poll_timer_ {nullptr}
|
||||
, retries_ {0}
|
||||
|
||||
@ -35,7 +35,7 @@ class PollingTransceiver
|
||||
Q_OBJECT; // for translation context
|
||||
|
||||
protected:
|
||||
explicit PollingTransceiver (int poll_interval, // in seconds
|
||||
explicit PollingTransceiver (logger_type *, int poll_interval, // in seconds
|
||||
QObject * parent);
|
||||
|
||||
protected:
|
||||
|
||||
@ -1,7 +1,15 @@
|
||||
#include "Transceiver.hpp"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "moc_Transceiver.cpp"
|
||||
|
||||
Transceiver::Transceiver (logger_type * logger, QObject * parent)
|
||||
: QObject {parent}
|
||||
, logger_ {logger}
|
||||
{
|
||||
}
|
||||
|
||||
#if !defined (QT_NO_DEBUG_STREAM)
|
||||
QDebug operator << (QDebug d, Transceiver::TransceiverState const& s)
|
||||
{
|
||||
@ -15,6 +23,16 @@ QDebug operator << (QDebug d, Transceiver::TransceiverState const& s)
|
||||
}
|
||||
#endif
|
||||
|
||||
std::ostream& operator << (std::ostream& os, Transceiver::TransceiverState const& s)
|
||||
{
|
||||
return os
|
||||
<< "Transceiver::TransceiverState(online: " << (s.online_ ? "yes" : "no")
|
||||
<< " Frequency {" << s.rx_frequency_ << "Hz, " << s.tx_frequency_ << "Hz} " << s.mode_
|
||||
<< "; SPLIT: " << (Transceiver::TransceiverState::Split::on == s.split_ ? "on" : Transceiver::TransceiverState::Split::off == s.split_ ? "off" : "unknown")
|
||||
<< "; PTT: " << (s.ptt_ ? "on" : "off")
|
||||
<< ')';
|
||||
}
|
||||
|
||||
ENUM_QDATASTREAM_OPS_IMPL (Transceiver, MODE);
|
||||
|
||||
ENUM_CONVERSION_OPS_IMPL (Transceiver, MODE);
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
#ifndef TRANSCEIVER_HPP__
|
||||
#define TRANSCEIVER_HPP__
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/sources/severity_channel_logger.hpp>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "qt_helpers.hpp"
|
||||
@ -55,9 +60,11 @@ class Transceiver
|
||||
|
||||
public:
|
||||
using Frequency = Radio::Frequency;
|
||||
using logger_type = boost::log::sources::severity_channel_logger_mt<boost::log::trivial::severity_level>;
|
||||
|
||||
protected:
|
||||
Transceiver (QObject * parent) : QObject {parent} {}
|
||||
Transceiver (logger_type *, QObject * parent);
|
||||
logger_type& logger () const {return *logger_;}
|
||||
|
||||
public:
|
||||
virtual ~Transceiver () {}
|
||||
@ -108,6 +115,7 @@ public:
|
||||
|
||||
friend QDebug operator << (QDebug, TransceiverState const&);
|
||||
friend bool operator != (TransceiverState const&, TransceiverState const&);
|
||||
friend std::ostream& operator << (std::ostream&, Transceiver::TransceiverState const&);
|
||||
};
|
||||
|
||||
//
|
||||
@ -150,6 +158,9 @@ public:
|
||||
|
||||
// Ready to be destroyed.
|
||||
Q_SIGNAL void finished () const;
|
||||
|
||||
private:
|
||||
logger_type mutable * logger_;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE (Transceiver::TransceiverState);
|
||||
@ -158,6 +169,8 @@ Q_DECLARE_METATYPE (Transceiver::TransceiverState);
|
||||
QDebug operator << (QDebug, Transceiver::TransceiverState const&);
|
||||
#endif
|
||||
|
||||
std::ostream& operator << (std::ostream&, Transceiver::TransceiverState const&);
|
||||
|
||||
ENUM_QDATASTREAM_OPS_DECL (Transceiver, MODE);
|
||||
ENUM_CONVERSION_OPS_DECL (Transceiver, MODE);
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@ void TransceiverBase::start (unsigned sequence_number) noexcept
|
||||
void TransceiverBase::set (TransceiverState const& s,
|
||||
unsigned sequence_number) noexcept
|
||||
{
|
||||
TRACE_CAT ("TransceiverBase", "#:" << sequence_number << s);
|
||||
CAT_TRACE ("#: " << sequence_number << " " << s);
|
||||
|
||||
QString message;
|
||||
try
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "Logger.hpp"
|
||||
#include "Transceiver.hpp"
|
||||
|
||||
//
|
||||
@ -61,8 +62,8 @@ class TransceiverBase
|
||||
Q_OBJECT;
|
||||
|
||||
protected:
|
||||
TransceiverBase (QObject * parent)
|
||||
: Transceiver {parent}
|
||||
TransceiverBase (logger_type * logger, QObject * parent)
|
||||
: Transceiver {logger, parent}
|
||||
, last_sequence_number_ {0}
|
||||
{}
|
||||
|
||||
@ -152,17 +153,12 @@ private:
|
||||
unsigned last_sequence_number_; // from set state operation
|
||||
};
|
||||
|
||||
// some trace macros
|
||||
#if WSJT_TRACE_CAT
|
||||
#define TRACE_CAT(FAC, MSG) qDebug () << QString {"%1::%2:"}.arg ((FAC)).arg (__func__) << MSG
|
||||
#else
|
||||
#define TRACE_CAT(FAC, MSG)
|
||||
#endif
|
||||
|
||||
#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS
|
||||
#define TRACE_CAT_POLL(FAC, MSG) qDebug () << QString {"%1::%2:"}.arg ((FAC)).arg (__func__) << MSG
|
||||
#else
|
||||
#define TRACE_CAT_POLL(FAC, MSG)
|
||||
#endif
|
||||
// some loggimg macros
|
||||
#define CAT_TRACE(MSG) LOG_LOG_LOCATION (logger (), trace, MSG)
|
||||
#define CAT_DEBUG(MSG) LOG_LOG_LOCATION (logger (), debug, MSG)
|
||||
#define CAT_INFO(MSG) LOG_LOG_LOCATION (logger (), info, MSG)
|
||||
#define CAT_WARNING(MSG) LOG_LOG_LOCATION (logger (), warning, MSG)
|
||||
#define CAT_ERROR(MSG) LOG_LOG_LOCATION (logger (), error, MSG)
|
||||
#define CAT_FATAL(MSG) LOG_LOG_LOCATION (logger (), fatal, MSG)
|
||||
|
||||
#endif
|
||||
|
||||
@ -32,14 +32,15 @@ namespace
|
||||
}
|
||||
|
||||
TransceiverFactory::TransceiverFactory ()
|
||||
: logger_ (boost::log::keywords::channel = "RIGCTRL")
|
||||
{
|
||||
HamlibTransceiver::register_transceivers (&transceivers_);
|
||||
DXLabSuiteCommanderTransceiver::register_transceivers (&transceivers_, CommanderId);
|
||||
HRDTransceiver::register_transceivers (&transceivers_, HRDId);
|
||||
HamlibTransceiver::register_transceivers (&logger_, &transceivers_);
|
||||
DXLabSuiteCommanderTransceiver::register_transceivers (&logger_, &transceivers_, CommanderId);
|
||||
HRDTransceiver::register_transceivers (&logger_, &transceivers_, HRDId);
|
||||
|
||||
#if defined (WIN32)
|
||||
// OmniRig is ActiveX/COM server so only on Windows
|
||||
OmniRigTransceiver::register_transceivers (&transceivers_, OmniRigOneId, OmniRigTwoId);
|
||||
OmniRigTransceiver::register_transceivers (&logger_, &transceivers_, OmniRigOneId, OmniRigTwoId);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -91,7 +92,7 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
if (PTT_method_CAT != params.ptt_type)
|
||||
{
|
||||
// we start with a dummy HamlibTransceiver object instance that can support direct PTT
|
||||
basic_transceiver.reset (new HamlibTransceiver {params.ptt_type, params.ptt_port});
|
||||
basic_transceiver.reset (new HamlibTransceiver {&logger_, params.ptt_type, params.ptt_port});
|
||||
if (target_thread)
|
||||
{
|
||||
basic_transceiver.get ()->moveToThread (target_thread);
|
||||
@ -99,7 +100,7 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
}
|
||||
|
||||
// wrap the basic Transceiver object instance with a decorator object that talks to DX Lab Suite Commander
|
||||
result.reset (new DXLabSuiteCommanderTransceiver {std::move (basic_transceiver), params.network_port, PTT_method_CAT == params.ptt_type, params.poll_interval});
|
||||
result.reset (new DXLabSuiteCommanderTransceiver {&logger_, std::move (basic_transceiver), params.network_port, PTT_method_CAT == params.ptt_type, params.poll_interval});
|
||||
if (target_thread)
|
||||
{
|
||||
result->moveToThread (target_thread);
|
||||
@ -113,7 +114,7 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
if (PTT_method_CAT != params.ptt_type)
|
||||
{
|
||||
// we start with a dummy HamlibTransceiver object instance that can support direct PTT
|
||||
basic_transceiver.reset (new HamlibTransceiver {params.ptt_type, params.ptt_port});
|
||||
basic_transceiver.reset (new HamlibTransceiver {&logger_, params.ptt_type, params.ptt_port});
|
||||
if (target_thread)
|
||||
{
|
||||
basic_transceiver.get ()->moveToThread (target_thread);
|
||||
@ -121,7 +122,7 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
}
|
||||
|
||||
// wrap the basic Transceiver object instance with a decorator object that talks to ham Radio Deluxe
|
||||
result.reset (new HRDTransceiver {std::move (basic_transceiver), params.network_port, PTT_method_CAT == params.ptt_type, params.audio_source, params.poll_interval});
|
||||
result.reset (new HRDTransceiver {&logger_, std::move (basic_transceiver), params.network_port, PTT_method_CAT == params.ptt_type, params.audio_source, params.poll_interval});
|
||||
if (target_thread)
|
||||
{
|
||||
result->moveToThread (target_thread);
|
||||
@ -136,7 +137,7 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
if (PTT_method_CAT != params.ptt_type && "CAT" != params.ptt_port)
|
||||
{
|
||||
// we start with a dummy HamlibTransceiver object instance that can support direct PTT
|
||||
basic_transceiver.reset (new HamlibTransceiver {params.ptt_type, params.ptt_port});
|
||||
basic_transceiver.reset (new HamlibTransceiver {&logger_, params.ptt_type, params.ptt_port});
|
||||
if (target_thread)
|
||||
{
|
||||
basic_transceiver.get ()->moveToThread (target_thread);
|
||||
@ -144,7 +145,7 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
}
|
||||
|
||||
// wrap the basic Transceiver object instance with a decorator object that talks to OmniRig rig one
|
||||
result.reset (new OmniRigTransceiver {std::move (basic_transceiver), OmniRigTransceiver::One, params.ptt_type, params.ptt_port});
|
||||
result.reset (new OmniRigTransceiver {&logger_, std::move (basic_transceiver), OmniRigTransceiver::One, params.ptt_type, params.ptt_port});
|
||||
if (target_thread)
|
||||
{
|
||||
result->moveToThread (target_thread);
|
||||
@ -158,7 +159,7 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
if (PTT_method_CAT != params.ptt_type && "CAT" != params.ptt_port)
|
||||
{
|
||||
// we start with a dummy HamlibTransceiver object instance that can support direct PTT
|
||||
basic_transceiver.reset (new HamlibTransceiver {params.ptt_type, params.ptt_port});
|
||||
basic_transceiver.reset (new HamlibTransceiver {&logger_, params.ptt_type, params.ptt_port});
|
||||
if (target_thread)
|
||||
{
|
||||
basic_transceiver.get ()->moveToThread (target_thread);
|
||||
@ -166,7 +167,7 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
}
|
||||
|
||||
// wrap the basic Transceiver object instance with a decorator object that talks to OmniRig rig two
|
||||
result.reset (new OmniRigTransceiver {std::move (basic_transceiver), OmniRigTransceiver::Two, params.ptt_type, params.ptt_port});
|
||||
result.reset (new OmniRigTransceiver {&logger_, std::move (basic_transceiver), OmniRigTransceiver::Two, params.ptt_type, params.ptt_port});
|
||||
if (target_thread)
|
||||
{
|
||||
result->moveToThread (target_thread);
|
||||
@ -176,7 +177,7 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
#endif
|
||||
|
||||
default:
|
||||
result.reset (new HamlibTransceiver {supported_transceivers ()[params.rig_name].model_number_, params});
|
||||
result.reset (new HamlibTransceiver {&logger_, supported_transceivers ()[params.rig_name].model_number_, params});
|
||||
if (target_thread)
|
||||
{
|
||||
result->moveToThread (target_thread);
|
||||
@ -187,7 +188,7 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
if (split_mode_emulate == params.split_mode)
|
||||
{
|
||||
// wrap the Transceiver object instance with a decorator that emulates split mode
|
||||
result.reset (new EmulateSplitTransceiver {std::move (result)});
|
||||
result.reset (new EmulateSplitTransceiver {&logger_, std::move (result)});
|
||||
if (target_thread)
|
||||
{
|
||||
result->moveToThread (target_thread);
|
||||
|
||||
@ -3,6 +3,9 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/sources/severity_channel_logger.hpp>
|
||||
|
||||
#include <QObject>
|
||||
#include <QMap>
|
||||
|
||||
@ -151,6 +154,7 @@ public:
|
||||
std::unique_ptr<Transceiver> create (ParameterPack const&, QThread * target_thread = nullptr);
|
||||
|
||||
private:
|
||||
Transceiver::logger_type mutable logger_;
|
||||
Transceivers transceivers_;
|
||||
};
|
||||
|
||||
|
||||
@ -25,10 +25,13 @@ namespace
|
||||
|
||||
QFont text_font {"Courier", 10};
|
||||
|
||||
QList<QStandardItem *> make_row (QString const& client_id, QTime time, qint32 snr, float delta_time
|
||||
QList<QStandardItem *> make_row (MessageServer::ClientKey const& key, QTime time, qint32 snr, float delta_time
|
||||
, Frequency frequency, qint32 drift, QString const& callsign
|
||||
, QString const& grid, qint32 power, bool off_air)
|
||||
{
|
||||
auto client_item = new QStandardItem {QString {"%1(%2)"}.arg (key.second).arg (key.first.toString ())};
|
||||
client_item->setData (QVariant::fromValue (key));
|
||||
|
||||
auto time_item = new QStandardItem {time.toString ("hh:mm")};
|
||||
time_item->setData (time);
|
||||
time_item->setTextAlignment (Qt::AlignRight);
|
||||
@ -60,7 +63,7 @@ namespace
|
||||
live->setTextAlignment (Qt::AlignHCenter);
|
||||
|
||||
QList<QStandardItem *> row {
|
||||
new QStandardItem {client_id}, time_item, snr_item, dt, freq, dri, gd, pwr, live, new QStandardItem {callsign}};
|
||||
client_item, time_item, snr_item, dt, freq, dri, gd, pwr, live, new QStandardItem {callsign}};
|
||||
Q_FOREACH (auto& item, row)
|
||||
{
|
||||
item->setEditable (false);
|
||||
@ -81,7 +84,7 @@ BeaconsModel::BeaconsModel (QObject * parent)
|
||||
}
|
||||
}
|
||||
|
||||
void BeaconsModel::add_beacon_spot (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time
|
||||
void BeaconsModel::add_beacon_spot (bool is_new, ClientKey const& key, QTime time, qint32 snr, float delta_time
|
||||
, Frequency frequency, qint32 drift, QString const& callsign
|
||||
, QString const& grid, qint32 power, bool off_air)
|
||||
{
|
||||
@ -90,7 +93,7 @@ void BeaconsModel::add_beacon_spot (bool is_new, QString const& client_id, QTime
|
||||
int target_row {-1};
|
||||
for (auto row = 0; row < rowCount (); ++row)
|
||||
{
|
||||
if (data (index (row, 0)).toString () == client_id)
|
||||
if (item (row, 0)->data ().value<ClientKey> () == key)
|
||||
{
|
||||
auto row_time = item (row, 1)->data ().toTime ();
|
||||
if (row_time == time
|
||||
@ -113,19 +116,19 @@ void BeaconsModel::add_beacon_spot (bool is_new, QString const& client_id, QTime
|
||||
}
|
||||
if (target_row >= 0)
|
||||
{
|
||||
insertRow (target_row + 1, make_row (client_id, time, snr, delta_time, frequency, drift, callsign, grid, power, off_air));
|
||||
insertRow (target_row + 1, make_row (key, time, snr, delta_time, frequency, drift, callsign, grid, power, off_air));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
appendRow (make_row (client_id, time, snr, delta_time, frequency, drift, callsign, grid, power, off_air));
|
||||
appendRow (make_row (key, time, snr, delta_time, frequency, drift, callsign, grid, power, off_air));
|
||||
}
|
||||
|
||||
void BeaconsModel::decodes_cleared (QString const& client_id)
|
||||
void BeaconsModel::decodes_cleared (ClientKey const& key)
|
||||
{
|
||||
for (auto row = rowCount () - 1; row >= 0; --row)
|
||||
{
|
||||
if (data (index (row, 0)).toString () == client_id)
|
||||
if (item (row, 0)->data ().value<ClientKey> () == key)
|
||||
{
|
||||
removeRow (row);
|
||||
}
|
||||
|
||||
@ -26,13 +26,15 @@ class BeaconsModel
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
using ClientKey = MessageServer::ClientKey;
|
||||
|
||||
public:
|
||||
explicit BeaconsModel (QObject * parent = nullptr);
|
||||
|
||||
Q_SLOT void add_beacon_spot (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time
|
||||
Q_SLOT void add_beacon_spot (bool is_new, ClientKey const&, QTime time, qint32 snr, float delta_time
|
||||
, Frequency frequency, qint32 drift, QString const& callsign, QString const& grid
|
||||
, qint32 power, bool off_air);
|
||||
Q_SLOT void decodes_cleared (QString const& client_id);
|
||||
Q_SLOT void decodes_cleared (ClientKey const&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
#include <QColor>
|
||||
#include <QtWidgets>
|
||||
#include <QAction>
|
||||
#include <QDebug>
|
||||
|
||||
#include "validators/MaidenheadLocatorValidator.hpp"
|
||||
|
||||
@ -27,9 +26,9 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
ClientWidget::IdFilterModel::IdFilterModel (QString const& client_id, QObject * parent)
|
||||
ClientWidget::IdFilterModel::IdFilterModel (ClientKey const& key, QObject * parent)
|
||||
: QSortFilterProxyModel {parent}
|
||||
, client_id_ {client_id}
|
||||
, key_ {key}
|
||||
, rx_df_ (quint32_max)
|
||||
{
|
||||
}
|
||||
@ -73,7 +72,7 @@ bool ClientWidget::IdFilterModel::filterAcceptsRow (int source_row
|
||||
, QModelIndex const& source_parent) const
|
||||
{
|
||||
auto source_index_col0 = sourceModel ()->index (source_row, 0, source_parent);
|
||||
return sourceModel ()->data (source_index_col0).toString () == client_id_;
|
||||
return sourceModel ()->data (source_index_col0, Qt::UserRole + 1).value<ClientKey> () == key_;
|
||||
}
|
||||
|
||||
void ClientWidget::IdFilterModel::de_call (QString const& call)
|
||||
@ -106,9 +105,9 @@ void ClientWidget::IdFilterModel::rx_df (quint32 df)
|
||||
|
||||
namespace
|
||||
{
|
||||
QString make_title (QString const& id, QString const& version, QString const& revision)
|
||||
QString make_title (MessageServer::ClientKey const& key, QString const& version, QString const& revision)
|
||||
{
|
||||
QString title {id};
|
||||
QString title {QString {"%1(%2)"}.arg (key.second).arg (key.first.toString ())};
|
||||
if (version.size ())
|
||||
{
|
||||
title += QString {" v%1"}.arg (version);
|
||||
@ -122,14 +121,14 @@ namespace
|
||||
}
|
||||
|
||||
ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model
|
||||
, QString const& id, QString const& version, QString const& revision
|
||||
, ClientKey const& key, QString const& version, QString const& revision
|
||||
, QListWidget const * calls_of_interest, QWidget * parent)
|
||||
: QDockWidget {make_title (id, version, revision), parent}
|
||||
, id_ {id}
|
||||
: QDockWidget {make_title (key, version, revision), parent}
|
||||
, key_ {key}
|
||||
, done_ {false}
|
||||
, calls_of_interest_ {calls_of_interest}
|
||||
, decodes_proxy_model_ {id}
|
||||
, beacons_proxy_model_ {id}
|
||||
, decodes_proxy_model_ {key}
|
||||
, beacons_proxy_model_ {key}
|
||||
, erase_action_ {new QAction {tr ("&Erase Band Activity"), this}}
|
||||
, erase_rx_frequency_action_ {new QAction {tr ("Erase &Rx Frequency"), this}}
|
||||
, erase_both_action_ {new QAction {tr ("Erase &Both"), this}}
|
||||
@ -184,10 +183,10 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
|
||||
message_line_edit_->setValidator (&message_validator);
|
||||
grid_line_edit_->setValidator (&locator_validator);
|
||||
dx_grid_line_edit_->setValidator (&locator_validator);
|
||||
tr_period_spin_box_->setRange (5, 30);
|
||||
tr_period_spin_box_->setRange (5, 1800);
|
||||
tr_period_spin_box_->setSuffix (" s");
|
||||
rx_df_spin_box_->setRange (200, 5000);
|
||||
frequency_tolerance_spin_box_->setRange (10, 1000);
|
||||
frequency_tolerance_spin_box_->setRange (1, 1000);
|
||||
frequency_tolerance_spin_box_->setPrefix ("\u00b1");
|
||||
frequency_tolerance_spin_box_->setSuffix (" Hz");
|
||||
|
||||
@ -209,56 +208,56 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
|
||||
horizontal_layout_->addLayout (subform3_layout_);
|
||||
|
||||
connect (message_line_edit_, &QLineEdit::textEdited, [this] (QString const& text) {
|
||||
Q_EMIT do_free_text (id_, text, false);
|
||||
Q_EMIT do_free_text (key_, text, false);
|
||||
});
|
||||
connect (message_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
Q_EMIT do_free_text (id_, message_line_edit_->text (), true);
|
||||
Q_EMIT do_free_text (key_, message_line_edit_->text (), true);
|
||||
});
|
||||
connect (grid_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
Q_EMIT location (id_, grid_line_edit_->text ());
|
||||
Q_EMIT location (key_, grid_line_edit_->text ());
|
||||
});
|
||||
connect (configuration_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
Q_EMIT switch_configuration (id_, configuration_line_edit_->text ());
|
||||
Q_EMIT switch_configuration (key_, configuration_line_edit_->text ());
|
||||
});
|
||||
connect (mode_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, mode_line_edit_->text (), quint32_max, empty, fast_mode ()
|
||||
Q_EMIT configure (key_, mode_line_edit_->text (), quint32_max, empty, fast_mode ()
|
||||
, quint32_max, quint32_max, empty, empty, false);
|
||||
});
|
||||
connect (frequency_tolerance_spin_box_, static_cast<void (QSpinBox::*) (int)> (&QSpinBox::valueChanged), [this] (int i) {
|
||||
QString empty;
|
||||
auto f = frequency_tolerance_spin_box_->specialValueText ().size () ? quint32_max : i;
|
||||
Q_EMIT configure (id_, empty, f, empty, fast_mode ()
|
||||
Q_EMIT configure (key_, empty, f, empty, fast_mode ()
|
||||
, quint32_max, quint32_max, empty, empty, false);
|
||||
});
|
||||
connect (submode_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, submode_line_edit_->text (), fast_mode ()
|
||||
Q_EMIT configure (key_, empty, quint32_max, submode_line_edit_->text (), fast_mode ()
|
||||
, quint32_max, quint32_max, empty, empty, false);
|
||||
});
|
||||
connect (fast_mode_check_box_, &QCheckBox::stateChanged, [this] (int state) {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, empty, Qt::Checked == state
|
||||
Q_EMIT configure (key_, empty, quint32_max, empty, Qt::Checked == state
|
||||
, quint32_max, quint32_max, empty, empty, false);
|
||||
});
|
||||
connect (tr_period_spin_box_, static_cast<void (QSpinBox::*) (int)> (&QSpinBox::valueChanged), [this] (int i) {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode ()
|
||||
Q_EMIT configure (key_, empty, quint32_max, empty, fast_mode ()
|
||||
, i, quint32_max, empty, empty, false);
|
||||
});
|
||||
connect (rx_df_spin_box_, static_cast<void (QSpinBox::*) (int)> (&QSpinBox::valueChanged), [this] (int i) {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode ()
|
||||
Q_EMIT configure (key_, empty, quint32_max, empty, fast_mode ()
|
||||
, quint32_max, i, empty, empty, false);
|
||||
});
|
||||
connect (dx_call_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode ()
|
||||
Q_EMIT configure (key_, empty, quint32_max, empty, fast_mode ()
|
||||
, quint32_max, quint32_max, dx_call_line_edit_->text (), empty, false);
|
||||
});
|
||||
connect (dx_grid_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode ()
|
||||
Q_EMIT configure (key_, empty, quint32_max, empty, fast_mode ()
|
||||
, quint32_max, quint32_max, empty, dx_grid_line_edit_->text (), false);
|
||||
});
|
||||
|
||||
@ -289,14 +288,14 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
|
||||
halt_tx_button_ = control_button_box_->addButton (tr ("&Halt Tx"), QDialogButtonBox::ActionRole);
|
||||
connect (generate_messages_push_button_, &QAbstractButton::clicked, [this] (bool /*checked*/) {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode ()
|
||||
Q_EMIT configure (key_, empty, quint32_max, empty, fast_mode ()
|
||||
, quint32_max, quint32_max, empty, empty, true);
|
||||
});
|
||||
connect (auto_off_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
|
||||
Q_EMIT do_halt_tx (id_, true);
|
||||
Q_EMIT do_halt_tx (key_, true);
|
||||
});
|
||||
connect (halt_tx_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
|
||||
Q_EMIT do_halt_tx (id_, false);
|
||||
Q_EMIT do_halt_tx (key_, false);
|
||||
});
|
||||
content_layout_->addWidget (control_button_box_);
|
||||
|
||||
@ -318,13 +317,13 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
|
||||
|
||||
// connect context menu actions
|
||||
connect (erase_action_, &QAction::triggered, [this] (bool /*checked*/) {
|
||||
Q_EMIT do_clear_decodes (id_);
|
||||
Q_EMIT do_clear_decodes (key_);
|
||||
});
|
||||
connect (erase_rx_frequency_action_, &QAction::triggered, [this] (bool /*checked*/) {
|
||||
Q_EMIT do_clear_decodes (id_, 1);
|
||||
Q_EMIT do_clear_decodes (key_, 1);
|
||||
});
|
||||
connect (erase_both_action_, &QAction::triggered, [this] (bool /*checked*/) {
|
||||
Q_EMIT do_clear_decodes (id_, 2);
|
||||
Q_EMIT do_clear_decodes (key_, 2);
|
||||
});
|
||||
|
||||
// connect up table view signals
|
||||
@ -335,7 +334,7 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
|
||||
// tell new client about calls of interest
|
||||
for (int row = 0; row < calls_of_interest_->count (); ++row)
|
||||
{
|
||||
Q_EMIT highlight_callsign (id_, calls_of_interest_->item (row)->text (), QColor {Qt::blue}, QColor {Qt::yellow});
|
||||
Q_EMIT highlight_callsign (key_, calls_of_interest_->item (row)->text (), QColor {Qt::blue}, QColor {Qt::yellow});
|
||||
}
|
||||
}
|
||||
|
||||
@ -349,7 +348,7 @@ void ClientWidget::closeEvent (QCloseEvent *e)
|
||||
{
|
||||
if (!done_)
|
||||
{
|
||||
Q_EMIT do_close (id_);
|
||||
Q_EMIT do_close (key_);
|
||||
e->ignore (); // defer closure until client actually closes
|
||||
}
|
||||
else
|
||||
@ -363,7 +362,7 @@ ClientWidget::~ClientWidget ()
|
||||
for (int row = 0; row < calls_of_interest_->count (); ++row)
|
||||
{
|
||||
// tell client to forget calls of interest
|
||||
Q_EMIT highlight_callsign (id_, calls_of_interest_->item (row)->text ());
|
||||
Q_EMIT highlight_callsign (key_, calls_of_interest_->item (row)->text ());
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,7 +394,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
void ClientWidget::update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call
|
||||
void ClientWidget::update_status (ClientKey const& key, Frequency f, QString const& mode, QString const& dx_call
|
||||
, QString const& report, QString const& tx_mode, bool tx_enabled
|
||||
, bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df
|
||||
, QString const& de_call, QString const& de_grid, QString const& dx_grid
|
||||
@ -403,7 +402,7 @@ void ClientWidget::update_status (QString const& id, Frequency f, QString const&
|
||||
, quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period
|
||||
, QString const& configuration_name)
|
||||
{
|
||||
if (id == id_)
|
||||
if (key == key_)
|
||||
{
|
||||
fast_mode_check_box_->setChecked (fast_mode);
|
||||
decodes_proxy_model_.de_call (de_call);
|
||||
@ -447,11 +446,11 @@ void ClientWidget::update_status (QString const& id, Frequency f, QString const&
|
||||
}
|
||||
}
|
||||
|
||||
void ClientWidget::decode_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/
|
||||
void ClientWidget::decode_added (bool /*is_new*/, ClientKey const& key, QTime /*time*/, qint32 /*snr*/
|
||||
, float /*delta_time*/, quint32 /*delta_frequency*/, QString const& /*mode*/
|
||||
, QString const& /*message*/, bool /*low_confidence*/, bool /*off_air*/)
|
||||
{
|
||||
if (client_id == id_ && !columns_resized_)
|
||||
if (key == key_ && !columns_resized_)
|
||||
{
|
||||
decodes_stack_->setCurrentIndex (0);
|
||||
decodes_table_view_->resizeColumnsToContents ();
|
||||
@ -460,12 +459,12 @@ void ClientWidget::decode_added (bool /*is_new*/, QString const& client_id, QTim
|
||||
decodes_table_view_->scrollToBottom ();
|
||||
}
|
||||
|
||||
void ClientWidget::beacon_spot_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/
|
||||
void ClientWidget::beacon_spot_added (bool /*is_new*/, ClientKey const& key, QTime /*time*/, qint32 /*snr*/
|
||||
, float /*delta_time*/, Frequency /*delta_frequency*/, qint32 /*drift*/
|
||||
, QString const& /*callsign*/, QString const& /*grid*/, qint32 /*power*/
|
||||
, bool /*off_air*/)
|
||||
{
|
||||
if (client_id == id_ && !columns_resized_)
|
||||
if (key == key_ && !columns_resized_)
|
||||
{
|
||||
decodes_stack_->setCurrentIndex (1);
|
||||
beacons_table_view_->resizeColumnsToContents ();
|
||||
@ -474,9 +473,9 @@ void ClientWidget::beacon_spot_added (bool /*is_new*/, QString const& client_id,
|
||||
beacons_table_view_->scrollToBottom ();
|
||||
}
|
||||
|
||||
void ClientWidget::decodes_cleared (QString const& client_id)
|
||||
void ClientWidget::decodes_cleared (ClientKey const& key)
|
||||
{
|
||||
if (client_id == id_)
|
||||
if (key == key_)
|
||||
{
|
||||
columns_resized_ = false;
|
||||
}
|
||||
|
||||
@ -35,42 +35,44 @@ class ClientWidget
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
using ClientKey = MessageServer::ClientKey;
|
||||
|
||||
public:
|
||||
explicit ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model
|
||||
, QString const& id, QString const& version, QString const& revision
|
||||
, ClientKey const& key, QString const& version, QString const& revision
|
||||
, QListWidget const * calls_of_interest, QWidget * parent = nullptr);
|
||||
void dispose ();
|
||||
~ClientWidget ();
|
||||
|
||||
bool fast_mode () const;
|
||||
|
||||
Q_SLOT void update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call
|
||||
Q_SLOT void update_status (ClientKey const& key, Frequency f, QString const& mode, QString const& dx_call
|
||||
, QString const& report, QString const& tx_mode, bool tx_enabled
|
||||
, bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df
|
||||
, QString const& de_call, QString const& de_grid, QString const& dx_grid
|
||||
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode
|
||||
, quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period
|
||||
, QString const& configuration_name);
|
||||
Q_SLOT void decode_added (bool is_new, QString const& client_id, QTime, qint32 snr
|
||||
Q_SLOT void decode_added (bool is_new, ClientKey const& key, QTime, qint32 snr
|
||||
, float delta_time, quint32 delta_frequency, QString const& mode
|
||||
, QString const& message, bool low_confidence, bool off_air);
|
||||
Q_SLOT void beacon_spot_added (bool is_new, QString const& client_id, QTime, qint32 snr
|
||||
Q_SLOT void beacon_spot_added (bool is_new, ClientKey const& key, QTime, qint32 snr
|
||||
, float delta_time, Frequency delta_frequency, qint32 drift
|
||||
, QString const& callsign, QString const& grid, qint32 power
|
||||
, bool off_air);
|
||||
Q_SLOT void decodes_cleared (QString const& client_id);
|
||||
Q_SLOT void decodes_cleared (ClientKey const& key);
|
||||
|
||||
Q_SIGNAL void do_clear_decodes (QString const& id, quint8 window = 0);
|
||||
Q_SIGNAL void do_close (QString const& id);
|
||||
Q_SIGNAL void do_clear_decodes (ClientKey const& key, quint8 window = 0);
|
||||
Q_SIGNAL void do_close (ClientKey const& key);
|
||||
Q_SIGNAL void do_reply (QModelIndex const&, quint8 modifier);
|
||||
Q_SIGNAL void do_halt_tx (QString const& id, bool auto_only);
|
||||
Q_SIGNAL void do_free_text (QString const& id, QString const& text, bool);
|
||||
Q_SIGNAL void location (QString const& id, QString const& text);
|
||||
Q_SIGNAL void highlight_callsign (QString const& id, QString const& call
|
||||
Q_SIGNAL void do_halt_tx (ClientKey const& key, bool auto_only);
|
||||
Q_SIGNAL void do_free_text (ClientKey const& key, QString const& text, bool);
|
||||
Q_SIGNAL void location (ClientKey const& key, QString const& text);
|
||||
Q_SIGNAL void highlight_callsign (ClientKey const& key, QString const& call
|
||||
, QColor const& bg = QColor {}, QColor const& fg = QColor {}
|
||||
, bool last_only = false);
|
||||
Q_SIGNAL void switch_configuration (QString const& id, QString const& configuration_name);
|
||||
Q_SIGNAL void configure (QString const& id, QString const& mode, quint32 frequency_tolerance
|
||||
Q_SIGNAL void switch_configuration (ClientKey const& key, QString const& configuration_name);
|
||||
Q_SIGNAL void configure (ClientKey const& key, QString const& mode, quint32 frequency_tolerance
|
||||
, QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df
|
||||
, QString const& dx_call, QString const& dx_grid, bool generate_messages);
|
||||
|
||||
@ -79,7 +81,7 @@ private:
|
||||
: public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
IdFilterModel (QString const& client_id, QObject * = nullptr);
|
||||
IdFilterModel (ClientKey const& key, QObject * = nullptr);
|
||||
|
||||
void de_call (QString const&);
|
||||
void rx_df (quint32);
|
||||
@ -88,7 +90,7 @@ private:
|
||||
private:
|
||||
bool filterAcceptsRow (int source_row, QModelIndex const& source_parent) const override;
|
||||
|
||||
QString client_id_;
|
||||
ClientKey key_;
|
||||
QString call_;
|
||||
QRegularExpression base_call_re_;
|
||||
quint32 rx_df_;
|
||||
@ -96,7 +98,7 @@ private:
|
||||
|
||||
void closeEvent (QCloseEvent *) override;
|
||||
|
||||
QString id_;
|
||||
ClientKey key_;
|
||||
bool done_;
|
||||
QListWidget const * calls_of_interest_;
|
||||
IdFilterModel decodes_proxy_model_;
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include <QStandardItem>
|
||||
#include <QModelIndex>
|
||||
#include <QVariant>
|
||||
#include <QTime>
|
||||
#include <QString>
|
||||
#include <QFont>
|
||||
@ -33,10 +34,13 @@ namespace
|
||||
|
||||
QFont text_font {"Courier", 10};
|
||||
|
||||
QList<QStandardItem *> make_row (QString const& client_id, QTime time, qint32 snr, float delta_time
|
||||
, quint32 delta_frequency, QString const& mode, QString const& message
|
||||
, bool low_confidence, bool off_air, bool is_fast)
|
||||
QList<QStandardItem *> make_row (MessageServer::ClientKey const& key, QTime time, qint32 snr
|
||||
, float delta_time, quint32 delta_frequency, QString const& mode
|
||||
, QString const& message, bool low_confidence, bool off_air, bool is_fast)
|
||||
{
|
||||
auto client_item = new QStandardItem {QString {"%1(%2)"}.arg (key.second).arg (key.first.toString ())};
|
||||
client_item->setData (QVariant::fromValue (key));
|
||||
|
||||
auto time_item = new QStandardItem {time.toString (is_fast || "~" == mode ? "hh:mm:ss" : "hh:mm")};
|
||||
time_item->setData (time);
|
||||
time_item->setTextAlignment (Qt::AlignRight);
|
||||
@ -63,7 +67,7 @@ namespace
|
||||
live->setTextAlignment (Qt::AlignHCenter);
|
||||
|
||||
QList<QStandardItem *> row {
|
||||
new QStandardItem {client_id}, time_item, snr_item, dt, df, md, confidence, live, new QStandardItem {message}};
|
||||
client_item, time_item, snr_item, dt, df, md, confidence, live, new QStandardItem {message}};
|
||||
Q_FOREACH (auto& item, row)
|
||||
{
|
||||
item->setEditable (false);
|
||||
@ -84,7 +88,7 @@ DecodesModel::DecodesModel (QObject * parent)
|
||||
}
|
||||
}
|
||||
|
||||
void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time
|
||||
void DecodesModel::add_decode (bool is_new, ClientKey const& key, QTime time, qint32 snr, float delta_time
|
||||
, quint32 delta_frequency, QString const& mode, QString const& message
|
||||
, bool low_confidence, bool off_air, bool is_fast)
|
||||
{
|
||||
@ -93,7 +97,7 @@ void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time
|
||||
int target_row {-1};
|
||||
for (auto row = 0; row < rowCount (); ++row)
|
||||
{
|
||||
if (data (index (row, 0)).toString () == client_id)
|
||||
if (item (row, 0)->data ().value<ClientKey> () == key)
|
||||
{
|
||||
auto row_time = item (row, 1)->data ().toTime ();
|
||||
if (row_time == time
|
||||
@ -115,21 +119,21 @@ void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time
|
||||
}
|
||||
if (target_row >= 0)
|
||||
{
|
||||
insertRow (target_row + 1, make_row (client_id, time, snr, delta_time, delta_frequency, mode
|
||||
insertRow (target_row + 1, make_row (key, time, snr, delta_time, delta_frequency, mode
|
||||
, message, low_confidence, off_air, is_fast));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
appendRow (make_row (client_id, time, snr, delta_time, delta_frequency, mode, message, low_confidence
|
||||
appendRow (make_row (key, time, snr, delta_time, delta_frequency, mode, message, low_confidence
|
||||
, off_air, is_fast));
|
||||
}
|
||||
|
||||
void DecodesModel::decodes_cleared (QString const& client_id)
|
||||
void DecodesModel::decodes_cleared (ClientKey const& key)
|
||||
{
|
||||
for (auto row = rowCount () - 1; row >= 0; --row)
|
||||
{
|
||||
if (data (index (row, 0)).toString () == client_id)
|
||||
if (item (row, 0)->data ().value<ClientKey> () == key)
|
||||
{
|
||||
removeRow (row);
|
||||
}
|
||||
@ -139,7 +143,7 @@ void DecodesModel::decodes_cleared (QString const& client_id)
|
||||
void DecodesModel::do_reply (QModelIndex const& source, quint8 modifiers)
|
||||
{
|
||||
auto row = source.row ();
|
||||
Q_EMIT reply (data (index (row, 0)).toString ()
|
||||
Q_EMIT reply (item (row, 0)->data ().value<ClientKey> ()
|
||||
, item (row, 1)->data ().toTime ()
|
||||
, item (row, 2)->data ().toInt ()
|
||||
, item (row, 3)->data ().toFloat ()
|
||||
|
||||
@ -5,8 +5,6 @@
|
||||
|
||||
#include "MessageServer.hpp"
|
||||
|
||||
using Frequency = MessageServer::Frequency;
|
||||
|
||||
class QTime;
|
||||
class QString;
|
||||
class QModelIndex;
|
||||
@ -28,16 +26,18 @@ class DecodesModel
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
using ClientKey = MessageServer::ClientKey;
|
||||
|
||||
public:
|
||||
explicit DecodesModel (QObject * parent = nullptr);
|
||||
|
||||
Q_SLOT void add_decode (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time
|
||||
Q_SLOT void add_decode (bool is_new, ClientKey const&, QTime, qint32 snr, float delta_time
|
||||
, quint32 delta_frequency, QString const& mode, QString const& message
|
||||
, bool low_confidence, bool off_air, bool is_fast);
|
||||
Q_SLOT void decodes_cleared (QString const& client_id);
|
||||
Q_SLOT void decodes_cleared (ClientKey const&);
|
||||
Q_SLOT void do_reply (QModelIndex const& source, quint8 modifiers);
|
||||
|
||||
Q_SIGNAL void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
|
||||
Q_SIGNAL void reply (ClientKey const&, QTime, qint32 snr, float delta_time, quint32 delta_frequency
|
||||
, QString const& mode, QString const& message, bool low_confidence, quint8 modifiers);
|
||||
};
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QDateTime>
|
||||
#include <QNetworkInterface>
|
||||
#include <QSet>
|
||||
|
||||
#include "DecodesModel.hpp"
|
||||
#include "BeaconsModel.hpp"
|
||||
@ -37,8 +39,10 @@ MessageAggregatorMainWindow::MessageAggregatorMainWindow ()
|
||||
, decodes_model_ {new DecodesModel {this}}
|
||||
, beacons_model_ {new BeaconsModel {this}}
|
||||
, server_ {new MessageServer {this}}
|
||||
, multicast_group_line_edit_ {new QLineEdit}
|
||||
, log_table_view_ {new QTableView}
|
||||
, port_spin_box_ {new QSpinBox {this}}
|
||||
, multicast_group_line_edit_ {new QLineEdit {this}}
|
||||
, network_interfaces_combo_box_ {new CheckableItemComboBox {this}}
|
||||
, log_table_view_ {new QTableView {this}}
|
||||
, add_call_of_interest_action_ {new QAction {tr ("&Add callsign"), this}}
|
||||
, delete_call_of_interest_action_ {new QAction {tr ("&Delete callsign"), this}}
|
||||
, last_call_of_interest_action_ {new QAction {tr ("&Highlight last only"), this}}
|
||||
@ -68,16 +72,71 @@ MessageAggregatorMainWindow::MessageAggregatorMainWindow ()
|
||||
auto central_layout = new QVBoxLayout;
|
||||
|
||||
// server details
|
||||
auto port_spin_box = new QSpinBox;
|
||||
port_spin_box->setMinimum (1);
|
||||
port_spin_box->setMaximum (std::numeric_limits<port_type>::max ());
|
||||
port_spin_box_->setMinimum (1);
|
||||
port_spin_box_->setMaximum (std::numeric_limits<port_type>::max ());
|
||||
auto group_box_layout = new QFormLayout;
|
||||
group_box_layout->addRow (tr ("Port number:"), port_spin_box);
|
||||
group_box_layout->addRow (tr ("Port number:"), port_spin_box_);
|
||||
group_box_layout->addRow (tr ("Multicast Group (blank for unicast server):"), multicast_group_line_edit_);
|
||||
group_box_layout->addRow (tr ("Network interfaces:"), network_interfaces_combo_box_);
|
||||
int row;
|
||||
QFormLayout::ItemRole role;
|
||||
group_box_layout->getWidgetPosition (network_interfaces_combo_box_, &row, &role);
|
||||
Q_ASSERT (row >= 0);
|
||||
network_interfaces_form_label_widget_ = static_cast<QLabel *> (group_box_layout->itemAt (row, QFormLayout::LabelRole)->widget ());
|
||||
network_interfaces_form_label_widget_->hide ();
|
||||
network_interfaces_form_label_widget_->buddy ()->hide ();
|
||||
connect (multicast_group_line_edit_, &QLineEdit::editingFinished, [this] {
|
||||
if (multicast_group_line_edit_->text ().size ())
|
||||
{
|
||||
network_interfaces_form_label_widget_->show ();
|
||||
network_interfaces_form_label_widget_->buddy ()->show ();
|
||||
}
|
||||
else
|
||||
{
|
||||
network_interfaces_form_label_widget_->hide ();
|
||||
network_interfaces_form_label_widget_->buddy ()->hide ();
|
||||
}
|
||||
});
|
||||
auto group_box = new QGroupBox {tr ("Server Details")};
|
||||
group_box->setLayout (group_box_layout);
|
||||
central_layout->addWidget (group_box);
|
||||
|
||||
// populate network interface list
|
||||
for (auto const& net_if : QNetworkInterface::allInterfaces ())
|
||||
{
|
||||
auto flags = QNetworkInterface::IsRunning | QNetworkInterface::CanMulticast;
|
||||
if ((net_if.flags () & flags) == flags)
|
||||
{
|
||||
if (net_if.flags () & QNetworkInterface::IsLoopBack)
|
||||
{
|
||||
loopback_interface_name_ = net_if.name ();
|
||||
}
|
||||
auto item = network_interfaces_combo_box_->addCheckItem (net_if.humanReadableName ()
|
||||
, net_if.name ()
|
||||
, Qt::Unchecked);
|
||||
auto tip = QString {"name(index): %1(%2) - %3"}
|
||||
.arg (net_if.name ()).arg (net_if.index ())
|
||||
.arg (net_if.flags () & QNetworkInterface::IsUp ? "Up" : "Down");
|
||||
auto hw_addr = net_if.hardwareAddress ();
|
||||
if (hw_addr.size ())
|
||||
{
|
||||
tip += QString {"\nhw: %1"}.arg (net_if.hardwareAddress ());
|
||||
}
|
||||
auto aes = net_if.addressEntries ();
|
||||
if (aes.size ())
|
||||
{
|
||||
tip += "\naddresses:";
|
||||
for (auto const& ae : aes)
|
||||
{
|
||||
tip += QString {"\n ip: %1/%2"}.arg (ae.ip ().toString ()).arg (ae.prefixLength ());
|
||||
}
|
||||
}
|
||||
item->setToolTip (tip);
|
||||
}
|
||||
}
|
||||
connect (network_interfaces_combo_box_, &QComboBox::currentTextChanged, this, &MessageAggregatorMainWindow::validate_network_interfaces);
|
||||
validate_network_interfaces (QString {});
|
||||
|
||||
log_table_view_->setModel (log_);
|
||||
log_table_view_->verticalHeader ()->hide ();
|
||||
central_layout->addWidget (log_table_view_);
|
||||
@ -184,30 +243,52 @@ MessageAggregatorMainWindow::MessageAggregatorMainWindow ()
|
||||
connect (server_, &MessageServer::client_closed, this, &MessageAggregatorMainWindow::remove_client);
|
||||
connect (server_, &MessageServer::client_closed, decodes_model_, &DecodesModel::decodes_cleared);
|
||||
connect (server_, &MessageServer::client_closed, beacons_model_, &BeaconsModel::decodes_cleared);
|
||||
connect (server_, &MessageServer::decode, [this] (bool is_new, QString const& id, QTime time
|
||||
connect (server_, &MessageServer::decode, [this] (bool is_new, ClientKey const& key, QTime time
|
||||
, qint32 snr, float delta_time
|
||||
, quint32 delta_frequency, QString const& mode
|
||||
, QString const& message, bool low_confidence
|
||||
, bool off_air) {
|
||||
decodes_model_->add_decode (is_new, id, time, snr, delta_time, delta_frequency, mode, message
|
||||
, low_confidence, off_air, dock_widgets_[id]->fast_mode ());});
|
||||
decodes_model_->add_decode (is_new, key, time, snr, delta_time
|
||||
, delta_frequency, mode, message
|
||||
, low_confidence, off_air
|
||||
, dock_widgets_[key]->fast_mode ());
|
||||
});
|
||||
connect (server_, &MessageServer::WSPR_decode, beacons_model_, &BeaconsModel::add_beacon_spot);
|
||||
connect (server_, &MessageServer::decodes_cleared, decodes_model_, &DecodesModel::decodes_cleared);
|
||||
connect (server_, &MessageServer::decodes_cleared, beacons_model_, &BeaconsModel::decodes_cleared);
|
||||
connect (decodes_model_, &DecodesModel::reply, server_, &MessageServer::reply);
|
||||
|
||||
// UI behaviour
|
||||
connect (port_spin_box, static_cast<void (QSpinBox::*)(int)> (&QSpinBox::valueChanged)
|
||||
, [this] (port_type port) {server_->start (port);});
|
||||
connect (multicast_group_line_edit_, &QLineEdit::editingFinished, [this, port_spin_box] () {
|
||||
server_->start (port_spin_box->value (), QHostAddress {multicast_group_line_edit_->text ()});
|
||||
});
|
||||
connect (port_spin_box_, static_cast<void (QSpinBox::*)(int)> (&QSpinBox::valueChanged)
|
||||
, [this] (int /*port*/) {restart_server ();});
|
||||
connect (multicast_group_line_edit_, &QLineEdit::editingFinished, [this] () {restart_server ();});
|
||||
connect (network_interfaces_combo_box_, &QComboBox::currentTextChanged, [this] () {restart_server ();});
|
||||
|
||||
port_spin_box->setValue (2237); // start up in unicast mode
|
||||
port_spin_box_->setValue (2237); // start up in unicast mode
|
||||
show ();
|
||||
}
|
||||
|
||||
void MessageAggregatorMainWindow::log_qso (QString const& /*id*/, QDateTime time_off, QString const& dx_call
|
||||
void MessageAggregatorMainWindow::restart_server ()
|
||||
{
|
||||
QSet<QString> net_ifs;
|
||||
if (network_interfaces_combo_box_->isVisible ())
|
||||
{
|
||||
auto model = static_cast<QStandardItemModel *> (network_interfaces_combo_box_->model ());
|
||||
for (int row = 0; row < model->rowCount (); ++row)
|
||||
{
|
||||
if (Qt::Checked == model->item (row)->checkState ())
|
||||
{
|
||||
net_ifs << model->item (row)->data ().toString ();
|
||||
}
|
||||
}
|
||||
}
|
||||
server_->start (port_spin_box_->value ()
|
||||
, QHostAddress {multicast_group_line_edit_->text ()}
|
||||
, net_ifs);
|
||||
}
|
||||
|
||||
void MessageAggregatorMainWindow::log_qso (ClientKey const& /*key*/, QDateTime time_off
|
||||
, QString const& dx_call
|
||||
, QString const& dx_grid, Frequency dial_frequency, QString const& mode
|
||||
, QString const& report_sent, QString const& report_received
|
||||
, QString const& tx_power, QString const& comments
|
||||
@ -240,9 +321,9 @@ void MessageAggregatorMainWindow::log_qso (QString const& /*id*/, QDateTime time
|
||||
log_table_view_->scrollToBottom ();
|
||||
}
|
||||
|
||||
void MessageAggregatorMainWindow::add_client (QString const& id, QString const& version, QString const& revision)
|
||||
void MessageAggregatorMainWindow::add_client (ClientKey const& key, QString const& version, QString const& revision)
|
||||
{
|
||||
auto dock = new ClientWidget {decodes_model_, beacons_model_, id, version, revision, calls_of_interest_, this};
|
||||
auto dock = new ClientWidget {decodes_model_, beacons_model_, key, version, revision, calls_of_interest_, this};
|
||||
dock->setAttribute (Qt::WA_DeleteOnClose);
|
||||
auto view_action = dock->toggleViewAction ();
|
||||
view_action->setEnabled (true);
|
||||
@ -262,13 +343,13 @@ void MessageAggregatorMainWindow::add_client (QString const& id, QString const&
|
||||
connect (dock, &ClientWidget::highlight_callsign, server_, &MessageServer::highlight_callsign);
|
||||
connect (dock, &ClientWidget::switch_configuration, server_, &MessageServer::switch_configuration);
|
||||
connect (dock, &ClientWidget::configure, server_, &MessageServer::configure);
|
||||
dock_widgets_[id] = dock;
|
||||
server_->replay (id); // request decodes and status
|
||||
dock_widgets_[key] = dock;
|
||||
server_->replay (key); // request decodes and status
|
||||
}
|
||||
|
||||
void MessageAggregatorMainWindow::remove_client (QString const& id)
|
||||
void MessageAggregatorMainWindow::remove_client (ClientKey const& key)
|
||||
{
|
||||
auto iter = dock_widgets_.find (id);
|
||||
auto iter = dock_widgets_.find (key);
|
||||
if (iter != std::end (dock_widgets_))
|
||||
{
|
||||
(*iter)->dispose ();
|
||||
@ -287,9 +368,35 @@ MessageAggregatorMainWindow::~MessageAggregatorMainWindow ()
|
||||
void MessageAggregatorMainWindow::change_highlighting (QString const& call, QColor const& bg, QColor const& fg
|
||||
, bool last_only)
|
||||
{
|
||||
for (auto id : dock_widgets_.keys ())
|
||||
for (auto key : dock_widgets_.keys ())
|
||||
{
|
||||
server_->highlight_callsign (id, call, bg, fg, last_only);
|
||||
server_->highlight_callsign (key, call, bg, fg, last_only);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageAggregatorMainWindow::validate_network_interfaces (QString const& /*text*/)
|
||||
{
|
||||
auto model = static_cast<QStandardItemModel *> (network_interfaces_combo_box_->model ());
|
||||
bool has_checked {false};
|
||||
int loopback_row {-1};
|
||||
for (int row = 0; row < model->rowCount (); ++row)
|
||||
{
|
||||
if (model->item (row)->data ().toString () == loopback_interface_name_)
|
||||
{
|
||||
loopback_row = row;
|
||||
}
|
||||
else if (Qt::Checked == model->item (row)->checkState ())
|
||||
{
|
||||
has_checked = true;
|
||||
}
|
||||
}
|
||||
if (loopback_row >= 0)
|
||||
{
|
||||
if (!has_checked)
|
||||
{
|
||||
model->item (loopback_row)->setCheckState (Qt::Checked);
|
||||
}
|
||||
model->item (loopback_row)->setEnabled (has_checked);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <QString>
|
||||
|
||||
#include "MessageServer.hpp"
|
||||
#include "widgets/CheckableItemComboBox.hpp"
|
||||
|
||||
class QDateTime;
|
||||
class QStandardItemModel;
|
||||
@ -16,6 +17,8 @@ class QLineEdit;
|
||||
class QTableView;
|
||||
class ClientWidget;
|
||||
class QListWidget;
|
||||
class QLabel;
|
||||
class QSpinBox;
|
||||
|
||||
using Frequency = MessageServer::Frequency;
|
||||
|
||||
@ -24,11 +27,13 @@ class MessageAggregatorMainWindow
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
using ClientKey = MessageServer::ClientKey;
|
||||
|
||||
public:
|
||||
MessageAggregatorMainWindow ();
|
||||
~MessageAggregatorMainWindow ();
|
||||
|
||||
Q_SLOT void log_qso (QString const& /*id*/, QDateTime time_off, QString const& dx_call, QString const& dx_grid
|
||||
Q_SLOT void log_qso (ClientKey const&, QDateTime time_off, QString const& dx_call, QString const& dx_grid
|
||||
, Frequency dial_frequency, QString const& mode, QString const& report_sent
|
||||
, QString const& report_received, QString const& tx_power, QString const& comments
|
||||
, QString const& name, QDateTime time_on, QString const& operator_call
|
||||
@ -36,13 +41,15 @@ public:
|
||||
, QString const& exchange_sent, QString const& exchange_rcvd, QString const& prop_mode);
|
||||
|
||||
private:
|
||||
void add_client (QString const& id, QString const& version, QString const& revision);
|
||||
void remove_client (QString const& id);
|
||||
void restart_server ();
|
||||
void add_client (ClientKey const&, QString const& version, QString const& revision);
|
||||
void remove_client (ClientKey const&);
|
||||
void change_highlighting (QString const& call, QColor const& bg = QColor {}, QColor const& fg = QColor {},
|
||||
bool last_only = false);
|
||||
Q_SLOT void validate_network_interfaces (QString const&);
|
||||
|
||||
// maps client id to widgets
|
||||
using ClientsDictionary = QHash<QString, ClientWidget *>;
|
||||
using ClientsDictionary = QHash<ClientKey, ClientWidget *>;
|
||||
ClientsDictionary dock_widgets_;
|
||||
|
||||
QStandardItemModel * log_;
|
||||
@ -50,7 +57,11 @@ private:
|
||||
DecodesModel * decodes_model_;
|
||||
BeaconsModel * beacons_model_;
|
||||
MessageServer * server_;
|
||||
QSpinBox * port_spin_box_;
|
||||
QLineEdit * multicast_group_line_edit_;
|
||||
CheckableItemComboBox * network_interfaces_combo_box_;
|
||||
QString loopback_interface_name_;
|
||||
QLabel * network_interfaces_form_label_widget_;
|
||||
QTableView * log_table_view_;
|
||||
QListWidget * calls_of_interest_;
|
||||
QAction * add_call_of_interest_action_;
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
|
||||
#include <QNetworkInterface>
|
||||
#include <QUdpSocket>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
#include <QHash>
|
||||
|
||||
@ -32,7 +31,6 @@ public:
|
||||
: self_ {self}
|
||||
, version_ {version}
|
||||
, revision_ {revision}
|
||||
, port_ {0u}
|
||||
, clock_ {new QTimer {this}}
|
||||
{
|
||||
// register the required types with Qt
|
||||
@ -78,15 +76,14 @@ public:
|
||||
MessageServer * self_;
|
||||
QString version_;
|
||||
QString revision_;
|
||||
port_type port_;
|
||||
QHostAddress multicast_group_address_;
|
||||
QSet<QString> network_interfaces_;
|
||||
static BindMode constexpr bind_mode_ = ShareAddress | ReuseAddressHint;
|
||||
struct Client
|
||||
{
|
||||
Client () = default;
|
||||
Client (QHostAddress const& sender_address, port_type const& sender_port)
|
||||
: sender_address_ {sender_address}
|
||||
, sender_port_ {sender_port}
|
||||
Client (port_type const& sender_port)
|
||||
: sender_port_ {sender_port}
|
||||
, negotiated_schema_number_ {2} // not 1 because it's broken
|
||||
, last_activity_ {QDateTime::currentDateTime ()}
|
||||
{
|
||||
@ -94,12 +91,11 @@ public:
|
||||
Client (Client const&) = default;
|
||||
Client& operator= (Client const&) = default;
|
||||
|
||||
QHostAddress sender_address_;
|
||||
port_type sender_port_;
|
||||
quint32 negotiated_schema_number_;
|
||||
QDateTime last_activity_;
|
||||
};
|
||||
QHash<QString, Client> clients_; // maps id to Client
|
||||
QHash<ClientKey, Client> clients_; // maps id to Client
|
||||
QTimer * clock_;
|
||||
};
|
||||
|
||||
@ -109,56 +105,39 @@ MessageServer::impl::BindMode constexpr MessageServer::impl::bind_mode_;
|
||||
|
||||
void MessageServer::impl::leave_multicast_group ()
|
||||
{
|
||||
if (!multicast_group_address_.isNull () && BoundState == state ()
|
||||
#if QT_VERSION >= 0x050600
|
||||
&& multicast_group_address_.isMulticast ()
|
||||
#endif
|
||||
)
|
||||
if (BoundState == state () && is_multicast_address (multicast_group_address_))
|
||||
{
|
||||
for (auto const& interface : QNetworkInterface::allInterfaces ())
|
||||
for (auto const& if_name : network_interfaces_)
|
||||
{
|
||||
if (QNetworkInterface::CanMulticast & interface.flags ())
|
||||
{
|
||||
leaveMulticastGroup (multicast_group_address_, interface);
|
||||
}
|
||||
leaveMulticastGroup (multicast_group_address_, QNetworkInterface::interfaceFromName (if_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::impl::join_multicast_group ()
|
||||
{
|
||||
if (BoundState == state ()
|
||||
&& !multicast_group_address_.isNull ()
|
||||
#if QT_VERSION >= 0x050600
|
||||
&& multicast_group_address_.isMulticast ()
|
||||
#endif
|
||||
)
|
||||
if (BoundState == state () && is_multicast_address (multicast_group_address_))
|
||||
{
|
||||
auto mcast_iface = multicastInterface ();
|
||||
if (IPv4Protocol == multicast_group_address_.protocol ()
|
||||
&& IPv4Protocol != localAddress ().protocol ())
|
||||
if (network_interfaces_.size ())
|
||||
{
|
||||
close ();
|
||||
bind (QHostAddress::AnyIPv4, port_, bind_mode_);
|
||||
}
|
||||
bool joined {false};
|
||||
for (auto const& interface : QNetworkInterface::allInterfaces ())
|
||||
{
|
||||
if (QNetworkInterface::CanMulticast & interface.flags ())
|
||||
for (auto const& if_name : network_interfaces_)
|
||||
{
|
||||
// Windows requires outgoing interface to match
|
||||
// interface to be joined while joining, at least for
|
||||
// IPv4 it seems to
|
||||
setMulticastInterface (interface);
|
||||
|
||||
joined |= joinMulticastGroup (multicast_group_address_, interface);
|
||||
joinMulticastGroup (multicast_group_address_, QNetworkInterface::interfaceFromName (if_name));
|
||||
}
|
||||
}
|
||||
if (!joined)
|
||||
else
|
||||
{
|
||||
multicast_group_address_.clear ();
|
||||
// find the loop-back interface and join on that
|
||||
for (auto const& net_if : QNetworkInterface::allInterfaces ())
|
||||
{
|
||||
auto flags = QNetworkInterface::IsUp | QNetworkInterface::IsLoopBack | QNetworkInterface::CanMulticast;
|
||||
if ((net_if.flags () & flags) == flags)
|
||||
{
|
||||
joinMulticastGroup (multicast_group_address_, net_if);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
setMulticastInterface (mcast_iface);
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,9 +168,10 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
auto id = in.id ();
|
||||
if (OK == check_status (in))
|
||||
{
|
||||
if (!clients_.contains (id))
|
||||
auto client_key = ClientKey {sender, id};
|
||||
if (!clients_.contains (client_key))
|
||||
{
|
||||
auto& client = (clients_[id] = {sender, sender_port});
|
||||
auto& client = (clients_[client_key] = {sender_port});
|
||||
QByteArray client_version;
|
||||
QByteArray client_revision;
|
||||
|
||||
@ -212,7 +192,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
<< version_.toUtf8 () << revision_.toUtf8 ();
|
||||
if (impl::OK == check_status (hb))
|
||||
{
|
||||
writeDatagram (message, client.sender_address_, client.sender_port_);
|
||||
writeDatagram (message, client_key.first, sender_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -222,10 +202,10 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
// we don't care if this fails to read
|
||||
in >> client_version >> client_revision;
|
||||
}
|
||||
Q_EMIT self_->client_opened (id, QString::fromUtf8 (client_version),
|
||||
Q_EMIT self_->client_opened (client_key, QString::fromUtf8 (client_version),
|
||||
QString::fromUtf8 (client_revision));
|
||||
}
|
||||
clients_[id].last_activity_ = QDateTime::currentDateTime ();
|
||||
clients_[client_key].last_activity_ = QDateTime::currentDateTime ();
|
||||
|
||||
//
|
||||
// message format is described in NetworkMessage.hpp
|
||||
@ -237,7 +217,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
break;
|
||||
|
||||
case NetworkMessage::Clear:
|
||||
Q_EMIT self_->decodes_cleared (id);
|
||||
Q_EMIT self_->decodes_cleared (client_key);
|
||||
break;
|
||||
|
||||
case NetworkMessage::Status:
|
||||
@ -268,7 +248,8 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
>> fast_mode >> special_op_mode >> frequency_tolerance >> tr_period >> configuration_name;
|
||||
if (check_status (in) != Fail)
|
||||
{
|
||||
Q_EMIT self_->status_update (id, f, QString::fromUtf8 (mode), QString::fromUtf8 (dx_call)
|
||||
Q_EMIT self_->status_update (client_key, f, QString::fromUtf8 (mode)
|
||||
, QString::fromUtf8 (dx_call)
|
||||
, QString::fromUtf8 (report), QString::fromUtf8 (tx_mode)
|
||||
, tx_enabled, transmitting, decoding, rx_df, tx_df
|
||||
, QString::fromUtf8 (de_call), QString::fromUtf8 (de_grid)
|
||||
@ -296,7 +277,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
>> message >> low_confidence >> off_air;
|
||||
if (check_status (in) != Fail)
|
||||
{
|
||||
Q_EMIT self_->decode (is_new, id, time, snr, delta_time, delta_frequency
|
||||
Q_EMIT self_->decode (is_new, client_key, time, snr, delta_time, delta_frequency
|
||||
, QString::fromUtf8 (mode), QString::fromUtf8 (message)
|
||||
, low_confidence, off_air);
|
||||
}
|
||||
@ -320,7 +301,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
>> off_air;
|
||||
if (check_status (in) != Fail)
|
||||
{
|
||||
Q_EMIT self_->WSPR_decode (is_new, id, time, snr, delta_time, frequency, drift
|
||||
Q_EMIT self_->WSPR_decode (is_new, client_key, time, snr, delta_time, frequency, drift
|
||||
, QString::fromUtf8 (callsign), QString::fromUtf8 (grid)
|
||||
, power, off_air);
|
||||
}
|
||||
@ -351,8 +332,10 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
>> exchange_sent >> exchange_rcvd >> prop_mode;
|
||||
if (check_status (in) != Fail)
|
||||
{
|
||||
Q_EMIT self_->qso_logged (id, time_off, QString::fromUtf8 (dx_call), QString::fromUtf8 (dx_grid)
|
||||
, dial_frequency, QString::fromUtf8 (mode), QString::fromUtf8 (report_sent)
|
||||
Q_EMIT self_->qso_logged (client_key, time_off, QString::fromUtf8 (dx_call)
|
||||
, QString::fromUtf8 (dx_grid)
|
||||
, dial_frequency, QString::fromUtf8 (mode)
|
||||
, QString::fromUtf8 (report_sent)
|
||||
, QString::fromUtf8 (report_received), QString::fromUtf8 (tx_power)
|
||||
, QString::fromUtf8 (comments), QString::fromUtf8 (name), time_on
|
||||
, QString::fromUtf8 (operator_call), QString::fromUtf8 (my_call)
|
||||
@ -363,8 +346,8 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
break;
|
||||
|
||||
case NetworkMessage::Close:
|
||||
Q_EMIT self_->client_closed (id);
|
||||
clients_.remove (id);
|
||||
Q_EMIT self_->client_closed (client_key);
|
||||
clients_.remove (client_key);
|
||||
break;
|
||||
|
||||
case NetworkMessage::LoggedADIF:
|
||||
@ -373,7 +356,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
in >> ADIF;
|
||||
if (check_status (in) != Fail)
|
||||
{
|
||||
Q_EMIT self_->logged_ADIF (id, ADIF);
|
||||
Q_EMIT self_->logged_ADIF (client_key, ADIF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -406,7 +389,7 @@ void MessageServer::impl::tick ()
|
||||
{
|
||||
if (now > (*iter).last_activity_.addSecs (NetworkMessage::pulse))
|
||||
{
|
||||
Q_EMIT self_->clear_decodes (iter.key ());
|
||||
Q_EMIT self_->decodes_cleared (iter.key ());
|
||||
Q_EMIT self_->client_closed (iter.key ());
|
||||
iter = clients_.erase (iter); // safe while iterating as doesn't rehash
|
||||
}
|
||||
@ -448,152 +431,162 @@ MessageServer::MessageServer (QObject * parent, QString const& version, QString
|
||||
{
|
||||
}
|
||||
|
||||
void MessageServer::start (port_type port, QHostAddress const& multicast_group_address)
|
||||
void MessageServer::start (port_type port, QHostAddress const& multicast_group_address
|
||||
, QSet<QString> const& network_interface_names)
|
||||
{
|
||||
if (port != m_->port_
|
||||
|| multicast_group_address != m_->multicast_group_address_)
|
||||
// qDebug () << "MessageServer::start port:" << port << "multicast addr:" << multicast_group_address.toString () << "network interfaces:" << network_interface_names;
|
||||
if (port != m_->localPort ()
|
||||
|| multicast_group_address != m_->multicast_group_address_
|
||||
|| network_interface_names != m_->network_interfaces_)
|
||||
{
|
||||
m_->leave_multicast_group ();
|
||||
if (impl::BoundState == m_->state ())
|
||||
if (impl::UnconnectedState != m_->state ())
|
||||
{
|
||||
m_->close ();
|
||||
}
|
||||
m_->multicast_group_address_ = multicast_group_address;
|
||||
auto address = m_->multicast_group_address_.isNull ()
|
||||
|| impl::IPv4Protocol != m_->multicast_group_address_.protocol () ? QHostAddress::Any : QHostAddress::AnyIPv4;
|
||||
if (port && m_->bind (address, port, m_->bind_mode_))
|
||||
if (!(multicast_group_address.isNull () || is_multicast_address (multicast_group_address)))
|
||||
{
|
||||
m_->port_ = port;
|
||||
m_->join_multicast_group ();
|
||||
Q_EMIT error ("Invalid multicast group address");
|
||||
}
|
||||
else if (is_MAC_ambiguous_multicast_address (multicast_group_address))
|
||||
{
|
||||
Q_EMIT error ("MAC-ambiguous IPv4 multicast group address not supported");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_->port_ = 0;
|
||||
m_->multicast_group_address_ = multicast_group_address;
|
||||
m_->network_interfaces_ = network_interface_names;
|
||||
QHostAddress local_addr {is_multicast_address (multicast_group_address)
|
||||
&& impl::IPv4Protocol == multicast_group_address.protocol () ? QHostAddress::AnyIPv4 : QHostAddress::Any};
|
||||
if (port && m_->bind (local_addr, port, m_->bind_mode_))
|
||||
{
|
||||
m_->join_multicast_group ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::clear_decodes (QString const& id, quint8 window)
|
||||
void MessageServer::clear_decodes (ClientKey const& key, quint8 window)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
auto iter = m_->clients_.find (key);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Clear, id, (*iter).negotiated_schema_number_};
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Clear, key.second, (*iter).negotiated_schema_number_};
|
||||
out << window;
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
m_->send_message (out, message, key.first, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::reply (QString const& id, QTime time, qint32 snr, float delta_time
|
||||
void MessageServer::reply (ClientKey const& key, QTime time, qint32 snr, float delta_time
|
||||
, quint32 delta_frequency, QString const& mode
|
||||
, QString const& message_text, bool low_confidence, quint8 modifiers)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
auto iter = m_->clients_.find (key);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Reply, id, (*iter).negotiated_schema_number_};
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Reply, key.second, (*iter).negotiated_schema_number_};
|
||||
out << time << snr << delta_time << delta_frequency << mode.toUtf8 ()
|
||||
<< message_text.toUtf8 () << low_confidence << modifiers;
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
m_->send_message (out, message, key.first, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::replay (QString const& id)
|
||||
void MessageServer::replay (ClientKey const& key)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
auto iter = m_->clients_.find (key);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Replay, id, (*iter).negotiated_schema_number_};
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Replay, key.second, (*iter).negotiated_schema_number_};
|
||||
m_->send_message (out, message, key.first, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::close (QString const& id)
|
||||
void MessageServer::close (ClientKey const& key)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
auto iter = m_->clients_.find (key);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Close, id, (*iter).negotiated_schema_number_};
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Close, key.second, (*iter).negotiated_schema_number_};
|
||||
m_->send_message (out, message, key.first, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::halt_tx (QString const& id, bool auto_only)
|
||||
void MessageServer::halt_tx (ClientKey const& key, bool auto_only)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
auto iter = m_->clients_.find (key);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::HaltTx, id, (*iter).negotiated_schema_number_};
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::HaltTx, key.second, (*iter).negotiated_schema_number_};
|
||||
out << auto_only;
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
m_->send_message (out, message, key.first, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::free_text (QString const& id, QString const& text, bool send)
|
||||
void MessageServer::free_text (ClientKey const& key, QString const& text, bool send)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
auto iter = m_->clients_.find (key);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::FreeText, id, (*iter).negotiated_schema_number_};
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::FreeText, key.second, (*iter).negotiated_schema_number_};
|
||||
out << text.toUtf8 () << send;
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
m_->send_message (out, message, key.first, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::location (QString const& id, QString const& loc)
|
||||
void MessageServer::location (ClientKey const& key, QString const& loc)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
auto iter = m_->clients_.find (key);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Location, id, (*iter).negotiated_schema_number_};
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Location, key.second, (*iter).negotiated_schema_number_};
|
||||
out << loc.toUtf8 ();
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
m_->send_message (out, message, key.first, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::highlight_callsign (QString const& id, QString const& callsign
|
||||
void MessageServer::highlight_callsign (ClientKey const& key, QString const& callsign
|
||||
, QColor const& bg, QColor const& fg, bool last_only)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
auto iter = m_->clients_.find (key);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::HighlightCallsign, id, (*iter).negotiated_schema_number_};
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::HighlightCallsign, key.second, (*iter).negotiated_schema_number_};
|
||||
out << callsign.toUtf8 () << bg << fg << last_only;
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
m_->send_message (out, message, key.first, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::switch_configuration (QString const& id, QString const& configuration_name)
|
||||
void MessageServer::switch_configuration (ClientKey const& key, QString const& configuration_name)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
auto iter = m_->clients_.find (key);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::SwitchConfiguration, id, (*iter).negotiated_schema_number_};
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::SwitchConfiguration, key.second, (*iter).negotiated_schema_number_};
|
||||
out << configuration_name.toUtf8 ();
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
m_->send_message (out, message, key.first, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::configure (QString const& id, QString const& mode, quint32 frequency_tolerance
|
||||
void MessageServer::configure (ClientKey const& key, QString const& mode, quint32 frequency_tolerance
|
||||
, QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df
|
||||
, QString const& dx_call, QString const& dx_grid, bool generate_messages)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
auto iter = m_->clients_.find (key);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Configure, id, (*iter).negotiated_schema_number_};
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Configure, key.second, (*iter).negotiated_schema_number_};
|
||||
out << mode.toUtf8 () << frequency_tolerance << submode.toUtf8 () << fast_mode << tr_period << rx_df
|
||||
<< dx_call.toUtf8 () << dx_grid.toUtf8 () << generate_messages;
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
m_->send_message (out, message, key.first, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
#define MESSAGE_SERVER_HPP__
|
||||
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QString>
|
||||
#include <QSet>
|
||||
#include <QTime>
|
||||
#include <QDateTime>
|
||||
#include <QHostAddress>
|
||||
@ -31,6 +34,7 @@ class UDP_EXPORT MessageServer
|
||||
public:
|
||||
using port_type = quint16;
|
||||
using Frequency = Radio::Frequency;
|
||||
using ClientKey = QPair<QHostAddress, QString>;
|
||||
|
||||
MessageServer (QObject * parent = nullptr,
|
||||
QString const& version = QString {}, QString const& revision = QString {});
|
||||
@ -38,77 +42,77 @@ public:
|
||||
// start or restart the server, if the multicast_group_address
|
||||
// argument is given it is assumed to be a multicast group address
|
||||
// which the server will join
|
||||
Q_SLOT void start (port_type port,
|
||||
QHostAddress const& multicast_group_address = QHostAddress {});
|
||||
Q_SLOT void start (port_type port
|
||||
, QHostAddress const& multicast_group_address = QHostAddress {}
|
||||
, QSet<QString> const& network_interface_names = QSet<QString> {});
|
||||
|
||||
// ask the client to clear one or both of the decode windows
|
||||
Q_SLOT void clear_decodes (QString const& id, quint8 window = 0);
|
||||
Q_SLOT void clear_decodes (ClientKey const&, quint8 window = 0);
|
||||
|
||||
// ask the client with identification 'id' to make the same action
|
||||
// as a double click on the decode would
|
||||
//
|
||||
// note that the client is not obliged to take any action and only
|
||||
// takes any action if the decode is present and is a CQ or QRZ message
|
||||
Q_SLOT void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
|
||||
Q_SLOT void reply (ClientKey const&, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
|
||||
, QString const& mode, QString const& message, bool low_confidence, quint8 modifiers);
|
||||
|
||||
// ask the client with identification 'id' to close down gracefully
|
||||
Q_SLOT void close (QString const& id);
|
||||
// ask the client to close down gracefully
|
||||
Q_SLOT void close (ClientKey const&);
|
||||
|
||||
// ask the client with identification 'id' to replay all decodes
|
||||
Q_SLOT void replay (QString const& id);
|
||||
// ask the client to replay all decodes
|
||||
Q_SLOT void replay (ClientKey const&);
|
||||
|
||||
// ask the client with identification 'id' to halt transmitting
|
||||
// auto_only just disables auto Tx, otherwise halt is immediate
|
||||
Q_SLOT void halt_tx (QString const& id, bool auto_only);
|
||||
// ask the client to halt transmitting auto_only just disables auto
|
||||
// Tx, otherwise halt is immediate
|
||||
Q_SLOT void halt_tx (ClientKey const&, bool auto_only);
|
||||
|
||||
// ask the client with identification 'id' to set the free text
|
||||
// message and optionally send it ASAP
|
||||
Q_SLOT void free_text (QString const& id, QString const& text, bool send);
|
||||
// ask the client to set the free text message and optionally send
|
||||
// it ASAP
|
||||
Q_SLOT void free_text (ClientKey const&, QString const& text, bool send);
|
||||
|
||||
// ask the client with identification 'id' to set the location provided
|
||||
Q_SLOT void location (QString const& id, QString const& location);
|
||||
// ask the client to set the location provided
|
||||
Q_SLOT void location (ClientKey const&, QString const& location);
|
||||
|
||||
// ask the client with identification 'id' to highlight the callsign
|
||||
// specified with the given colors
|
||||
Q_SLOT void highlight_callsign (QString const& id, QString const& callsign
|
||||
// ask the client to highlight the callsign specified with the given
|
||||
// colors
|
||||
Q_SLOT void highlight_callsign (ClientKey const&, QString const& callsign
|
||||
, QColor const& bg = QColor {}, QColor const& fg = QColor {}
|
||||
, bool last_only = false);
|
||||
|
||||
// ask the client with identification 'id' to switch to
|
||||
// configuration 'configuration_name'
|
||||
Q_SLOT void switch_configuration (QString const& id, QString const& configuration_name);
|
||||
// ask the client to switch to configuration 'configuration_name'
|
||||
Q_SLOT void switch_configuration (ClientKey const&, QString const& configuration_name);
|
||||
|
||||
// ask the client with identification 'id' to change configuration
|
||||
Q_SLOT void configure (QString const& id, QString const& mode, quint32 frequency_tolerance
|
||||
// ask the client to change configuration
|
||||
Q_SLOT void configure (ClientKey const&, QString const& mode, quint32 frequency_tolerance
|
||||
, QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df
|
||||
, QString const& dx_call, QString const& dx_grid, bool generate_messages);
|
||||
|
||||
// the following signals are emitted when a client broadcasts the
|
||||
// matching message
|
||||
Q_SIGNAL void client_opened (QString const& id, QString const& version, QString const& revision);
|
||||
Q_SIGNAL void status_update (QString const& id, Frequency, QString const& mode, QString const& dx_call
|
||||
Q_SIGNAL void client_opened (ClientKey const&, QString const& version, QString const& revision);
|
||||
Q_SIGNAL void status_update (ClientKey const&, Frequency, QString const& mode, QString const& dx_call
|
||||
, QString const& report, QString const& tx_mode, bool tx_enabled
|
||||
, bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df
|
||||
, QString const& de_call, QString const& de_grid, QString const& dx_grid
|
||||
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode
|
||||
, quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period
|
||||
, QString const& configuration_name);
|
||||
Q_SIGNAL void client_closed (QString const& id);
|
||||
Q_SIGNAL void decode (bool is_new, QString const& id, QTime time, qint32 snr, float delta_time
|
||||
Q_SIGNAL void client_closed (ClientKey const&);
|
||||
Q_SIGNAL void decode (bool is_new, ClientKey const&, QTime time, qint32 snr, float delta_time
|
||||
, quint32 delta_frequency, QString const& mode, QString const& message
|
||||
, bool low_confidence, bool off_air);
|
||||
Q_SIGNAL void WSPR_decode (bool is_new, QString const& id, QTime time, qint32 snr, float delta_time, Frequency
|
||||
Q_SIGNAL void WSPR_decode (bool is_new, ClientKey const&, QTime time, qint32 snr, float delta_time, Frequency
|
||||
, qint32 drift, QString const& callsign, QString const& grid, qint32 power
|
||||
, bool off_air);
|
||||
Q_SIGNAL void qso_logged (QString const& id, QDateTime time_off, QString const& dx_call, QString const& dx_grid
|
||||
Q_SIGNAL void qso_logged (ClientKey const&, QDateTime time_off, QString const& dx_call, QString const& dx_grid
|
||||
, Frequency dial_frequency, QString const& mode, QString const& report_sent
|
||||
, QString const& report_received, QString const& tx_power, QString const& comments
|
||||
, QString const& name, QDateTime time_on, QString const& operator_call
|
||||
, QString const& my_call, QString const& my_grid
|
||||
, QString const& exchange_sent, QString const& exchange_rcvd, QString const& prop_mode);
|
||||
Q_SIGNAL void decodes_cleared (QString const& id);
|
||||
Q_SIGNAL void logged_ADIF (QString const& id, QByteArray const& ADIF);
|
||||
Q_SIGNAL void decodes_cleared (ClientKey const&);
|
||||
Q_SIGNAL void logged_ADIF (ClientKey const&, QByteArray const& ADIF);
|
||||
|
||||
// this signal is emitted when a network error occurs
|
||||
Q_SIGNAL void error (QString const&) const;
|
||||
@ -118,4 +122,6 @@ private:
|
||||
pimpl<impl> m_;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE (MessageServer::ClientKey);
|
||||
|
||||
#endif
|
||||
|
||||
@ -17,9 +17,14 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QCommandLineParser>
|
||||
#include <QCommandLineOption>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QNetworkInterface>
|
||||
#include <QDateTime>
|
||||
#include <QTime>
|
||||
#include <QHash>
|
||||
@ -38,15 +43,17 @@ class Client
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
using ClientKey = MessageServer::ClientKey;
|
||||
|
||||
public:
|
||||
explicit Client (QString const& id, QObject * parent = nullptr)
|
||||
explicit Client (ClientKey const& key, QObject * parent = nullptr)
|
||||
: QObject {parent}
|
||||
, id_ {id}
|
||||
, key_ {key}
|
||||
, dial_frequency_ {0u}
|
||||
{
|
||||
}
|
||||
|
||||
Q_SLOT void update_status (QString const& id, Frequency f, QString const& mode, QString const& /*dx_call*/
|
||||
Q_SLOT void update_status (ClientKey const& key, Frequency f, QString const& mode, QString const& /*dx_call*/
|
||||
, QString const& /*report*/, QString const& /*tx_mode*/, bool /*tx_enabled*/
|
||||
, bool /*transmitting*/, bool /*decoding*/, qint32 /*rx_df*/, qint32 /*tx_df*/
|
||||
, QString const& /*de_call*/, QString const& /*de_grid*/, QString const& /*dx_grid*/
|
||||
@ -54,77 +61,85 @@ public:
|
||||
, quint8 /*special_op_mode*/, quint32 /*frequency_tolerance*/, quint32 /*tr_period*/
|
||||
, QString const& /*configuration_name*/)
|
||||
{
|
||||
if (id == id_)
|
||||
if (key == key_)
|
||||
{
|
||||
if (f != dial_frequency_)
|
||||
{
|
||||
std::cout << tr ("%1: Dial frequency changed to %2").arg (id_).arg (f).toStdString () << std::endl;
|
||||
std::cout << QString {"%1(%2): "}.arg (key_.second).arg (key_.first.toString ()).toStdString ()
|
||||
<< QString {"Dial frequency changed to %1"}.arg (f).toStdString () << std::endl;
|
||||
dial_frequency_ = f;
|
||||
}
|
||||
if (mode + sub_mode != mode_)
|
||||
{
|
||||
std::cout << tr ("%1: Mode changed to %2").arg (id_).arg (mode + sub_mode).toStdString () << std::endl;
|
||||
std::cout << QString {"%1(%2): "}.arg (key_.second).arg (key_.first.toString ()).toStdString ()
|
||||
<< QString {"Mode changed to %1"}.arg (mode + sub_mode).toStdString () << std::endl;
|
||||
mode_ = mode + sub_mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Q_SLOT void decode_added (bool is_new, QString const& client_id, QTime time, qint32 snr
|
||||
Q_SLOT void decode_added (bool is_new, ClientKey const& key, QTime time, qint32 snr
|
||||
, float delta_time, quint32 delta_frequency, QString const& mode
|
||||
, QString const& message, bool low_confidence, bool off_air)
|
||||
{
|
||||
if (client_id == id_)
|
||||
if (key == key_)
|
||||
{
|
||||
qDebug () << "new:" << is_new << "t:" << time << "snr:" << snr
|
||||
<< "Dt:" << delta_time << "Df:" << delta_frequency
|
||||
<< "mode:" << mode << "Confidence:" << (low_confidence ? "low" : "high")
|
||||
<< "On air:" << !off_air;
|
||||
std::cout << tr ("%1: Decoded %2").arg (id_).arg (message).toStdString () << std::endl;
|
||||
std::cout << QString {"%1(%2): "}.arg (key_.second).arg (key_.first.toString ()).toStdString ()
|
||||
<< QString {"Decoded %1"}.arg (message).toStdString () << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Q_SLOT void beacon_spot_added (bool is_new, QString const& client_id, QTime time, qint32 snr
|
||||
Q_SLOT void beacon_spot_added (bool is_new, ClientKey const& key, QTime time, qint32 snr
|
||||
, float delta_time, Frequency delta_frequency, qint32 drift, QString const& callsign
|
||||
, QString const& grid, qint32 power, bool off_air)
|
||||
{
|
||||
if (client_id == id_)
|
||||
if (key == key_)
|
||||
{
|
||||
qDebug () << "new:" << is_new << "t:" << time << "snr:" << snr
|
||||
<< "Dt:" << delta_time << "Df:" << delta_frequency
|
||||
<< "drift:" << drift;
|
||||
std::cout << tr ("%1: WSPR decode %2 grid %3 power: %4").arg (id_).arg (callsign).arg (grid).arg (power).toStdString ()
|
||||
std::cout << QString {"%1(%2): "}.arg (key_.second).arg (key_.first.toString ()).toStdString ()
|
||||
<< QString {"WSPR decode %1 grid %2 power: %3"}
|
||||
.arg (callsign).arg (grid).arg (power).toStdString ()
|
||||
<< "On air:" << !off_air << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Q_SLOT void qso_logged (QString const&client_id, QDateTime time_off, QString const& dx_call, QString const& dx_grid
|
||||
Q_SLOT void qso_logged (ClientKey const& key, QDateTime time_off, QString const& dx_call, QString const& dx_grid
|
||||
, Frequency dial_frequency, QString const& mode, QString const& report_sent
|
||||
, QString const& report_received, QString const& tx_power
|
||||
, QString const& comments, QString const& name, QDateTime time_on
|
||||
, QString const& operator_call, QString const& my_call, QString const& my_grid
|
||||
, QString const& exchange_sent, QString const& exchange_rcvd, QString const& prop_mode)
|
||||
{
|
||||
if (client_id == id_)
|
||||
if (key == key_)
|
||||
{
|
||||
qDebug () << "time_on:" << time_on << "time_off:" << time_off << "dx_call:" << dx_call << "grid:" << dx_grid
|
||||
qDebug () << "time_on:" << time_on << "time_off:" << time_off << "dx_call:"
|
||||
<< dx_call << "grid:" << dx_grid
|
||||
<< "freq:" << dial_frequency << "mode:" << mode << "rpt_sent:" << report_sent
|
||||
<< "rpt_rcvd:" << report_received << "Tx_pwr:" << tx_power << "comments:" << comments
|
||||
<< "name:" << name << "operator_call:" << operator_call << "my_call:" << my_call
|
||||
<< "my_grid:" << my_grid << "exchange_sent:" << exchange_sent
|
||||
<< "exchange_rcvd:" << exchange_rcvd << "prop_mode:" << prop_mode;
|
||||
std::cout << QByteArray {80, '-'}.data () << '\n';
|
||||
std::cout << tr ("%1: Logged %2 grid: %3 power: %4 sent: %5 recd: %6 freq: %7 time_off: %8 op: %9 my_call: %10 my_grid: %11 exchange_sent: %12 exchange_rcvd: %13 comments: %14 prop_mode: %15")
|
||||
.arg (id_).arg (dx_call).arg (dx_grid).arg (tx_power).arg (report_sent).arg (report_received)
|
||||
.arg (dial_frequency).arg (time_off.toString("yyyy-MM-dd hh:mm:ss.z")).arg (operator_call)
|
||||
.arg (my_call).arg (my_grid).arg (exchange_sent).arg (exchange_rcvd)
|
||||
.arg (comments).arg (prop_mode).toStdString ()
|
||||
std::cout << QString {"%1(%2): "}.arg (key_.second).arg (key_.first.toString ()).toStdString ()
|
||||
<< QString {"Logged %1 grid: %2 power: %3 sent: %4 recd: %5 freq: %6 time_off: %7 op: %8 my_call: %9 my_grid: %10 exchange_sent: %11 exchange_rcvd: %12 comments: %13 prop_mode: %14"}
|
||||
.arg (dx_call).arg (dx_grid).arg (tx_power)
|
||||
.arg (report_sent).arg (report_received)
|
||||
.arg (dial_frequency).arg (time_off.toString("yyyy-MM-dd hh:mm:ss.z")).arg (operator_call)
|
||||
.arg (my_call).arg (my_grid).arg (exchange_sent).arg (exchange_rcvd)
|
||||
.arg (comments).arg (prop_mode).toStdString ()
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Q_SLOT void logged_ADIF (QString const&client_id, QByteArray const& ADIF)
|
||||
Q_SLOT void logged_ADIF (ClientKey const& key, QByteArray const& ADIF)
|
||||
{
|
||||
if (client_id == id_)
|
||||
if (key == key_)
|
||||
{
|
||||
qDebug () << "ADIF:" << ADIF;
|
||||
std::cout << QByteArray {80, '-'}.data () << '\n';
|
||||
@ -133,7 +148,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
QString id_;
|
||||
ClientKey key_;
|
||||
Frequency dial_frequency_;
|
||||
QString mode_;
|
||||
};
|
||||
@ -143,8 +158,10 @@ class Server
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
using ClientKey = MessageServer::ClientKey;
|
||||
|
||||
public:
|
||||
Server (port_type port, QHostAddress const& multicast_group)
|
||||
Server (port_type port, QHostAddress const& multicast_group, QStringList const& network_interface_names)
|
||||
: server_ {new MessageServer {this}}
|
||||
{
|
||||
// connect up server
|
||||
@ -154,21 +171,26 @@ public:
|
||||
connect (server_, &MessageServer::client_opened, this, &Server::add_client);
|
||||
connect (server_, &MessageServer::client_closed, this, &Server::remove_client);
|
||||
|
||||
server_->start (port, multicast_group);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK (5, 14, 0)
|
||||
server_->start (port, multicast_group, QSet<QString> {network_interface_names.begin (), network_interface_names.end ()});
|
||||
#else
|
||||
server_->start (port, multicast_group, network_interface_names.toSet ());
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
void add_client (QString const& id, QString const& version, QString const& revision)
|
||||
void add_client (ClientKey const& key, QString const& version, QString const& revision)
|
||||
{
|
||||
auto client = new Client {id};
|
||||
auto client = new Client {key};
|
||||
connect (server_, &MessageServer::status_update, client, &Client::update_status);
|
||||
connect (server_, &MessageServer::decode, client, &Client::decode_added);
|
||||
connect (server_, &MessageServer::WSPR_decode, client, &Client::beacon_spot_added);
|
||||
connect (server_, &MessageServer::qso_logged, client, &Client::qso_logged);
|
||||
connect (server_, &MessageServer::logged_ADIF, client, &Client::logged_ADIF);
|
||||
clients_[id] = client;
|
||||
server_->replay (id);
|
||||
std::cout << "Discovered WSJT-X instance: " << id.toStdString ();
|
||||
clients_[key] = client;
|
||||
server_->replay (key);
|
||||
std::cout << "Discovered WSJT-X instance: " << key.second.toStdString ()
|
||||
<< '(' << key.first.toString ().toStdString () << ')';
|
||||
if (version.size ())
|
||||
{
|
||||
std::cout << " v" << version.toStdString ();
|
||||
@ -180,23 +202,60 @@ private:
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void remove_client (QString const& id)
|
||||
void remove_client (ClientKey const& key)
|
||||
{
|
||||
auto iter = clients_.find (id);
|
||||
auto iter = clients_.find (key);
|
||||
if (iter != std::end (clients_))
|
||||
{
|
||||
clients_.erase (iter);
|
||||
(*iter)->deleteLater ();
|
||||
}
|
||||
std::cout << "Removed WSJT-X instance: " << id.toStdString () << std::endl;
|
||||
std::cout << "Removed WSJT-X instance: " << key.second.toStdString ()
|
||||
<< '(' << key.first.toString ().toStdString () << ')' << std::endl;
|
||||
}
|
||||
|
||||
MessageServer * server_;
|
||||
|
||||
// maps client id to clients
|
||||
QHash<QString, Client *> clients_;
|
||||
// maps client key to clients
|
||||
QHash<ClientKey, Client *> clients_;
|
||||
};
|
||||
|
||||
void list_interfaces ()
|
||||
{
|
||||
for (auto const& net_if : QNetworkInterface::allInterfaces ())
|
||||
{
|
||||
if (net_if.flags () & QNetworkInterface::IsUp)
|
||||
{
|
||||
std::cout << net_if.humanReadableName ().toStdString () << ":\n"
|
||||
" id: " << net_if.name ().toStdString () << " (" << net_if.index () << ")\n"
|
||||
" addr: " << net_if.hardwareAddress ().toStdString () << "\n"
|
||||
" flags: ";
|
||||
if (net_if.flags () & QNetworkInterface::IsRunning)
|
||||
{
|
||||
std::cout << "Running ";
|
||||
}
|
||||
if (net_if.flags () & QNetworkInterface::CanBroadcast)
|
||||
{
|
||||
std::cout << "Broadcast ";
|
||||
}
|
||||
if (net_if.flags () & QNetworkInterface::CanMulticast)
|
||||
{
|
||||
std::cout << "Multicast ";
|
||||
}
|
||||
if (net_if.flags () & QNetworkInterface::IsLoopBack)
|
||||
{
|
||||
std::cout << "Loop-back ";
|
||||
}
|
||||
std::cout << "\n addresses:\n";
|
||||
for (auto const& ae : net_if.addressEntries ())
|
||||
{
|
||||
std::cout << " " << ae.ip ().toString ().toStdString () << '\n';
|
||||
}
|
||||
std::cout << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "UDPDaemon.moc"
|
||||
|
||||
int main (int argc, char * argv[])
|
||||
@ -217,6 +276,11 @@ int main (int argc, char * argv[])
|
||||
auto help_option = parser.addHelpOption ();
|
||||
auto version_option = parser.addVersionOption ();
|
||||
|
||||
QCommandLineOption list_option (QStringList {"l", "list-interfaces"},
|
||||
app.translate ("UDPDaemon",
|
||||
"Print the available network interfaces."));
|
||||
parser.addOption (list_option);
|
||||
|
||||
QCommandLineOption port_option (QStringList {"p", "port"},
|
||||
app.translate ("UDPDaemon",
|
||||
"Where <PORT> is the UDP service port number to listen on.\n"
|
||||
@ -232,9 +296,25 @@ int main (int argc, char * argv[])
|
||||
app.translate ("UDPDaemon", "GROUP"));
|
||||
parser.addOption (multicast_addr_option);
|
||||
|
||||
QCommandLineOption network_interface_option (QStringList {"i", "network-interface"},
|
||||
app.translate ("UDPDaemon",
|
||||
"Where <INTERFACE> is the network interface name to join on.\n"
|
||||
"This option can be passed more than once to specify multiple network interfaces\n"
|
||||
"The default is use just the loop back interface."),
|
||||
app.translate ("UDPDaemon", "INTERFACE"));
|
||||
parser.addOption (network_interface_option);
|
||||
|
||||
parser.process (app);
|
||||
|
||||
Server server {static_cast<port_type> (parser.value (port_option).toUInt ()), QHostAddress {parser.value (multicast_addr_option)}};
|
||||
if (parser.isSet (list_option))
|
||||
{
|
||||
list_interfaces ();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Server server {static_cast<port_type> (parser.value (port_option).toUInt ())
|
||||
, QHostAddress {parser.value (multicast_addr_option).trimmed ()}
|
||||
, parser.values (network_interface_option)};
|
||||
|
||||
return app.exec ();
|
||||
}
|
||||
|
||||
240
WSJTXLogging.cpp
Normal file
240
WSJTXLogging.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
#include "WSJTXLogging.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <sstream>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/log/core.hpp>
|
||||
#include <boost/log/utility/exception_handler.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/sinks/text_file_backend.hpp>
|
||||
#include <boost/log/sinks/async_frontend.hpp>
|
||||
#include <boost/log/expressions.hpp>
|
||||
#include <boost/log/expressions/formatters/date_time.hpp>
|
||||
#include <boost/log/expressions/predicates/channel_severity_filter.hpp>
|
||||
#include <boost/log/support/date_time.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/date_time/gregorian/greg_day.hpp>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QString>
|
||||
#include <QStandardPaths>
|
||||
#include <QRegularExpression>
|
||||
#include <QMessageLogContext>
|
||||
|
||||
#include "Logger.hpp"
|
||||
#include "qt_helpers.hpp"
|
||||
|
||||
namespace logging = boost::log;
|
||||
namespace trivial = logging::trivial;
|
||||
namespace keywords = logging::keywords;
|
||||
namespace expr = logging::expressions;
|
||||
namespace sinks = logging::sinks;
|
||||
namespace posix_time = boost::posix_time;
|
||||
namespace gregorian = boost::gregorian;
|
||||
namespace container = boost::container;
|
||||
|
||||
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", trivial::severity_level)
|
||||
BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", std::string)
|
||||
|
||||
namespace
|
||||
{
|
||||
// Top level exception handler that gets exceptions from filters and
|
||||
// formatters.
|
||||
struct exception_handler
|
||||
{
|
||||
typedef void result;
|
||||
|
||||
void operator () (std::runtime_error const& e) const
|
||||
{
|
||||
std::cout << "std::runtime_error: " << e.what () << std::endl;
|
||||
}
|
||||
void operator () (std::logic_error const& e) const
|
||||
{
|
||||
std::cout << "std::logic_error: " << e.what () << std::endl;
|
||||
//throw;
|
||||
}
|
||||
};
|
||||
|
||||
// Reroute Qt messages to the system logger
|
||||
void qt_log_handler (QtMsgType type, QMessageLogContext const& context, QString const& msg)
|
||||
{
|
||||
// Convert Qt message types to logger severities
|
||||
auto severity = trivial::trace;
|
||||
switch (type)
|
||||
{
|
||||
case QtDebugMsg: severity = trivial::debug; break;
|
||||
case QtInfoMsg: severity = trivial::info; break;
|
||||
case QtWarningMsg: severity = trivial::warning; break;
|
||||
case QtCriticalMsg: severity = trivial::error; break;
|
||||
case QtFatalMsg: severity = trivial::fatal; break;
|
||||
}
|
||||
// Map non-default Qt categories to logger channels, Qt logger
|
||||
// context is mapped to the appropriate logger attributes.
|
||||
auto log = sys::get ();
|
||||
std::string file;
|
||||
std::string function;
|
||||
if (context.file)
|
||||
{
|
||||
file = context.file;
|
||||
}
|
||||
if (context.function)
|
||||
{
|
||||
function = context.function;
|
||||
}
|
||||
if (!context.category || !qstrcmp (context.category, "default"))
|
||||
{
|
||||
BOOST_LOG_SEV (log, severity)
|
||||
<< boost::log::add_value ("Line", context.line)
|
||||
<< boost::log::add_value ("File", file)
|
||||
<< boost::log::add_value ("Function", function)
|
||||
<< msg.toStdWString ();
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_LOG_SEV (log, severity)
|
||||
<< boost::log::add_value ("Line", context.line)
|
||||
<< boost::log::add_value ("File", file)
|
||||
<< boost::log::add_value ("Function", function)
|
||||
<< context.category << ": " << msg.toStdWString ();
|
||||
}
|
||||
if (QtFatalMsg == type)
|
||||
{
|
||||
// bail out
|
||||
throw std::runtime_error {"Fatal Qt Error"};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WSJTXLogging::WSJTXLogging ()
|
||||
{
|
||||
auto core = logging::core::get ();
|
||||
// Catch relevant exceptions from logging.
|
||||
core->set_exception_handler
|
||||
(
|
||||
logging::make_exception_handler<std::runtime_error, std::logic_error> (exception_handler {})
|
||||
);
|
||||
|
||||
// Check for a user-defined logging configuration settings file.
|
||||
QFile log_config {QStandardPaths::locate (QStandardPaths::ConfigLocation, "wsjtx_log_config.ini")};
|
||||
if (log_config.exists () && log_config.open (QFile::ReadOnly) && log_config.isReadable ())
|
||||
{
|
||||
QTextStream ts {&log_config};
|
||||
auto config = ts.readAll ();
|
||||
|
||||
// Substitution variables.
|
||||
container::flat_map<QString, QString> replacements =
|
||||
{
|
||||
{"DesktopLocation", QStandardPaths::writableLocation (QStandardPaths::DesktopLocation)},
|
||||
{"DocumentsLocation", QStandardPaths::writableLocation (QStandardPaths::DocumentsLocation)},
|
||||
{"TempLocation", QStandardPaths::writableLocation (QStandardPaths::TempLocation)},
|
||||
{"HomeLocation", QStandardPaths::writableLocation (QStandardPaths::HomeLocation)},
|
||||
{"CacheLocation", QStandardPaths::writableLocation (QStandardPaths::CacheLocation)},
|
||||
{"GenericCacheLocation", QStandardPaths::writableLocation (QStandardPaths::GenericCacheLocation)},
|
||||
{"GenericDataLocation", QStandardPaths::writableLocation (QStandardPaths::GenericDataLocation)},
|
||||
{"AppDataLocation", QStandardPaths::writableLocation (QStandardPaths::AppDataLocation)},
|
||||
{"AppLocalDataLocation", QStandardPaths::writableLocation (QStandardPaths::AppLocalDataLocation)},
|
||||
};
|
||||
// Parse the configration settings substituting the variable if found.
|
||||
QString new_config;
|
||||
int pos {0};
|
||||
QRegularExpression subst_vars {R"(\${([^}]+)})"};
|
||||
auto iter = subst_vars.globalMatch (config);
|
||||
while (iter.hasNext ())
|
||||
{
|
||||
auto match = iter.next ();
|
||||
auto const& name = match.captured (1);
|
||||
auto repl_iter = replacements.find (name);
|
||||
auto repl = repl_iter != replacements.end () ? repl_iter->second : "${" + name + "}";
|
||||
new_config += config.mid (pos, match.capturedStart (1) - 2 - pos) + repl;
|
||||
pos = match.capturedEnd (0);
|
||||
}
|
||||
new_config += config.mid (pos);
|
||||
std::wstringbuf buffer {new_config.toStdWString (), std::ios_base::in};
|
||||
std::wistream stream {&buffer};
|
||||
Logger::init_from_config (stream);
|
||||
LOG_INFO ("Read logging configuration file: " << log_config.fileName ());
|
||||
}
|
||||
else // Default setup
|
||||
{
|
||||
//
|
||||
// Define sinks, filters, and formatters using expression
|
||||
// templates for efficiency.
|
||||
//
|
||||
|
||||
// Default log file location.
|
||||
QDir app_data {QStandardPaths::writableLocation (QStandardPaths::AppLocalDataLocation)};
|
||||
Logger::init (); // Basic setup of attributes
|
||||
|
||||
//
|
||||
// Sink intended for general use that passes everything above
|
||||
// selected severity levels per channel. Log file is appended
|
||||
// between sessions and rotated to limit storage space usage.
|
||||
//
|
||||
auto sys_sink = boost::make_shared<sinks::asynchronous_sink<sinks::text_file_backend>>
|
||||
(
|
||||
keywords::auto_flush = false
|
||||
#if BOOST_VERSION / 100 >= 1070
|
||||
, keywords::file_name = app_data.absoluteFilePath ("wsjtx_syslog.log").toStdWString ()
|
||||
, keywords::target_file_name =
|
||||
#else
|
||||
, keywords::file_name =
|
||||
#endif
|
||||
app_data.absoluteFilePath ("logs/wsjtx_syslog_%Y-%m.log").toStdString ()
|
||||
, keywords::time_based_rotation = sinks::file::rotation_at_time_point (gregorian::greg_day (1), 0, 0, 0)
|
||||
, keywords::open_mode = std::ios_base::out | std::ios_base::app
|
||||
#if BOOST_VERSION / 100 >= 1063
|
||||
, keywords::enable_final_rotation = false
|
||||
#endif
|
||||
);
|
||||
|
||||
sys_sink->locked_backend ()->set_file_collector
|
||||
(
|
||||
sinks::file::make_collector
|
||||
(
|
||||
keywords::max_size = 40 * 1024 * 1024
|
||||
, keywords::min_free_space = 1024 * 1024 * 1024
|
||||
, keywords::max_files = 12
|
||||
, keywords::target = app_data.absoluteFilePath ("logs").toStdWString ()
|
||||
)
|
||||
);
|
||||
sys_sink->locked_backend ()->scan_for_files ();
|
||||
|
||||
// Per channel severity level filter
|
||||
using min_severity_filter = expr::channel_severity_filter_actor<std::string, trivial::severity_level>;
|
||||
min_severity_filter min_severity = expr::channel_severity_filter (channel, severity);
|
||||
min_severity["SYSLOG"] = trivial::info;
|
||||
min_severity["RIGCTRL"] = trivial::info;
|
||||
min_severity["DATALOG"] = trivial::info;
|
||||
sys_sink->set_filter (min_severity || severity >= trivial::fatal);
|
||||
|
||||
sys_sink->set_formatter
|
||||
(
|
||||
expr::stream
|
||||
<< "[" << channel
|
||||
<< "][" << expr::format_date_time<posix_time::ptime> ("TimeStamp", "%Y-%m-%d %H:%M:%S.%f")
|
||||
<< "][" << expr::format_date_time<posix_time::time_duration> ("Uptime", "%O:%M:%S.%f")
|
||||
<< "][" << trivial::severity
|
||||
<< "] " << expr::message
|
||||
);
|
||||
|
||||
core->add_sink (sys_sink);
|
||||
}
|
||||
|
||||
// Indicate start of logging
|
||||
LOG_INFO ("Log Start");
|
||||
::qInstallMessageHandler (&qt_log_handler);
|
||||
}
|
||||
|
||||
WSJTXLogging::~WSJTXLogging ()
|
||||
{
|
||||
LOG_INFO ("Log Finish");
|
||||
auto core = logging::core::get ();
|
||||
core->flush ();
|
||||
core->remove_all_sinks ();
|
||||
}
|
||||
14
WSJTXLogging.hpp
Normal file
14
WSJTXLogging.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef WSJTX_LOGGING_HPP__
|
||||
#define WSJTX_LOGGING_HPP__
|
||||
|
||||
//
|
||||
// Class WSJTXLogging - wraps application specific logging
|
||||
//
|
||||
class WSJTXLogging final
|
||||
{
|
||||
public:
|
||||
explicit WSJTXLogging ();
|
||||
~WSJTXLogging ();
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,40 +0,0 @@
|
||||
Boost "vendor" repo for K1JT projects
|
||||
=====================================
|
||||
|
||||
This repository contains a subset of the Boost project with libraries
|
||||
needed by K1JT project s such as WSJT-X. It contains two branches,
|
||||
upstream and master. To upgrade the content do the following:
|
||||
|
||||
```bash
|
||||
git checkout upstream
|
||||
mv README.md /tmp
|
||||
rm -r *
|
||||
mv /tmp/README.md .
|
||||
# use the bcp tool to populate with the new Boost libraries from a clean boost install.
|
||||
# Something like:
|
||||
#
|
||||
# bcp --boost=../boost_1_70_0 --unix-lines iterator range math numeric crc circular_buffer multi_index intrusive .
|
||||
#
|
||||
# Clean out any unwanted files and directories (e.g. libs and docs for a header only subset).
|
||||
# Use git add to stage any new files and directories.
|
||||
git commit -a -m "Updated Boost v1.70.0 libraries including ..."
|
||||
git tag boost_1_70_0
|
||||
git push origin
|
||||
git checkout master
|
||||
git merge upstream
|
||||
git push origin
|
||||
```
|
||||
|
||||
The resulting master branch is now ready to be git-subtree merged into
|
||||
any projects that need these libraries.
|
||||
|
||||
This is imported here using git-subtree
|
||||
---------------------------------------
|
||||
|
||||
To update this tree when the upstream Boost libraries are updated use
|
||||
git-subtree-pull to import the changes like this:
|
||||
|
||||
```bash
|
||||
git remote add -f boost git@bitbucket.org:g4wjs/boost.git # for convienence
|
||||
git subtree pull --prefix boost boost master --squash
|
||||
```
|
||||
@ -1,83 +0,0 @@
|
||||
/*
|
||||
Copyright (c) Marshall Clow 2008-2012.
|
||||
|
||||
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)
|
||||
*/
|
||||
|
||||
/// \file all_of.hpp
|
||||
/// \brief Test ranges to see if all elements match a value or predicate.
|
||||
/// \author Marshall Clow
|
||||
|
||||
#ifndef BOOST_ALGORITHM_ALL_OF_HPP
|
||||
#define BOOST_ALGORITHM_ALL_OF_HPP
|
||||
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
|
||||
namespace boost { namespace algorithm {
|
||||
|
||||
/// \fn all_of ( InputIterator first, InputIterator last, Predicate p )
|
||||
/// \return true if all elements in [first, last) satisfy the predicate 'p'
|
||||
/// \note returns true on an empty range
|
||||
///
|
||||
/// \param first The start of the input sequence
|
||||
/// \param last One past the end of the input sequence
|
||||
/// \param p A predicate for testing the elements of the sequence
|
||||
///
|
||||
/// \note This function is part of the C++2011 standard library.
|
||||
template<typename InputIterator, typename Predicate>
|
||||
BOOST_CXX14_CONSTEXPR bool all_of ( InputIterator first, InputIterator last, Predicate p )
|
||||
{
|
||||
for ( ; first != last; ++first )
|
||||
if ( !p(*first))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \fn all_of ( const Range &r, Predicate p )
|
||||
/// \return true if all elements in the range satisfy the predicate 'p'
|
||||
/// \note returns true on an empty range
|
||||
///
|
||||
/// \param r The input range
|
||||
/// \param p A predicate for testing the elements of the range
|
||||
///
|
||||
template<typename Range, typename Predicate>
|
||||
BOOST_CXX14_CONSTEXPR bool all_of ( const Range &r, Predicate p )
|
||||
{
|
||||
return boost::algorithm::all_of ( boost::begin (r), boost::end (r), p );
|
||||
}
|
||||
|
||||
/// \fn all_of_equal ( InputIterator first, InputIterator last, const T &val )
|
||||
/// \return true if all elements in [first, last) are equal to 'val'
|
||||
/// \note returns true on an empty range
|
||||
///
|
||||
/// \param first The start of the input sequence
|
||||
/// \param last One past the end of the input sequence
|
||||
/// \param val A value to compare against
|
||||
///
|
||||
template<typename InputIterator, typename T>
|
||||
BOOST_CXX14_CONSTEXPR bool all_of_equal ( InputIterator first, InputIterator last, const T &val )
|
||||
{
|
||||
for ( ; first != last; ++first )
|
||||
if ( val != *first )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \fn all_of_equal ( const Range &r, const T &val )
|
||||
/// \return true if all elements in the range are equal to 'val'
|
||||
/// \note returns true on an empty range
|
||||
///
|
||||
/// \param r The input range
|
||||
/// \param val A value to compare against
|
||||
///
|
||||
template<typename Range, typename T>
|
||||
BOOST_CXX14_CONSTEXPR bool all_of_equal ( const Range &r, const T &val )
|
||||
{
|
||||
return boost::algorithm::all_of_equal ( boost::begin (r), boost::end (r), val );
|
||||
}
|
||||
|
||||
}} // namespace boost and algorithm
|
||||
|
||||
#endif // BOOST_ALGORITHM_ALL_OF_HPP
|
||||
@ -1,553 +0,0 @@
|
||||
// (C) Copyright Herve Bronnimann 2004.
|
||||
//
|
||||
// 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)
|
||||
|
||||
/*
|
||||
Revision history:
|
||||
1 July 2004
|
||||
Split the code into two headers to lessen dependence on
|
||||
Boost.tuple. (Herve)
|
||||
26 June 2004
|
||||
Added the code for the boost minmax library. (Herve)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ALGORITHM_MINMAX_ELEMENT_HPP
|
||||
#define BOOST_ALGORITHM_MINMAX_ELEMENT_HPP
|
||||
|
||||
/* PROPOSED STANDARD EXTENSIONS:
|
||||
*
|
||||
* minmax_element(first, last)
|
||||
* Effect: std::make_pair( std::min_element(first, last),
|
||||
* std::max_element(first, last) );
|
||||
*
|
||||
* minmax_element(first, last, comp)
|
||||
* Effect: std::make_pair( std::min_element(first, last, comp),
|
||||
* std::max_element(first, last, comp) );
|
||||
*/
|
||||
|
||||
#include <utility> // for std::pair and std::make_pair
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace detail { // for obtaining a uniform version of minmax_element
|
||||
// that compiles with VC++ 6.0 -- avoid the iterator_traits by
|
||||
// having comparison object over iterator, not over dereferenced value
|
||||
|
||||
template <typename Iterator>
|
||||
struct less_over_iter {
|
||||
bool operator()(Iterator const& it1,
|
||||
Iterator const& it2) const { return *it1 < *it2; }
|
||||
};
|
||||
|
||||
template <typename Iterator, class BinaryPredicate>
|
||||
struct binary_pred_over_iter {
|
||||
explicit binary_pred_over_iter(BinaryPredicate const& p ) : m_p( p ) {}
|
||||
bool operator()(Iterator const& it1,
|
||||
Iterator const& it2) const { return m_p(*it1, *it2); }
|
||||
private:
|
||||
BinaryPredicate m_p;
|
||||
};
|
||||
|
||||
// common base for the two minmax_element overloads
|
||||
|
||||
template <typename ForwardIter, class Compare >
|
||||
std::pair<ForwardIter,ForwardIter>
|
||||
basic_minmax_element(ForwardIter first, ForwardIter last, Compare comp)
|
||||
{
|
||||
if (first == last)
|
||||
return std::make_pair(last,last);
|
||||
|
||||
ForwardIter min_result = first;
|
||||
ForwardIter max_result = first;
|
||||
|
||||
// if only one element
|
||||
ForwardIter second = first; ++second;
|
||||
if (second == last)
|
||||
return std::make_pair(min_result, max_result);
|
||||
|
||||
// treat first pair separately (only one comparison for first two elements)
|
||||
ForwardIter potential_min_result = last;
|
||||
if (comp(first, second))
|
||||
max_result = second;
|
||||
else {
|
||||
min_result = second;
|
||||
potential_min_result = first;
|
||||
}
|
||||
|
||||
// then each element by pairs, with at most 3 comparisons per pair
|
||||
first = ++second; if (first != last) ++second;
|
||||
while (second != last) {
|
||||
if (comp(first, second)) {
|
||||
if (comp(first, min_result)) {
|
||||
min_result = first;
|
||||
potential_min_result = last;
|
||||
}
|
||||
if (comp(max_result, second))
|
||||
max_result = second;
|
||||
} else {
|
||||
if (comp(second, min_result)) {
|
||||
min_result = second;
|
||||
potential_min_result = first;
|
||||
}
|
||||
if (comp(max_result, first))
|
||||
max_result = first;
|
||||
}
|
||||
first = ++second;
|
||||
if (first != last) ++second;
|
||||
}
|
||||
|
||||
// if odd number of elements, treat last element
|
||||
if (first != last) { // odd number of elements
|
||||
if (comp(first, min_result)) {
|
||||
min_result = first;
|
||||
potential_min_result = last;
|
||||
}
|
||||
else if (comp(max_result, first))
|
||||
max_result = first;
|
||||
}
|
||||
|
||||
// resolve min_result being incorrect with one extra comparison
|
||||
// (in which case potential_min_result is necessarily the correct result)
|
||||
if (potential_min_result != last
|
||||
&& !comp(min_result, potential_min_result))
|
||||
min_result = potential_min_result;
|
||||
|
||||
return std::make_pair(min_result,max_result);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename ForwardIter>
|
||||
std::pair<ForwardIter,ForwardIter>
|
||||
minmax_element(ForwardIter first, ForwardIter last)
|
||||
{
|
||||
return detail::basic_minmax_element(first, last,
|
||||
detail::less_over_iter<ForwardIter>() );
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
std::pair<ForwardIter,ForwardIter>
|
||||
minmax_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
|
||||
{
|
||||
return detail::basic_minmax_element(first, last,
|
||||
detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* PROPOSED BOOST EXTENSIONS
|
||||
* In the description below, [rfirst,rlast) denotes the reversed range
|
||||
* of [first,last). Even though the iterator type of first and last may
|
||||
* be only a Forward Iterator, it is possible to explain the semantics
|
||||
* by assuming that it is a Bidirectional Iterator. In the sequel,
|
||||
* reverse(ForwardIterator&) returns the reverse_iterator adaptor.
|
||||
* This is not how the functions would be implemented!
|
||||
*
|
||||
* first_min_element(first, last)
|
||||
* Effect: std::min_element(first, last);
|
||||
*
|
||||
* first_min_element(first, last, comp)
|
||||
* Effect: std::min_element(first, last, comp);
|
||||
*
|
||||
* last_min_element(first, last)
|
||||
* Effect: reverse( std::min_element(reverse(last), reverse(first)) );
|
||||
*
|
||||
* last_min_element(first, last, comp)
|
||||
* Effect: reverse( std::min_element(reverse(last), reverse(first), comp) );
|
||||
*
|
||||
* first_max_element(first, last)
|
||||
* Effect: std::max_element(first, last);
|
||||
*
|
||||
* first_max_element(first, last, comp)
|
||||
* Effect: max_element(first, last);
|
||||
*
|
||||
* last_max_element(first, last)
|
||||
* Effect: reverse( std::max_element(reverse(last), reverse(first)) );
|
||||
*
|
||||
* last_max_element(first, last, comp)
|
||||
* Effect: reverse( std::max_element(reverse(last), reverse(first), comp) );
|
||||
*
|
||||
* first_min_first_max_element(first, last)
|
||||
* Effect: std::make_pair( first_min_element(first, last),
|
||||
* first_max_element(first, last) );
|
||||
*
|
||||
* first_min_first_max_element(first, last, comp)
|
||||
* Effect: std::make_pair( first_min_element(first, last, comp),
|
||||
* first_max_element(first, last, comp) );
|
||||
*
|
||||
* first_min_last_max_element(first, last)
|
||||
* Effect: std::make_pair( first_min_element(first, last),
|
||||
* last_max_element(first, last) );
|
||||
*
|
||||
* first_min_last_max_element(first, last, comp)
|
||||
* Effect: std::make_pair( first_min_element(first, last, comp),
|
||||
* last_max_element(first, last, comp) );
|
||||
*
|
||||
* last_min_first_max_element(first, last)
|
||||
* Effect: std::make_pair( last_min_element(first, last),
|
||||
* first_max_element(first, last) );
|
||||
*
|
||||
* last_min_first_max_element(first, last, comp)
|
||||
* Effect: std::make_pair( last_min_element(first, last, comp),
|
||||
* first_max_element(first, last, comp) );
|
||||
*
|
||||
* last_min_last_max_element(first, last)
|
||||
* Effect: std::make_pair( last_min_element(first, last),
|
||||
* last_max_element(first, last) );
|
||||
*
|
||||
* last_min_last_max_element(first, last, comp)
|
||||
* Effect: std::make_pair( last_min_element(first, last, comp),
|
||||
* last_max_element(first, last, comp) );
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
|
||||
// Min_element and max_element variants
|
||||
|
||||
namespace detail { // common base for the overloads
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
ForwardIter
|
||||
basic_first_min_element(ForwardIter first, ForwardIter last,
|
||||
BinaryPredicate comp)
|
||||
{
|
||||
if (first == last) return last;
|
||||
ForwardIter min_result = first;
|
||||
while (++first != last)
|
||||
if (comp(first, min_result))
|
||||
min_result = first;
|
||||
return min_result;
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
ForwardIter
|
||||
basic_last_min_element(ForwardIter first, ForwardIter last,
|
||||
BinaryPredicate comp)
|
||||
{
|
||||
if (first == last) return last;
|
||||
ForwardIter min_result = first;
|
||||
while (++first != last)
|
||||
if (!comp(min_result, first))
|
||||
min_result = first;
|
||||
return min_result;
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
ForwardIter
|
||||
basic_first_max_element(ForwardIter first, ForwardIter last,
|
||||
BinaryPredicate comp)
|
||||
{
|
||||
if (first == last) return last;
|
||||
ForwardIter max_result = first;
|
||||
while (++first != last)
|
||||
if (comp(max_result, first))
|
||||
max_result = first;
|
||||
return max_result;
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
ForwardIter
|
||||
basic_last_max_element(ForwardIter first, ForwardIter last,
|
||||
BinaryPredicate comp)
|
||||
{
|
||||
if (first == last) return last;
|
||||
ForwardIter max_result = first;
|
||||
while (++first != last)
|
||||
if (!comp(first, max_result))
|
||||
max_result = first;
|
||||
return max_result;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename ForwardIter>
|
||||
ForwardIter
|
||||
first_min_element(ForwardIter first, ForwardIter last)
|
||||
{
|
||||
return detail::basic_first_min_element(first, last,
|
||||
detail::less_over_iter<ForwardIter>() );
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
ForwardIter
|
||||
first_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
|
||||
{
|
||||
return detail::basic_first_min_element(first, last,
|
||||
detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
|
||||
}
|
||||
|
||||
template <typename ForwardIter>
|
||||
ForwardIter
|
||||
last_min_element(ForwardIter first, ForwardIter last)
|
||||
{
|
||||
return detail::basic_last_min_element(first, last,
|
||||
detail::less_over_iter<ForwardIter>() );
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
ForwardIter
|
||||
last_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
|
||||
{
|
||||
return detail::basic_last_min_element(first, last,
|
||||
detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
|
||||
}
|
||||
|
||||
template <typename ForwardIter>
|
||||
ForwardIter
|
||||
first_max_element(ForwardIter first, ForwardIter last)
|
||||
{
|
||||
return detail::basic_first_max_element(first, last,
|
||||
detail::less_over_iter<ForwardIter>() );
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
ForwardIter
|
||||
first_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
|
||||
{
|
||||
return detail::basic_first_max_element(first, last,
|
||||
detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
|
||||
}
|
||||
|
||||
template <typename ForwardIter>
|
||||
ForwardIter
|
||||
last_max_element(ForwardIter first, ForwardIter last)
|
||||
{
|
||||
return detail::basic_last_max_element(first, last,
|
||||
detail::less_over_iter<ForwardIter>() );
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
ForwardIter
|
||||
last_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
|
||||
{
|
||||
return detail::basic_last_max_element(first, last,
|
||||
detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
|
||||
}
|
||||
|
||||
|
||||
// Minmax_element variants -- comments removed
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
std::pair<ForwardIter,ForwardIter>
|
||||
basic_first_min_last_max_element(ForwardIter first, ForwardIter last,
|
||||
BinaryPredicate comp)
|
||||
{
|
||||
if (first == last)
|
||||
return std::make_pair(last,last);
|
||||
|
||||
ForwardIter min_result = first;
|
||||
ForwardIter max_result = first;
|
||||
|
||||
ForwardIter second = ++first;
|
||||
if (second == last)
|
||||
return std::make_pair(min_result, max_result);
|
||||
|
||||
if (comp(second, min_result))
|
||||
min_result = second;
|
||||
else
|
||||
max_result = second;
|
||||
|
||||
first = ++second; if (first != last) ++second;
|
||||
while (second != last) {
|
||||
if (!comp(second, first)) {
|
||||
if (comp(first, min_result))
|
||||
min_result = first;
|
||||
if (!comp(second, max_result))
|
||||
max_result = second;
|
||||
} else {
|
||||
if (comp(second, min_result))
|
||||
min_result = second;
|
||||
if (!comp(first, max_result))
|
||||
max_result = first;
|
||||
}
|
||||
first = ++second; if (first != last) ++second;
|
||||
}
|
||||
|
||||
if (first != last) {
|
||||
if (comp(first, min_result))
|
||||
min_result = first;
|
||||
else if (!comp(first, max_result))
|
||||
max_result = first;
|
||||
}
|
||||
|
||||
return std::make_pair(min_result, max_result);
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
std::pair<ForwardIter,ForwardIter>
|
||||
basic_last_min_first_max_element(ForwardIter first, ForwardIter last,
|
||||
BinaryPredicate comp)
|
||||
{
|
||||
if (first == last) return std::make_pair(last,last);
|
||||
|
||||
ForwardIter min_result = first;
|
||||
ForwardIter max_result = first;
|
||||
|
||||
ForwardIter second = ++first;
|
||||
if (second == last)
|
||||
return std::make_pair(min_result, max_result);
|
||||
|
||||
if (comp(max_result, second))
|
||||
max_result = second;
|
||||
else
|
||||
min_result = second;
|
||||
|
||||
first = ++second; if (first != last) ++second;
|
||||
while (second != last) {
|
||||
if (comp(first, second)) {
|
||||
if (!comp(min_result, first))
|
||||
min_result = first;
|
||||
if (comp(max_result, second))
|
||||
max_result = second;
|
||||
} else {
|
||||
if (!comp(min_result, second))
|
||||
min_result = second;
|
||||
if (comp(max_result, first))
|
||||
max_result = first;
|
||||
}
|
||||
first = ++second; if (first != last) ++second;
|
||||
}
|
||||
|
||||
if (first != last) {
|
||||
if (!comp(min_result, first))
|
||||
min_result = first;
|
||||
else if (comp(max_result, first))
|
||||
max_result = first;
|
||||
}
|
||||
|
||||
return std::make_pair(min_result, max_result);
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
std::pair<ForwardIter,ForwardIter>
|
||||
basic_last_min_last_max_element(ForwardIter first, ForwardIter last,
|
||||
BinaryPredicate comp)
|
||||
{
|
||||
if (first == last) return std::make_pair(last,last);
|
||||
|
||||
ForwardIter min_result = first;
|
||||
ForwardIter max_result = first;
|
||||
|
||||
ForwardIter second = first; ++second;
|
||||
if (second == last)
|
||||
return std::make_pair(min_result,max_result);
|
||||
|
||||
ForwardIter potential_max_result = last;
|
||||
if (comp(first, second))
|
||||
max_result = second;
|
||||
else {
|
||||
min_result = second;
|
||||
potential_max_result = second;
|
||||
}
|
||||
|
||||
first = ++second; if (first != last) ++second;
|
||||
while (second != last) {
|
||||
if (comp(first, second)) {
|
||||
if (!comp(min_result, first))
|
||||
min_result = first;
|
||||
if (!comp(second, max_result)) {
|
||||
max_result = second;
|
||||
potential_max_result = last;
|
||||
}
|
||||
} else {
|
||||
if (!comp(min_result, second))
|
||||
min_result = second;
|
||||
if (!comp(first, max_result)) {
|
||||
max_result = first;
|
||||
potential_max_result = second;
|
||||
}
|
||||
}
|
||||
first = ++second;
|
||||
if (first != last) ++second;
|
||||
}
|
||||
|
||||
if (first != last) {
|
||||
if (!comp(min_result, first))
|
||||
min_result = first;
|
||||
if (!comp(first, max_result)) {
|
||||
max_result = first;
|
||||
potential_max_result = last;
|
||||
}
|
||||
}
|
||||
|
||||
if (potential_max_result != last
|
||||
&& !comp(potential_max_result, max_result))
|
||||
max_result = potential_max_result;
|
||||
|
||||
return std::make_pair(min_result,max_result);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename ForwardIter>
|
||||
inline std::pair<ForwardIter,ForwardIter>
|
||||
first_min_first_max_element(ForwardIter first, ForwardIter last)
|
||||
{
|
||||
return minmax_element(first, last);
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
inline std::pair<ForwardIter,ForwardIter>
|
||||
first_min_first_max_element(ForwardIter first, ForwardIter last,
|
||||
BinaryPredicate comp)
|
||||
{
|
||||
return minmax_element(first, last, comp);
|
||||
}
|
||||
|
||||
template <typename ForwardIter>
|
||||
std::pair<ForwardIter,ForwardIter>
|
||||
first_min_last_max_element(ForwardIter first, ForwardIter last)
|
||||
{
|
||||
return detail::basic_first_min_last_max_element(first, last,
|
||||
detail::less_over_iter<ForwardIter>() );
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
inline std::pair<ForwardIter,ForwardIter>
|
||||
first_min_last_max_element(ForwardIter first, ForwardIter last,
|
||||
BinaryPredicate comp)
|
||||
{
|
||||
return detail::basic_first_min_last_max_element(first, last,
|
||||
detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
|
||||
}
|
||||
|
||||
template <typename ForwardIter>
|
||||
std::pair<ForwardIter,ForwardIter>
|
||||
last_min_first_max_element(ForwardIter first, ForwardIter last)
|
||||
{
|
||||
return detail::basic_last_min_first_max_element(first, last,
|
||||
detail::less_over_iter<ForwardIter>() );
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
inline std::pair<ForwardIter,ForwardIter>
|
||||
last_min_first_max_element(ForwardIter first, ForwardIter last,
|
||||
BinaryPredicate comp)
|
||||
{
|
||||
return detail::basic_last_min_first_max_element(first, last,
|
||||
detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
|
||||
}
|
||||
|
||||
template <typename ForwardIter>
|
||||
std::pair<ForwardIter,ForwardIter>
|
||||
last_min_last_max_element(ForwardIter first, ForwardIter last)
|
||||
{
|
||||
return detail::basic_last_min_last_max_element(first, last,
|
||||
detail::less_over_iter<ForwardIter>() );
|
||||
}
|
||||
|
||||
template <typename ForwardIter, class BinaryPredicate>
|
||||
inline std::pair<ForwardIter,ForwardIter>
|
||||
last_min_last_max_element(ForwardIter first, ForwardIter last,
|
||||
BinaryPredicate comp)
|
||||
{
|
||||
return detail::basic_last_min_last_max_element(first, last,
|
||||
detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_ALGORITHM_MINMAX_ELEMENT_HPP
|
||||
@ -1,31 +0,0 @@
|
||||
// Boost string_algo library string_algo.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2004.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_ALGO_HPP
|
||||
#define BOOST_STRING_ALGO_HPP
|
||||
|
||||
/*! \file
|
||||
Cumulative include for string_algo library
|
||||
*/
|
||||
|
||||
#include <boost/algorithm/string/std_containers_traits.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/find.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/algorithm/string/erase.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/find_iterator.hpp>
|
||||
|
||||
|
||||
#endif // BOOST_STRING_ALGO_HPP
|
||||
@ -1,176 +0,0 @@
|
||||
// Boost string_algo library case_conv.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_CASE_CONV_HPP
|
||||
#define BOOST_STRING_CASE_CONV_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <algorithm>
|
||||
#include <locale>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
|
||||
#include <boost/range/as_literal.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/range/value_type.hpp>
|
||||
|
||||
#include <boost/algorithm/string/detail/case_conv.hpp>
|
||||
|
||||
/*! \file
|
||||
Defines sequence case-conversion algorithms.
|
||||
Algorithms convert each element in the input sequence to the
|
||||
desired case using provided locales.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// to_lower -----------------------------------------------//
|
||||
|
||||
//! Convert to lower case
|
||||
/*!
|
||||
Each element of the input sequence is converted to lower
|
||||
case. The result is a copy of the input converted to lower case.
|
||||
It is returned as a sequence or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input range
|
||||
\param Loc A locale used for conversion
|
||||
\return
|
||||
An output iterator pointing just after the last inserted character or
|
||||
a copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
|
||||
*/
|
||||
template<typename OutputIteratorT, typename RangeT>
|
||||
inline OutputIteratorT
|
||||
to_lower_copy(
|
||||
OutputIteratorT Output,
|
||||
const RangeT& Input,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
return ::boost::algorithm::detail::transform_range_copy(
|
||||
Output,
|
||||
::boost::as_literal(Input),
|
||||
::boost::algorithm::detail::to_lowerF<
|
||||
typename range_value<RangeT>::type >(Loc));
|
||||
}
|
||||
|
||||
//! Convert to lower case
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT>
|
||||
inline SequenceT to_lower_copy(
|
||||
const SequenceT& Input,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
return ::boost::algorithm::detail::transform_range_copy<SequenceT>(
|
||||
Input,
|
||||
::boost::algorithm::detail::to_lowerF<
|
||||
typename range_value<SequenceT>::type >(Loc));
|
||||
}
|
||||
|
||||
//! Convert to lower case
|
||||
/*!
|
||||
Each element of the input sequence is converted to lower
|
||||
case. The input sequence is modified in-place.
|
||||
|
||||
\param Input A range
|
||||
\param Loc a locale used for conversion
|
||||
*/
|
||||
template<typename WritableRangeT>
|
||||
inline void to_lower(
|
||||
WritableRangeT& Input,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
::boost::algorithm::detail::transform_range(
|
||||
::boost::as_literal(Input),
|
||||
::boost::algorithm::detail::to_lowerF<
|
||||
typename range_value<WritableRangeT>::type >(Loc));
|
||||
}
|
||||
|
||||
// to_upper -----------------------------------------------//
|
||||
|
||||
//! Convert to upper case
|
||||
/*!
|
||||
Each element of the input sequence is converted to upper
|
||||
case. The result is a copy of the input converted to upper case.
|
||||
It is returned as a sequence or copied to the output iterator
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input range
|
||||
\param Loc A locale used for conversion
|
||||
\return
|
||||
An output iterator pointing just after the last inserted character or
|
||||
a copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename OutputIteratorT, typename RangeT>
|
||||
inline OutputIteratorT
|
||||
to_upper_copy(
|
||||
OutputIteratorT Output,
|
||||
const RangeT& Input,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
return ::boost::algorithm::detail::transform_range_copy(
|
||||
Output,
|
||||
::boost::as_literal(Input),
|
||||
::boost::algorithm::detail::to_upperF<
|
||||
typename range_value<RangeT>::type >(Loc));
|
||||
}
|
||||
|
||||
//! Convert to upper case
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT>
|
||||
inline SequenceT to_upper_copy(
|
||||
const SequenceT& Input,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
return ::boost::algorithm::detail::transform_range_copy<SequenceT>(
|
||||
Input,
|
||||
::boost::algorithm::detail::to_upperF<
|
||||
typename range_value<SequenceT>::type >(Loc));
|
||||
}
|
||||
|
||||
//! Convert to upper case
|
||||
/*!
|
||||
Each element of the input sequence is converted to upper
|
||||
case. The input sequence is modified in-place.
|
||||
|
||||
\param Input An input range
|
||||
\param Loc a locale used for conversion
|
||||
*/
|
||||
template<typename WritableRangeT>
|
||||
inline void to_upper(
|
||||
WritableRangeT& Input,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
::boost::algorithm::detail::transform_range(
|
||||
::boost::as_literal(Input),
|
||||
::boost::algorithm::detail::to_upperF<
|
||||
typename range_value<WritableRangeT>::type >(Loc));
|
||||
}
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull names to the boost namespace
|
||||
using algorithm::to_lower;
|
||||
using algorithm::to_lower_copy;
|
||||
using algorithm::to_upper;
|
||||
using algorithm::to_upper_copy;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_STRING_CASE_CONV_HPP
|
||||
@ -1,312 +0,0 @@
|
||||
// Boost string_algo library classification.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_CLASSIFICATION_HPP
|
||||
#define BOOST_STRING_CLASSIFICATION_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <locale>
|
||||
#include <boost/range/value_type.hpp>
|
||||
#include <boost/range/as_literal.hpp>
|
||||
#include <boost/algorithm/string/detail/classification.hpp>
|
||||
#include <boost/algorithm/string/predicate_facade.hpp>
|
||||
|
||||
|
||||
/*! \file
|
||||
Classification predicates are included in the library to give
|
||||
some more convenience when using algorithms like \c trim() and \c all().
|
||||
They wrap functionality of STL classification functions ( e.g. \c std::isspace() )
|
||||
into generic functors.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// classification functor generator -------------------------------------//
|
||||
|
||||
//! is_classified predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate. This predicate holds if the input is
|
||||
of specified \c std::ctype category.
|
||||
|
||||
\param Type A \c std::ctype category
|
||||
\param Loc A locale used for classification
|
||||
\return An instance of the \c is_classified predicate
|
||||
*/
|
||||
inline detail::is_classifiedF
|
||||
is_classified(std::ctype_base::mask Type, const std::locale& Loc=std::locale())
|
||||
{
|
||||
return detail::is_classifiedF(Type, Loc);
|
||||
}
|
||||
|
||||
//! is_space predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate for the \c ctype_base::space category.
|
||||
|
||||
\param Loc A locale used for classification
|
||||
\return An instance of the \c is_classified predicate
|
||||
*/
|
||||
inline detail::is_classifiedF
|
||||
is_space(const std::locale& Loc=std::locale())
|
||||
{
|
||||
return detail::is_classifiedF(std::ctype_base::space, Loc);
|
||||
}
|
||||
|
||||
//! is_alnum predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate for the \c ctype_base::alnum category.
|
||||
|
||||
\param Loc A locale used for classification
|
||||
\return An instance of the \c is_classified predicate
|
||||
*/
|
||||
inline detail::is_classifiedF
|
||||
is_alnum(const std::locale& Loc=std::locale())
|
||||
{
|
||||
return detail::is_classifiedF(std::ctype_base::alnum, Loc);
|
||||
}
|
||||
|
||||
//! is_alpha predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate for the \c ctype_base::alpha category.
|
||||
|
||||
\param Loc A locale used for classification
|
||||
\return An instance of the \c is_classified predicate
|
||||
*/
|
||||
inline detail::is_classifiedF
|
||||
is_alpha(const std::locale& Loc=std::locale())
|
||||
{
|
||||
return detail::is_classifiedF(std::ctype_base::alpha, Loc);
|
||||
}
|
||||
|
||||
//! is_cntrl predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate for the \c ctype_base::cntrl category.
|
||||
|
||||
\param Loc A locale used for classification
|
||||
\return An instance of the \c is_classified predicate
|
||||
*/
|
||||
inline detail::is_classifiedF
|
||||
is_cntrl(const std::locale& Loc=std::locale())
|
||||
{
|
||||
return detail::is_classifiedF(std::ctype_base::cntrl, Loc);
|
||||
}
|
||||
|
||||
//! is_digit predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate for the \c ctype_base::digit category.
|
||||
|
||||
\param Loc A locale used for classification
|
||||
\return An instance of the \c is_classified predicate
|
||||
*/
|
||||
inline detail::is_classifiedF
|
||||
is_digit(const std::locale& Loc=std::locale())
|
||||
{
|
||||
return detail::is_classifiedF(std::ctype_base::digit, Loc);
|
||||
}
|
||||
|
||||
//! is_graph predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate for the \c ctype_base::graph category.
|
||||
|
||||
\param Loc A locale used for classification
|
||||
\return An instance of the \c is_classified predicate
|
||||
*/
|
||||
inline detail::is_classifiedF
|
||||
is_graph(const std::locale& Loc=std::locale())
|
||||
{
|
||||
return detail::is_classifiedF(std::ctype_base::graph, Loc);
|
||||
}
|
||||
|
||||
//! is_lower predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate for the \c ctype_base::lower category.
|
||||
|
||||
\param Loc A locale used for classification
|
||||
\return An instance of \c is_classified predicate
|
||||
*/
|
||||
inline detail::is_classifiedF
|
||||
is_lower(const std::locale& Loc=std::locale())
|
||||
{
|
||||
return detail::is_classifiedF(std::ctype_base::lower, Loc);
|
||||
}
|
||||
|
||||
//! is_print predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate for the \c ctype_base::print category.
|
||||
|
||||
\param Loc A locale used for classification
|
||||
\return An instance of the \c is_classified predicate
|
||||
*/
|
||||
inline detail::is_classifiedF
|
||||
is_print(const std::locale& Loc=std::locale())
|
||||
{
|
||||
return detail::is_classifiedF(std::ctype_base::print, Loc);
|
||||
}
|
||||
|
||||
//! is_punct predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate for the \c ctype_base::punct category.
|
||||
|
||||
\param Loc A locale used for classification
|
||||
\return An instance of the \c is_classified predicate
|
||||
*/
|
||||
inline detail::is_classifiedF
|
||||
is_punct(const std::locale& Loc=std::locale())
|
||||
{
|
||||
return detail::is_classifiedF(std::ctype_base::punct, Loc);
|
||||
}
|
||||
|
||||
//! is_upper predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate for the \c ctype_base::upper category.
|
||||
|
||||
\param Loc A locale used for classification
|
||||
\return An instance of the \c is_classified predicate
|
||||
*/
|
||||
inline detail::is_classifiedF
|
||||
is_upper(const std::locale& Loc=std::locale())
|
||||
{
|
||||
return detail::is_classifiedF(std::ctype_base::upper, Loc);
|
||||
}
|
||||
|
||||
//! is_xdigit predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate for the \c ctype_base::xdigit category.
|
||||
|
||||
\param Loc A locale used for classification
|
||||
\return An instance of the \c is_classified predicate
|
||||
*/
|
||||
inline detail::is_classifiedF
|
||||
is_xdigit(const std::locale& Loc=std::locale())
|
||||
{
|
||||
return detail::is_classifiedF(std::ctype_base::xdigit, Loc);
|
||||
}
|
||||
|
||||
//! is_any_of predicate
|
||||
/*!
|
||||
Construct the \c is_any_of predicate. The predicate holds if the input
|
||||
is included in the specified set of characters.
|
||||
|
||||
\param Set A set of characters to be recognized
|
||||
\return An instance of the \c is_any_of predicate
|
||||
*/
|
||||
template<typename RangeT>
|
||||
inline detail::is_any_ofF<
|
||||
BOOST_STRING_TYPENAME range_value<RangeT>::type>
|
||||
is_any_of( const RangeT& Set )
|
||||
{
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> lit_set(boost::as_literal(Set));
|
||||
return detail::is_any_ofF<BOOST_STRING_TYPENAME range_value<RangeT>::type>(lit_set);
|
||||
}
|
||||
|
||||
//! is_from_range predicate
|
||||
/*!
|
||||
Construct the \c is_from_range predicate. The predicate holds if the input
|
||||
is included in the specified range. (i.e. From <= Ch <= To )
|
||||
|
||||
\param From The start of the range
|
||||
\param To The end of the range
|
||||
\return An instance of the \c is_from_range predicate
|
||||
*/
|
||||
template<typename CharT>
|
||||
inline detail::is_from_rangeF<CharT> is_from_range(CharT From, CharT To)
|
||||
{
|
||||
return detail::is_from_rangeF<CharT>(From,To);
|
||||
}
|
||||
|
||||
// predicate combinators ---------------------------------------------------//
|
||||
|
||||
//! predicate 'and' composition predicate
|
||||
/*!
|
||||
Construct the \c class_and predicate. This predicate can be used
|
||||
to logically combine two classification predicates. \c class_and holds,
|
||||
if both predicates return true.
|
||||
|
||||
\param Pred1 The first predicate
|
||||
\param Pred2 The second predicate
|
||||
\return An instance of the \c class_and predicate
|
||||
*/
|
||||
template<typename Pred1T, typename Pred2T>
|
||||
inline detail::pred_andF<Pred1T, Pred2T>
|
||||
operator&&(
|
||||
const predicate_facade<Pred1T>& Pred1,
|
||||
const predicate_facade<Pred2T>& Pred2 )
|
||||
{
|
||||
// Doing the static_cast with the pointer instead of the reference
|
||||
// is a workaround for some compilers which have problems with
|
||||
// static_cast's of template references, i.e. CW8. /grafik/
|
||||
return detail::pred_andF<Pred1T,Pred2T>(
|
||||
*static_cast<const Pred1T*>(&Pred1),
|
||||
*static_cast<const Pred2T*>(&Pred2) );
|
||||
}
|
||||
|
||||
//! predicate 'or' composition predicate
|
||||
/*!
|
||||
Construct the \c class_or predicate. This predicate can be used
|
||||
to logically combine two classification predicates. \c class_or holds,
|
||||
if one of the predicates return true.
|
||||
|
||||
\param Pred1 The first predicate
|
||||
\param Pred2 The second predicate
|
||||
\return An instance of the \c class_or predicate
|
||||
*/
|
||||
template<typename Pred1T, typename Pred2T>
|
||||
inline detail::pred_orF<Pred1T, Pred2T>
|
||||
operator||(
|
||||
const predicate_facade<Pred1T>& Pred1,
|
||||
const predicate_facade<Pred2T>& Pred2 )
|
||||
{
|
||||
// Doing the static_cast with the pointer instead of the reference
|
||||
// is a workaround for some compilers which have problems with
|
||||
// static_cast's of template references, i.e. CW8. /grafik/
|
||||
return detail::pred_orF<Pred1T,Pred2T>(
|
||||
*static_cast<const Pred1T*>(&Pred1),
|
||||
*static_cast<const Pred2T*>(&Pred2));
|
||||
}
|
||||
|
||||
//! predicate negation operator
|
||||
/*!
|
||||
Construct the \c class_not predicate. This predicate represents a negation.
|
||||
\c class_or holds if of the predicates return false.
|
||||
|
||||
\param Pred The predicate to be negated
|
||||
\return An instance of the \c class_not predicate
|
||||
*/
|
||||
template<typename PredT>
|
||||
inline detail::pred_notF<PredT>
|
||||
operator!( const predicate_facade<PredT>& Pred )
|
||||
{
|
||||
// Doing the static_cast with the pointer instead of the reference
|
||||
// is a workaround for some compilers which have problems with
|
||||
// static_cast's of template references, i.e. CW8. /grafik/
|
||||
return detail::pred_notF<PredT>(*static_cast<const PredT*>(&Pred));
|
||||
}
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull names to the boost namespace
|
||||
using algorithm::is_classified;
|
||||
using algorithm::is_space;
|
||||
using algorithm::is_alnum;
|
||||
using algorithm::is_alpha;
|
||||
using algorithm::is_cntrl;
|
||||
using algorithm::is_digit;
|
||||
using algorithm::is_graph;
|
||||
using algorithm::is_lower;
|
||||
using algorithm::is_upper;
|
||||
using algorithm::is_print;
|
||||
using algorithm::is_punct;
|
||||
using algorithm::is_xdigit;
|
||||
using algorithm::is_any_of;
|
||||
using algorithm::is_from_range;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_STRING_PREDICATE_HPP
|
||||
@ -1,199 +0,0 @@
|
||||
// Boost string_algo library compare.hpp header file -------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2006.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_COMPARE_HPP
|
||||
#define BOOST_STRING_COMPARE_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <locale>
|
||||
|
||||
/*! \file
|
||||
Defines element comparison predicates. Many algorithms in this library can
|
||||
take an additional argument with a predicate used to compare elements.
|
||||
This makes it possible, for instance, to have case insensitive versions
|
||||
of the algorithms.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// is_equal functor -----------------------------------------------//
|
||||
|
||||
//! is_equal functor
|
||||
/*!
|
||||
Standard STL equal_to only handle comparison between arguments
|
||||
of the same type. This is a less restrictive version which wraps operator ==.
|
||||
*/
|
||||
struct is_equal
|
||||
{
|
||||
//! Function operator
|
||||
/*!
|
||||
Compare two operands for equality
|
||||
*/
|
||||
template< typename T1, typename T2 >
|
||||
bool operator()( const T1& Arg1, const T2& Arg2 ) const
|
||||
{
|
||||
return Arg1==Arg2;
|
||||
}
|
||||
};
|
||||
|
||||
//! case insensitive version of is_equal
|
||||
/*!
|
||||
Case insensitive comparison predicate. Comparison is done using
|
||||
specified locales.
|
||||
*/
|
||||
struct is_iequal
|
||||
{
|
||||
//! Constructor
|
||||
/*!
|
||||
\param Loc locales used for comparison
|
||||
*/
|
||||
is_iequal( const std::locale& Loc=std::locale() ) :
|
||||
m_Loc( Loc ) {}
|
||||
|
||||
//! Function operator
|
||||
/*!
|
||||
Compare two operands. Case is ignored.
|
||||
*/
|
||||
template< typename T1, typename T2 >
|
||||
bool operator()( const T1& Arg1, const T2& Arg2 ) const
|
||||
{
|
||||
#if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL)
|
||||
return std::toupper(Arg1)==std::toupper(Arg2);
|
||||
#else
|
||||
return std::toupper<T1>(Arg1,m_Loc)==std::toupper<T2>(Arg2,m_Loc);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
std::locale m_Loc;
|
||||
};
|
||||
|
||||
// is_less functor -----------------------------------------------//
|
||||
|
||||
//! is_less functor
|
||||
/*!
|
||||
Convenient version of standard std::less. Operation is templated, therefore it is
|
||||
not required to specify the exact types upon the construction
|
||||
*/
|
||||
struct is_less
|
||||
{
|
||||
//! Functor operation
|
||||
/*!
|
||||
Compare two operands using > operator
|
||||
*/
|
||||
template< typename T1, typename T2 >
|
||||
bool operator()( const T1& Arg1, const T2& Arg2 ) const
|
||||
{
|
||||
return Arg1<Arg2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//! case insensitive version of is_less
|
||||
/*!
|
||||
Case insensitive comparison predicate. Comparison is done using
|
||||
specified locales.
|
||||
*/
|
||||
struct is_iless
|
||||
{
|
||||
//! Constructor
|
||||
/*!
|
||||
\param Loc locales used for comparison
|
||||
*/
|
||||
is_iless( const std::locale& Loc=std::locale() ) :
|
||||
m_Loc( Loc ) {}
|
||||
|
||||
//! Function operator
|
||||
/*!
|
||||
Compare two operands. Case is ignored.
|
||||
*/
|
||||
template< typename T1, typename T2 >
|
||||
bool operator()( const T1& Arg1, const T2& Arg2 ) const
|
||||
{
|
||||
#if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL)
|
||||
return std::toupper(Arg1)<std::toupper(Arg2);
|
||||
#else
|
||||
return std::toupper<T1>(Arg1,m_Loc)<std::toupper<T2>(Arg2,m_Loc);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
std::locale m_Loc;
|
||||
};
|
||||
|
||||
// is_not_greater functor -----------------------------------------------//
|
||||
|
||||
//! is_not_greater functor
|
||||
/*!
|
||||
Convenient version of standard std::not_greater_to. Operation is templated, therefore it is
|
||||
not required to specify the exact types upon the construction
|
||||
*/
|
||||
struct is_not_greater
|
||||
{
|
||||
//! Functor operation
|
||||
/*!
|
||||
Compare two operands using > operator
|
||||
*/
|
||||
template< typename T1, typename T2 >
|
||||
bool operator()( const T1& Arg1, const T2& Arg2 ) const
|
||||
{
|
||||
return Arg1<=Arg2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//! case insensitive version of is_not_greater
|
||||
/*!
|
||||
Case insensitive comparison predicate. Comparison is done using
|
||||
specified locales.
|
||||
*/
|
||||
struct is_not_igreater
|
||||
{
|
||||
//! Constructor
|
||||
/*!
|
||||
\param Loc locales used for comparison
|
||||
*/
|
||||
is_not_igreater( const std::locale& Loc=std::locale() ) :
|
||||
m_Loc( Loc ) {}
|
||||
|
||||
//! Function operator
|
||||
/*!
|
||||
Compare two operands. Case is ignored.
|
||||
*/
|
||||
template< typename T1, typename T2 >
|
||||
bool operator()( const T1& Arg1, const T2& Arg2 ) const
|
||||
{
|
||||
#if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL)
|
||||
return std::toupper(Arg1)<=std::toupper(Arg2);
|
||||
#else
|
||||
return std::toupper<T1>(Arg1,m_Loc)<=std::toupper<T2>(Arg2,m_Loc);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
std::locale m_Loc;
|
||||
};
|
||||
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull names to the boost namespace
|
||||
using algorithm::is_equal;
|
||||
using algorithm::is_iequal;
|
||||
using algorithm::is_less;
|
||||
using algorithm::is_iless;
|
||||
using algorithm::is_not_greater;
|
||||
using algorithm::is_not_igreater;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_COMPARE_HPP
|
||||
@ -1,83 +0,0 @@
|
||||
// Boost string_algo library concept.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_CONCEPT_HPP
|
||||
#define BOOST_STRING_CONCEPT_HPP
|
||||
|
||||
#include <boost/concept_check.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
|
||||
/*! \file
|
||||
Defines concepts used in string_algo library
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
//! Finder concept
|
||||
/*!
|
||||
Defines the Finder concept. Finder is a functor which selects
|
||||
an arbitrary part of a string. Search is performed on
|
||||
the range specified by starting and ending iterators.
|
||||
|
||||
Result of the find operation must be convertible to iterator_range.
|
||||
*/
|
||||
template<typename FinderT, typename IteratorT>
|
||||
struct FinderConcept
|
||||
{
|
||||
private:
|
||||
typedef iterator_range<IteratorT> range;
|
||||
public:
|
||||
void constraints()
|
||||
{
|
||||
// Operation
|
||||
r=(*pF)(i,i);
|
||||
}
|
||||
private:
|
||||
range r;
|
||||
IteratorT i;
|
||||
FinderT* pF;
|
||||
}; // Finder_concept
|
||||
|
||||
|
||||
//! Formatter concept
|
||||
/*!
|
||||
Defines the Formatter concept. Formatter is a functor, which
|
||||
takes a result from a finder operation and transforms it
|
||||
in a specific way.
|
||||
|
||||
Result must be a container supported by container_traits,
|
||||
or a reference to it.
|
||||
*/
|
||||
template<typename FormatterT, typename FinderT, typename IteratorT>
|
||||
struct FormatterConcept
|
||||
{
|
||||
public:
|
||||
void constraints()
|
||||
{
|
||||
// Operation
|
||||
::boost::begin((*pFo)( (*pF)(i,i) ));
|
||||
::boost::end((*pFo)( (*pF)(i,i) ));
|
||||
}
|
||||
private:
|
||||
IteratorT i;
|
||||
FinderT* pF;
|
||||
FormatterT *pFo;
|
||||
}; // FormatterConcept;
|
||||
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // BOOST_STRING_CONCEPT_HPP
|
||||
@ -1,28 +0,0 @@
|
||||
// Boost string_algo library config.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_CONFIG_HPP
|
||||
#define BOOST_STRING_CONFIG_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#ifdef BOOST_STRING_DEDUCED_TYPENAME
|
||||
# error "macro already defined!"
|
||||
#endif
|
||||
|
||||
#define BOOST_STRING_TYPENAME BOOST_DEDUCED_TYPENAME
|
||||
|
||||
// Metrowerks workaround
|
||||
#if BOOST_WORKAROUND(__MWERKS__, <= 0x3003) // 8.x
|
||||
#pragma parse_func_templ off
|
||||
#endif
|
||||
|
||||
#endif // BOOST_STRING_CONFIG_HPP
|
||||
@ -1,36 +0,0 @@
|
||||
// Boost string_algo library constants.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_CONSTANTS_HPP
|
||||
#define BOOST_STRING_CONSTANTS_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
//! Token compression mode
|
||||
/*!
|
||||
Specifies token compression mode for the token_finder.
|
||||
*/
|
||||
enum token_compress_mode_type
|
||||
{
|
||||
token_compress_on, //!< Compress adjacent tokens
|
||||
token_compress_off //!< Do not compress adjacent tokens
|
||||
};
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull the names to the boost namespace
|
||||
using algorithm::token_compress_on;
|
||||
using algorithm::token_compress_off;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_STRING_CONSTANTS_HPP
|
||||
|
||||
@ -1,127 +0,0 @@
|
||||
// Boost string_algo library string_funct.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_CASE_CONV_DETAIL_HPP
|
||||
#define BOOST_STRING_CASE_CONV_DETAIL_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <locale>
|
||||
#include <functional>
|
||||
|
||||
#include <boost/type_traits/make_unsigned.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
namespace detail {
|
||||
|
||||
// case conversion functors -----------------------------------------------//
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4512) //assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
// a tolower functor
|
||||
template<typename CharT>
|
||||
struct to_lowerF
|
||||
{
|
||||
typedef CharT argument_type;
|
||||
typedef CharT result_type;
|
||||
// Constructor
|
||||
to_lowerF( const std::locale& Loc ) : m_Loc( &Loc ) {}
|
||||
|
||||
// Operation
|
||||
CharT operator ()( CharT Ch ) const
|
||||
{
|
||||
#if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL)
|
||||
return std::tolower( static_cast<typename boost::make_unsigned <CharT>::type> ( Ch ));
|
||||
#else
|
||||
return std::tolower<CharT>( Ch, *m_Loc );
|
||||
#endif
|
||||
}
|
||||
private:
|
||||
const std::locale* m_Loc;
|
||||
};
|
||||
|
||||
// a toupper functor
|
||||
template<typename CharT>
|
||||
struct to_upperF
|
||||
{
|
||||
typedef CharT argument_type;
|
||||
typedef CharT result_type;
|
||||
// Constructor
|
||||
to_upperF( const std::locale& Loc ) : m_Loc( &Loc ) {}
|
||||
|
||||
// Operation
|
||||
CharT operator ()( CharT Ch ) const
|
||||
{
|
||||
#if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL)
|
||||
return std::toupper( static_cast<typename boost::make_unsigned <CharT>::type> ( Ch ));
|
||||
#else
|
||||
return std::toupper<CharT>( Ch, *m_Loc );
|
||||
#endif
|
||||
}
|
||||
private:
|
||||
const std::locale* m_Loc;
|
||||
};
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// algorithm implementation -------------------------------------------------------------------------
|
||||
|
||||
// Transform a range
|
||||
template<typename OutputIteratorT, typename RangeT, typename FunctorT>
|
||||
OutputIteratorT transform_range_copy(
|
||||
OutputIteratorT Output,
|
||||
const RangeT& Input,
|
||||
FunctorT Functor)
|
||||
{
|
||||
return std::transform(
|
||||
::boost::begin(Input),
|
||||
::boost::end(Input),
|
||||
Output,
|
||||
Functor);
|
||||
}
|
||||
|
||||
// Transform a range (in-place)
|
||||
template<typename RangeT, typename FunctorT>
|
||||
void transform_range(
|
||||
const RangeT& Input,
|
||||
FunctorT Functor)
|
||||
{
|
||||
std::transform(
|
||||
::boost::begin(Input),
|
||||
::boost::end(Input),
|
||||
::boost::begin(Input),
|
||||
Functor);
|
||||
}
|
||||
|
||||
template<typename SequenceT, typename RangeT, typename FunctorT>
|
||||
inline SequenceT transform_range_copy(
|
||||
const RangeT& Input,
|
||||
FunctorT Functor)
|
||||
{
|
||||
return SequenceT(
|
||||
::boost::make_transform_iterator(
|
||||
::boost::begin(Input),
|
||||
Functor),
|
||||
::boost::make_transform_iterator(
|
||||
::boost::end(Input),
|
||||
Functor));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_CASE_CONV_DETAIL_HPP
|
||||
@ -1,353 +0,0 @@
|
||||
// Boost string_algo library classification.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_CLASSIFICATION_DETAIL_HPP
|
||||
#define BOOST_STRING_CLASSIFICATION_DETAIL_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <locale>
|
||||
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
|
||||
#include <boost/algorithm/string/predicate_facade.hpp>
|
||||
#include <boost/type_traits/remove_const.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
namespace detail {
|
||||
|
||||
// classification functors -----------------------------------------------//
|
||||
|
||||
// is_classified functor
|
||||
struct is_classifiedF :
|
||||
public predicate_facade<is_classifiedF>
|
||||
{
|
||||
// Boost.ResultOf support
|
||||
typedef bool result_type;
|
||||
|
||||
// Constructor from a locale
|
||||
is_classifiedF(std::ctype_base::mask Type, std::locale const & Loc = std::locale()) :
|
||||
m_Type(Type), m_Locale(Loc) {}
|
||||
// Operation
|
||||
template<typename CharT>
|
||||
bool operator()( CharT Ch ) const
|
||||
{
|
||||
return std::use_facet< std::ctype<CharT> >(m_Locale).is( m_Type, Ch );
|
||||
}
|
||||
|
||||
#if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x582) && !defined(_USE_OLD_RW_STL)
|
||||
template<>
|
||||
bool operator()( char const Ch ) const
|
||||
{
|
||||
return std::use_facet< std::ctype<char> >(m_Locale).is( m_Type, Ch );
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
std::ctype_base::mask m_Type;
|
||||
std::locale m_Locale;
|
||||
};
|
||||
|
||||
|
||||
// is_any_of functor
|
||||
/*
|
||||
returns true if the value is from the specified set
|
||||
*/
|
||||
template<typename CharT>
|
||||
struct is_any_ofF :
|
||||
public predicate_facade<is_any_ofF<CharT> >
|
||||
{
|
||||
private:
|
||||
// set cannot operate on const value-type
|
||||
typedef typename ::boost::remove_const<CharT>::type set_value_type;
|
||||
|
||||
public:
|
||||
// Boost.ResultOf support
|
||||
typedef bool result_type;
|
||||
|
||||
// Constructor
|
||||
template<typename RangeT>
|
||||
is_any_ofF( const RangeT& Range ) : m_Size(0)
|
||||
{
|
||||
// Prepare storage
|
||||
m_Storage.m_dynSet=0;
|
||||
|
||||
std::size_t Size=::boost::distance(Range);
|
||||
m_Size=Size;
|
||||
set_value_type* Storage=0;
|
||||
|
||||
if(use_fixed_storage(m_Size))
|
||||
{
|
||||
// Use fixed storage
|
||||
Storage=&m_Storage.m_fixSet[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use dynamic storage
|
||||
m_Storage.m_dynSet=new set_value_type[m_Size];
|
||||
Storage=m_Storage.m_dynSet;
|
||||
}
|
||||
|
||||
// Use fixed storage
|
||||
::std::copy(::boost::begin(Range), ::boost::end(Range), Storage);
|
||||
::std::sort(Storage, Storage+m_Size);
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
is_any_ofF(const is_any_ofF& Other) : m_Size(Other.m_Size)
|
||||
{
|
||||
// Prepare storage
|
||||
m_Storage.m_dynSet=0;
|
||||
const set_value_type* SrcStorage=0;
|
||||
set_value_type* DestStorage=0;
|
||||
|
||||
if(use_fixed_storage(m_Size))
|
||||
{
|
||||
// Use fixed storage
|
||||
DestStorage=&m_Storage.m_fixSet[0];
|
||||
SrcStorage=&Other.m_Storage.m_fixSet[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use dynamic storage
|
||||
m_Storage.m_dynSet=new set_value_type[m_Size];
|
||||
DestStorage=m_Storage.m_dynSet;
|
||||
SrcStorage=Other.m_Storage.m_dynSet;
|
||||
}
|
||||
|
||||
// Use fixed storage
|
||||
::std::memcpy(DestStorage, SrcStorage, sizeof(set_value_type)*m_Size);
|
||||
}
|
||||
|
||||
// Destructor
|
||||
~is_any_ofF()
|
||||
{
|
||||
if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0)
|
||||
{
|
||||
delete [] m_Storage.m_dynSet;
|
||||
}
|
||||
}
|
||||
|
||||
// Assignment
|
||||
is_any_ofF& operator=(const is_any_ofF& Other)
|
||||
{
|
||||
// Handle self assignment
|
||||
if(this==&Other) return *this;
|
||||
|
||||
// Prepare storage
|
||||
const set_value_type* SrcStorage;
|
||||
set_value_type* DestStorage;
|
||||
|
||||
if(use_fixed_storage(Other.m_Size))
|
||||
{
|
||||
// Use fixed storage
|
||||
DestStorage=&m_Storage.m_fixSet[0];
|
||||
SrcStorage=&Other.m_Storage.m_fixSet[0];
|
||||
|
||||
// Delete old storage if was present
|
||||
if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0)
|
||||
{
|
||||
delete [] m_Storage.m_dynSet;
|
||||
}
|
||||
|
||||
// Set new size
|
||||
m_Size=Other.m_Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Other uses dynamic storage
|
||||
SrcStorage=Other.m_Storage.m_dynSet;
|
||||
|
||||
// Check what kind of storage are we using right now
|
||||
if(use_fixed_storage(m_Size))
|
||||
{
|
||||
// Using fixed storage, allocate new
|
||||
set_value_type* pTemp=new set_value_type[Other.m_Size];
|
||||
DestStorage=pTemp;
|
||||
m_Storage.m_dynSet=pTemp;
|
||||
m_Size=Other.m_Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Using dynamic storage, check if can reuse
|
||||
if(m_Storage.m_dynSet!=0 && m_Size>=Other.m_Size && m_Size<Other.m_Size*2)
|
||||
{
|
||||
// Reuse the current storage
|
||||
DestStorage=m_Storage.m_dynSet;
|
||||
m_Size=Other.m_Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Allocate the new one
|
||||
set_value_type* pTemp=new set_value_type[Other.m_Size];
|
||||
DestStorage=pTemp;
|
||||
|
||||
// Delete old storage if necessary
|
||||
if(m_Storage.m_dynSet!=0)
|
||||
{
|
||||
delete [] m_Storage.m_dynSet;
|
||||
}
|
||||
// Store the new storage
|
||||
m_Storage.m_dynSet=pTemp;
|
||||
// Set new size
|
||||
m_Size=Other.m_Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the data
|
||||
::std::memcpy(DestStorage, SrcStorage, sizeof(set_value_type)*m_Size);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Operation
|
||||
template<typename Char2T>
|
||||
bool operator()( Char2T Ch ) const
|
||||
{
|
||||
const set_value_type* Storage=
|
||||
(use_fixed_storage(m_Size))
|
||||
? &m_Storage.m_fixSet[0]
|
||||
: m_Storage.m_dynSet;
|
||||
|
||||
return ::std::binary_search(Storage, Storage+m_Size, Ch);
|
||||
}
|
||||
private:
|
||||
// check if the size is eligible for fixed storage
|
||||
static bool use_fixed_storage(std::size_t size)
|
||||
{
|
||||
return size<=sizeof(set_value_type*)*2;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// storage
|
||||
// The actual used storage is selected on the type
|
||||
union
|
||||
{
|
||||
set_value_type* m_dynSet;
|
||||
set_value_type m_fixSet[sizeof(set_value_type*)*2];
|
||||
}
|
||||
m_Storage;
|
||||
|
||||
// storage size
|
||||
::std::size_t m_Size;
|
||||
};
|
||||
|
||||
// is_from_range functor
|
||||
/*
|
||||
returns true if the value is from the specified range.
|
||||
(i.e. x>=From && x>=To)
|
||||
*/
|
||||
template<typename CharT>
|
||||
struct is_from_rangeF :
|
||||
public predicate_facade< is_from_rangeF<CharT> >
|
||||
{
|
||||
// Boost.ResultOf support
|
||||
typedef bool result_type;
|
||||
|
||||
// Constructor
|
||||
is_from_rangeF( CharT From, CharT To ) : m_From(From), m_To(To) {}
|
||||
|
||||
// Operation
|
||||
template<typename Char2T>
|
||||
bool operator()( Char2T Ch ) const
|
||||
{
|
||||
return ( m_From <= Ch ) && ( Ch <= m_To );
|
||||
}
|
||||
|
||||
private:
|
||||
CharT m_From;
|
||||
CharT m_To;
|
||||
};
|
||||
|
||||
// class_and composition predicate
|
||||
template<typename Pred1T, typename Pred2T>
|
||||
struct pred_andF :
|
||||
public predicate_facade< pred_andF<Pred1T,Pred2T> >
|
||||
{
|
||||
public:
|
||||
|
||||
// Boost.ResultOf support
|
||||
typedef bool result_type;
|
||||
|
||||
// Constructor
|
||||
pred_andF( Pred1T Pred1, Pred2T Pred2 ) :
|
||||
m_Pred1(Pred1), m_Pred2(Pred2) {}
|
||||
|
||||
// Operation
|
||||
template<typename CharT>
|
||||
bool operator()( CharT Ch ) const
|
||||
{
|
||||
return m_Pred1(Ch) && m_Pred2(Ch);
|
||||
}
|
||||
|
||||
private:
|
||||
Pred1T m_Pred1;
|
||||
Pred2T m_Pred2;
|
||||
};
|
||||
|
||||
// class_or composition predicate
|
||||
template<typename Pred1T, typename Pred2T>
|
||||
struct pred_orF :
|
||||
public predicate_facade< pred_orF<Pred1T,Pred2T> >
|
||||
{
|
||||
public:
|
||||
// Boost.ResultOf support
|
||||
typedef bool result_type;
|
||||
|
||||
// Constructor
|
||||
pred_orF( Pred1T Pred1, Pred2T Pred2 ) :
|
||||
m_Pred1(Pred1), m_Pred2(Pred2) {}
|
||||
|
||||
// Operation
|
||||
template<typename CharT>
|
||||
bool operator()( CharT Ch ) const
|
||||
{
|
||||
return m_Pred1(Ch) || m_Pred2(Ch);
|
||||
}
|
||||
|
||||
private:
|
||||
Pred1T m_Pred1;
|
||||
Pred2T m_Pred2;
|
||||
};
|
||||
|
||||
// class_not composition predicate
|
||||
template< typename PredT >
|
||||
struct pred_notF :
|
||||
public predicate_facade< pred_notF<PredT> >
|
||||
{
|
||||
public:
|
||||
// Boost.ResultOf support
|
||||
typedef bool result_type;
|
||||
|
||||
// Constructor
|
||||
pred_notF( PredT Pred ) : m_Pred(Pred) {}
|
||||
|
||||
// Operation
|
||||
template<typename CharT>
|
||||
bool operator()( CharT Ch ) const
|
||||
{
|
||||
return !m_Pred(Ch);
|
||||
}
|
||||
|
||||
private:
|
||||
PredT m_Pred;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_CLASSIFICATION_DETAIL_HPP
|
||||
@ -1,204 +0,0 @@
|
||||
// Boost string_algo library find_format.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_FIND_FORMAT_DETAIL_HPP
|
||||
#define BOOST_STRING_FIND_FORMAT_DETAIL_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/const_iterator.hpp>
|
||||
#include <boost/range/iterator.hpp>
|
||||
#include <boost/algorithm/string/detail/find_format_store.hpp>
|
||||
#include <boost/algorithm/string/detail/replace_storage.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
namespace detail {
|
||||
|
||||
// find_format_copy (iterator variant) implementation -------------------------------//
|
||||
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename InputT,
|
||||
typename FormatterT,
|
||||
typename FindResultT,
|
||||
typename FormatResultT >
|
||||
inline OutputIteratorT find_format_copy_impl2(
|
||||
OutputIteratorT Output,
|
||||
const InputT& Input,
|
||||
FormatterT Formatter,
|
||||
const FindResultT& FindResult,
|
||||
const FormatResultT& FormatResult )
|
||||
{
|
||||
typedef find_format_store<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_const_iterator<InputT>::type,
|
||||
FormatterT,
|
||||
FormatResultT > store_type;
|
||||
|
||||
// Create store for the find result
|
||||
store_type M( FindResult, FormatResult, Formatter );
|
||||
|
||||
if ( !M )
|
||||
{
|
||||
// Match not found - return original sequence
|
||||
Output = std::copy( ::boost::begin(Input), ::boost::end(Input), Output );
|
||||
return Output;
|
||||
}
|
||||
|
||||
// Copy the beginning of the sequence
|
||||
Output = std::copy( ::boost::begin(Input), ::boost::begin(M), Output );
|
||||
// Format find result
|
||||
// Copy formatted result
|
||||
Output = std::copy( ::boost::begin(M.format_result()), ::boost::end(M.format_result()), Output );
|
||||
// Copy the rest of the sequence
|
||||
Output = std::copy( M.end(), ::boost::end(Input), Output );
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename InputT,
|
||||
typename FormatterT,
|
||||
typename FindResultT >
|
||||
inline OutputIteratorT find_format_copy_impl(
|
||||
OutputIteratorT Output,
|
||||
const InputT& Input,
|
||||
FormatterT Formatter,
|
||||
const FindResultT& FindResult )
|
||||
{
|
||||
if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) {
|
||||
return ::boost::algorithm::detail::find_format_copy_impl2(
|
||||
Output,
|
||||
Input,
|
||||
Formatter,
|
||||
FindResult,
|
||||
Formatter(FindResult) );
|
||||
} else {
|
||||
return std::copy( ::boost::begin(Input), ::boost::end(Input), Output );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// find_format_copy implementation --------------------------------------------------//
|
||||
|
||||
template<
|
||||
typename InputT,
|
||||
typename FormatterT,
|
||||
typename FindResultT,
|
||||
typename FormatResultT >
|
||||
inline InputT find_format_copy_impl2(
|
||||
const InputT& Input,
|
||||
FormatterT Formatter,
|
||||
const FindResultT& FindResult,
|
||||
const FormatResultT& FormatResult)
|
||||
{
|
||||
typedef find_format_store<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_const_iterator<InputT>::type,
|
||||
FormatterT,
|
||||
FormatResultT > store_type;
|
||||
|
||||
// Create store for the find result
|
||||
store_type M( FindResult, FormatResult, Formatter );
|
||||
|
||||
if ( !M )
|
||||
{
|
||||
// Match not found - return original sequence
|
||||
return InputT( Input );
|
||||
}
|
||||
|
||||
InputT Output;
|
||||
// Copy the beginning of the sequence
|
||||
boost::algorithm::detail::insert( Output, ::boost::end(Output), ::boost::begin(Input), M.begin() );
|
||||
// Copy formatted result
|
||||
boost::algorithm::detail::insert( Output, ::boost::end(Output), M.format_result() );
|
||||
// Copy the rest of the sequence
|
||||
boost::algorithm::detail::insert( Output, ::boost::end(Output), M.end(), ::boost::end(Input) );
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
template<
|
||||
typename InputT,
|
||||
typename FormatterT,
|
||||
typename FindResultT >
|
||||
inline InputT find_format_copy_impl(
|
||||
const InputT& Input,
|
||||
FormatterT Formatter,
|
||||
const FindResultT& FindResult)
|
||||
{
|
||||
if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) {
|
||||
return ::boost::algorithm::detail::find_format_copy_impl2(
|
||||
Input,
|
||||
Formatter,
|
||||
FindResult,
|
||||
Formatter(FindResult) );
|
||||
} else {
|
||||
return Input;
|
||||
}
|
||||
}
|
||||
|
||||
// replace implementation ----------------------------------------------------//
|
||||
|
||||
template<
|
||||
typename InputT,
|
||||
typename FormatterT,
|
||||
typename FindResultT,
|
||||
typename FormatResultT >
|
||||
inline void find_format_impl2(
|
||||
InputT& Input,
|
||||
FormatterT Formatter,
|
||||
const FindResultT& FindResult,
|
||||
const FormatResultT& FormatResult)
|
||||
{
|
||||
typedef find_format_store<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_iterator<InputT>::type,
|
||||
FormatterT,
|
||||
FormatResultT > store_type;
|
||||
|
||||
// Create store for the find result
|
||||
store_type M( FindResult, FormatResult, Formatter );
|
||||
|
||||
if ( !M )
|
||||
{
|
||||
// Search not found - return original sequence
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace match
|
||||
::boost::algorithm::detail::replace( Input, M.begin(), M.end(), M.format_result() );
|
||||
}
|
||||
|
||||
template<
|
||||
typename InputT,
|
||||
typename FormatterT,
|
||||
typename FindResultT >
|
||||
inline void find_format_impl(
|
||||
InputT& Input,
|
||||
FormatterT Formatter,
|
||||
const FindResultT& FindResult)
|
||||
{
|
||||
if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) {
|
||||
::boost::algorithm::detail::find_format_impl2(
|
||||
Input,
|
||||
Formatter,
|
||||
FindResult,
|
||||
Formatter(FindResult) );
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_STRING_FIND_FORMAT_DETAIL_HPP
|
||||
@ -1,273 +0,0 @@
|
||||
// Boost string_algo library find_format_all.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_FIND_FORMAT_ALL_DETAIL_HPP
|
||||
#define BOOST_STRING_FIND_FORMAT_ALL_DETAIL_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/const_iterator.hpp>
|
||||
#include <boost/range/value_type.hpp>
|
||||
#include <boost/algorithm/string/detail/find_format_store.hpp>
|
||||
#include <boost/algorithm/string/detail/replace_storage.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
namespace detail {
|
||||
|
||||
// find_format_all_copy (iterator variant) implementation ---------------------------//
|
||||
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename InputT,
|
||||
typename FinderT,
|
||||
typename FormatterT,
|
||||
typename FindResultT,
|
||||
typename FormatResultT >
|
||||
inline OutputIteratorT find_format_all_copy_impl2(
|
||||
OutputIteratorT Output,
|
||||
const InputT& Input,
|
||||
FinderT Finder,
|
||||
FormatterT Formatter,
|
||||
const FindResultT& FindResult,
|
||||
const FormatResultT& FormatResult )
|
||||
{
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
range_const_iterator<InputT>::type input_iterator_type;
|
||||
|
||||
typedef find_format_store<
|
||||
input_iterator_type,
|
||||
FormatterT,
|
||||
FormatResultT > store_type;
|
||||
|
||||
// Create store for the find result
|
||||
store_type M( FindResult, FormatResult, Formatter );
|
||||
|
||||
// Initialize last match
|
||||
input_iterator_type LastMatch=::boost::begin(Input);
|
||||
|
||||
// Iterate through all matches
|
||||
while( M )
|
||||
{
|
||||
// Copy the beginning of the sequence
|
||||
Output = std::copy( LastMatch, M.begin(), Output );
|
||||
// Copy formatted result
|
||||
Output = std::copy( ::boost::begin(M.format_result()), ::boost::end(M.format_result()), Output );
|
||||
|
||||
// Proceed to the next match
|
||||
LastMatch=M.end();
|
||||
M=Finder( LastMatch, ::boost::end(Input) );
|
||||
}
|
||||
|
||||
// Copy the rest of the sequence
|
||||
Output = std::copy( LastMatch, ::boost::end(Input), Output );
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename InputT,
|
||||
typename FinderT,
|
||||
typename FormatterT,
|
||||
typename FindResultT >
|
||||
inline OutputIteratorT find_format_all_copy_impl(
|
||||
OutputIteratorT Output,
|
||||
const InputT& Input,
|
||||
FinderT Finder,
|
||||
FormatterT Formatter,
|
||||
const FindResultT& FindResult )
|
||||
{
|
||||
if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) {
|
||||
return ::boost::algorithm::detail::find_format_all_copy_impl2(
|
||||
Output,
|
||||
Input,
|
||||
Finder,
|
||||
Formatter,
|
||||
FindResult,
|
||||
Formatter(FindResult) );
|
||||
} else {
|
||||
return std::copy( ::boost::begin(Input), ::boost::end(Input), Output );
|
||||
}
|
||||
}
|
||||
|
||||
// find_format_all_copy implementation ----------------------------------------------//
|
||||
|
||||
template<
|
||||
typename InputT,
|
||||
typename FinderT,
|
||||
typename FormatterT,
|
||||
typename FindResultT,
|
||||
typename FormatResultT >
|
||||
inline InputT find_format_all_copy_impl2(
|
||||
const InputT& Input,
|
||||
FinderT Finder,
|
||||
FormatterT Formatter,
|
||||
const FindResultT& FindResult,
|
||||
const FormatResultT& FormatResult)
|
||||
{
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
range_const_iterator<InputT>::type input_iterator_type;
|
||||
|
||||
typedef find_format_store<
|
||||
input_iterator_type,
|
||||
FormatterT,
|
||||
FormatResultT > store_type;
|
||||
|
||||
// Create store for the find result
|
||||
store_type M( FindResult, FormatResult, Formatter );
|
||||
|
||||
// Initialize last match
|
||||
input_iterator_type LastMatch=::boost::begin(Input);
|
||||
|
||||
// Output temporary
|
||||
InputT Output;
|
||||
|
||||
// Iterate through all matches
|
||||
while( M )
|
||||
{
|
||||
// Copy the beginning of the sequence
|
||||
boost::algorithm::detail::insert( Output, ::boost::end(Output), LastMatch, M.begin() );
|
||||
// Copy formatted result
|
||||
boost::algorithm::detail::insert( Output, ::boost::end(Output), M.format_result() );
|
||||
|
||||
// Proceed to the next match
|
||||
LastMatch=M.end();
|
||||
M=Finder( LastMatch, ::boost::end(Input) );
|
||||
}
|
||||
|
||||
// Copy the rest of the sequence
|
||||
::boost::algorithm::detail::insert( Output, ::boost::end(Output), LastMatch, ::boost::end(Input) );
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
template<
|
||||
typename InputT,
|
||||
typename FinderT,
|
||||
typename FormatterT,
|
||||
typename FindResultT >
|
||||
inline InputT find_format_all_copy_impl(
|
||||
const InputT& Input,
|
||||
FinderT Finder,
|
||||
FormatterT Formatter,
|
||||
const FindResultT& FindResult)
|
||||
{
|
||||
if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) {
|
||||
return ::boost::algorithm::detail::find_format_all_copy_impl2(
|
||||
Input,
|
||||
Finder,
|
||||
Formatter,
|
||||
FindResult,
|
||||
Formatter(FindResult) );
|
||||
} else {
|
||||
return Input;
|
||||
}
|
||||
}
|
||||
|
||||
// find_format_all implementation ------------------------------------------------//
|
||||
|
||||
template<
|
||||
typename InputT,
|
||||
typename FinderT,
|
||||
typename FormatterT,
|
||||
typename FindResultT,
|
||||
typename FormatResultT >
|
||||
inline void find_format_all_impl2(
|
||||
InputT& Input,
|
||||
FinderT Finder,
|
||||
FormatterT Formatter,
|
||||
FindResultT FindResult,
|
||||
FormatResultT FormatResult)
|
||||
{
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
range_iterator<InputT>::type input_iterator_type;
|
||||
typedef find_format_store<
|
||||
input_iterator_type,
|
||||
FormatterT,
|
||||
FormatResultT > store_type;
|
||||
|
||||
// Create store for the find result
|
||||
store_type M( FindResult, FormatResult, Formatter );
|
||||
|
||||
// Instantiate replacement storage
|
||||
std::deque<
|
||||
BOOST_STRING_TYPENAME range_value<InputT>::type> Storage;
|
||||
|
||||
// Initialize replacement iterators
|
||||
input_iterator_type InsertIt=::boost::begin(Input);
|
||||
input_iterator_type SearchIt=::boost::begin(Input);
|
||||
|
||||
while( M )
|
||||
{
|
||||
// process the segment
|
||||
InsertIt=process_segment(
|
||||
Storage,
|
||||
Input,
|
||||
InsertIt,
|
||||
SearchIt,
|
||||
M.begin() );
|
||||
|
||||
// Adjust search iterator
|
||||
SearchIt=M.end();
|
||||
|
||||
// Copy formatted replace to the storage
|
||||
::boost::algorithm::detail::copy_to_storage( Storage, M.format_result() );
|
||||
|
||||
// Find range for a next match
|
||||
M=Finder( SearchIt, ::boost::end(Input) );
|
||||
}
|
||||
|
||||
// process the last segment
|
||||
InsertIt=::boost::algorithm::detail::process_segment(
|
||||
Storage,
|
||||
Input,
|
||||
InsertIt,
|
||||
SearchIt,
|
||||
::boost::end(Input) );
|
||||
|
||||
if ( Storage.empty() )
|
||||
{
|
||||
// Truncate input
|
||||
::boost::algorithm::detail::erase( Input, InsertIt, ::boost::end(Input) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy remaining data to the end of input
|
||||
::boost::algorithm::detail::insert( Input, ::boost::end(Input), Storage.begin(), Storage.end() );
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename InputT,
|
||||
typename FinderT,
|
||||
typename FormatterT,
|
||||
typename FindResultT >
|
||||
inline void find_format_all_impl(
|
||||
InputT& Input,
|
||||
FinderT Finder,
|
||||
FormatterT Formatter,
|
||||
FindResultT FindResult)
|
||||
{
|
||||
if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) {
|
||||
::boost::algorithm::detail::find_format_all_impl2(
|
||||
Input,
|
||||
Finder,
|
||||
Formatter,
|
||||
FindResult,
|
||||
Formatter(FindResult) );
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_STRING_FIND_FORMAT_ALL_DETAIL_HPP
|
||||
@ -1,89 +0,0 @@
|
||||
// Boost string_algo library find_format_store.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_FIND_FORMAT_STORE_DETAIL_HPP
|
||||
#define BOOST_STRING_FIND_FORMAT_STORE_DETAIL_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
namespace detail {
|
||||
|
||||
// temporary format and find result storage --------------------------------//
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4512) //assignment operator could not be generated
|
||||
#endif
|
||||
template<
|
||||
typename ForwardIteratorT,
|
||||
typename FormatterT,
|
||||
typename FormatResultT >
|
||||
class find_format_store :
|
||||
public iterator_range<ForwardIteratorT>
|
||||
{
|
||||
public:
|
||||
// typedefs
|
||||
typedef iterator_range<ForwardIteratorT> base_type;
|
||||
typedef FormatterT formatter_type;
|
||||
typedef FormatResultT format_result_type;
|
||||
|
||||
public:
|
||||
// Construction
|
||||
find_format_store(
|
||||
const base_type& FindResult,
|
||||
const format_result_type& FormatResult,
|
||||
const formatter_type& Formatter ) :
|
||||
base_type(FindResult),
|
||||
m_FormatResult(FormatResult),
|
||||
m_Formatter(Formatter) {}
|
||||
|
||||
// Assignment
|
||||
template< typename FindResultT >
|
||||
find_format_store& operator=( FindResultT FindResult )
|
||||
{
|
||||
iterator_range<ForwardIteratorT>::operator=(FindResult);
|
||||
if( !this->empty() ) {
|
||||
m_FormatResult=m_Formatter(FindResult);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Retrieve format result
|
||||
const format_result_type& format_result()
|
||||
{
|
||||
return m_FormatResult;
|
||||
}
|
||||
|
||||
private:
|
||||
format_result_type m_FormatResult;
|
||||
const formatter_type& m_Formatter;
|
||||
};
|
||||
|
||||
template<typename InputT, typename FindResultT>
|
||||
bool check_find_result(InputT&, FindResultT& FindResult)
|
||||
{
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
range_const_iterator<InputT>::type input_iterator_type;
|
||||
iterator_range<input_iterator_type> ResultRange(FindResult);
|
||||
return !ResultRange.empty();
|
||||
}
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
} // namespace detail
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_STRING_FIND_FORMAT_STORE_DETAIL_HPP
|
||||
@ -1,87 +0,0 @@
|
||||
// Boost string_algo library find_iterator.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_FIND_ITERATOR_DETAIL_HPP
|
||||
#define BOOST_STRING_FIND_ITERATOR_DETAIL_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/iterator/iterator_categories.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
namespace detail {
|
||||
|
||||
// find_iterator base -----------------------------------------------//
|
||||
|
||||
// Find iterator base
|
||||
template<typename IteratorT>
|
||||
class find_iterator_base
|
||||
{
|
||||
protected:
|
||||
// typedefs
|
||||
typedef IteratorT input_iterator_type;
|
||||
typedef iterator_range<IteratorT> match_type;
|
||||
typedef function2<
|
||||
match_type,
|
||||
input_iterator_type,
|
||||
input_iterator_type> finder_type;
|
||||
|
||||
protected:
|
||||
// Protected construction/destruction
|
||||
|
||||
// Default constructor
|
||||
find_iterator_base() {}
|
||||
// Copy construction
|
||||
find_iterator_base( const find_iterator_base& Other ) :
|
||||
m_Finder(Other.m_Finder) {}
|
||||
|
||||
// Constructor
|
||||
template<typename FinderT>
|
||||
find_iterator_base( FinderT Finder, int ) :
|
||||
m_Finder(Finder) {}
|
||||
|
||||
// Destructor
|
||||
~find_iterator_base() {}
|
||||
|
||||
// Find operation
|
||||
match_type do_find(
|
||||
input_iterator_type Begin,
|
||||
input_iterator_type End ) const
|
||||
{
|
||||
if (!m_Finder.empty())
|
||||
{
|
||||
return m_Finder(Begin,End);
|
||||
}
|
||||
else
|
||||
{
|
||||
return match_type(End,End);
|
||||
}
|
||||
}
|
||||
|
||||
// Check
|
||||
bool is_null() const
|
||||
{
|
||||
return m_Finder.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
// Finder
|
||||
finder_type m_Finder;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_FIND_ITERATOR_DETAIL_HPP
|
||||
@ -1,639 +0,0 @@
|
||||
// Boost string_algo library finder.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2006.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_FINDER_DETAIL_HPP
|
||||
#define BOOST_STRING_FINDER_DETAIL_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <boost/algorithm/string/constants.hpp>
|
||||
#include <boost/detail/iterator.hpp>
|
||||
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/range/empty.hpp>
|
||||
#include <boost/range/as_literal.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
namespace detail {
|
||||
|
||||
|
||||
// find first functor -----------------------------------------------//
|
||||
|
||||
// find a subsequence in the sequence ( functor )
|
||||
/*
|
||||
Returns a pair <begin,end> marking the subsequence in the sequence.
|
||||
If the find fails, functor returns <End,End>
|
||||
*/
|
||||
template<typename SearchIteratorT,typename PredicateT>
|
||||
struct first_finderF
|
||||
{
|
||||
typedef SearchIteratorT search_iterator_type;
|
||||
|
||||
// Construction
|
||||
template< typename SearchT >
|
||||
first_finderF( const SearchT& Search, PredicateT Comp ) :
|
||||
m_Search(::boost::begin(Search), ::boost::end(Search)), m_Comp(Comp) {}
|
||||
first_finderF(
|
||||
search_iterator_type SearchBegin,
|
||||
search_iterator_type SearchEnd,
|
||||
PredicateT Comp ) :
|
||||
m_Search(SearchBegin, SearchEnd), m_Comp(Comp) {}
|
||||
|
||||
// Operation
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
operator()(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End ) const
|
||||
{
|
||||
typedef iterator_range<ForwardIteratorT> result_type;
|
||||
typedef ForwardIteratorT input_iterator_type;
|
||||
|
||||
// Outer loop
|
||||
for(input_iterator_type OuterIt=Begin;
|
||||
OuterIt!=End;
|
||||
++OuterIt)
|
||||
{
|
||||
// Sanity check
|
||||
if( boost::empty(m_Search) )
|
||||
return result_type( End, End );
|
||||
|
||||
input_iterator_type InnerIt=OuterIt;
|
||||
search_iterator_type SubstrIt=m_Search.begin();
|
||||
for(;
|
||||
InnerIt!=End && SubstrIt!=m_Search.end();
|
||||
++InnerIt,++SubstrIt)
|
||||
{
|
||||
if( !( m_Comp(*InnerIt,*SubstrIt) ) )
|
||||
break;
|
||||
}
|
||||
|
||||
// Substring matching succeeded
|
||||
if ( SubstrIt==m_Search.end() )
|
||||
return result_type( OuterIt, InnerIt );
|
||||
}
|
||||
|
||||
return result_type( End, End );
|
||||
}
|
||||
|
||||
private:
|
||||
iterator_range<search_iterator_type> m_Search;
|
||||
PredicateT m_Comp;
|
||||
};
|
||||
|
||||
// find last functor -----------------------------------------------//
|
||||
|
||||
// find the last match a subsequence in the sequence ( functor )
|
||||
/*
|
||||
Returns a pair <begin,end> marking the subsequence in the sequence.
|
||||
If the find fails, returns <End,End>
|
||||
*/
|
||||
template<typename SearchIteratorT, typename PredicateT>
|
||||
struct last_finderF
|
||||
{
|
||||
typedef SearchIteratorT search_iterator_type;
|
||||
typedef first_finderF<
|
||||
search_iterator_type,
|
||||
PredicateT> first_finder_type;
|
||||
|
||||
// Construction
|
||||
template< typename SearchT >
|
||||
last_finderF( const SearchT& Search, PredicateT Comp ) :
|
||||
m_Search(::boost::begin(Search), ::boost::end(Search)), m_Comp(Comp) {}
|
||||
last_finderF(
|
||||
search_iterator_type SearchBegin,
|
||||
search_iterator_type SearchEnd,
|
||||
PredicateT Comp ) :
|
||||
m_Search(SearchBegin, SearchEnd), m_Comp(Comp) {}
|
||||
|
||||
// Operation
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
operator()(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End ) const
|
||||
{
|
||||
typedef iterator_range<ForwardIteratorT> result_type;
|
||||
|
||||
if( boost::empty(m_Search) )
|
||||
return result_type( End, End );
|
||||
|
||||
typedef BOOST_STRING_TYPENAME boost::detail::
|
||||
iterator_traits<ForwardIteratorT>::iterator_category category;
|
||||
|
||||
return findit( Begin, End, category() );
|
||||
}
|
||||
|
||||
private:
|
||||
// forward iterator
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
findit(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End,
|
||||
std::forward_iterator_tag ) const
|
||||
{
|
||||
typedef iterator_range<ForwardIteratorT> result_type;
|
||||
|
||||
first_finder_type first_finder(
|
||||
m_Search.begin(), m_Search.end(), m_Comp );
|
||||
|
||||
result_type M=first_finder( Begin, End );
|
||||
result_type Last=M;
|
||||
|
||||
while( M )
|
||||
{
|
||||
Last=M;
|
||||
M=first_finder( ::boost::end(M), End );
|
||||
}
|
||||
|
||||
return Last;
|
||||
}
|
||||
|
||||
// bidirectional iterator
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
findit(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End,
|
||||
std::bidirectional_iterator_tag ) const
|
||||
{
|
||||
typedef iterator_range<ForwardIteratorT> result_type;
|
||||
typedef ForwardIteratorT input_iterator_type;
|
||||
|
||||
// Outer loop
|
||||
for(input_iterator_type OuterIt=End;
|
||||
OuterIt!=Begin; )
|
||||
{
|
||||
input_iterator_type OuterIt2=--OuterIt;
|
||||
|
||||
input_iterator_type InnerIt=OuterIt2;
|
||||
search_iterator_type SubstrIt=m_Search.begin();
|
||||
for(;
|
||||
InnerIt!=End && SubstrIt!=m_Search.end();
|
||||
++InnerIt,++SubstrIt)
|
||||
{
|
||||
if( !( m_Comp(*InnerIt,*SubstrIt) ) )
|
||||
break;
|
||||
}
|
||||
|
||||
// Substring matching succeeded
|
||||
if( SubstrIt==m_Search.end() )
|
||||
return result_type( OuterIt2, InnerIt );
|
||||
}
|
||||
|
||||
return result_type( End, End );
|
||||
}
|
||||
|
||||
private:
|
||||
iterator_range<search_iterator_type> m_Search;
|
||||
PredicateT m_Comp;
|
||||
};
|
||||
|
||||
// find n-th functor -----------------------------------------------//
|
||||
|
||||
// find the n-th match of a subsequence in the sequence ( functor )
|
||||
/*
|
||||
Returns a pair <begin,end> marking the subsequence in the sequence.
|
||||
If the find fails, returns <End,End>
|
||||
*/
|
||||
template<typename SearchIteratorT, typename PredicateT>
|
||||
struct nth_finderF
|
||||
{
|
||||
typedef SearchIteratorT search_iterator_type;
|
||||
typedef first_finderF<
|
||||
search_iterator_type,
|
||||
PredicateT> first_finder_type;
|
||||
typedef last_finderF<
|
||||
search_iterator_type,
|
||||
PredicateT> last_finder_type;
|
||||
|
||||
// Construction
|
||||
template< typename SearchT >
|
||||
nth_finderF(
|
||||
const SearchT& Search,
|
||||
int Nth,
|
||||
PredicateT Comp) :
|
||||
m_Search(::boost::begin(Search), ::boost::end(Search)),
|
||||
m_Nth(Nth),
|
||||
m_Comp(Comp) {}
|
||||
nth_finderF(
|
||||
search_iterator_type SearchBegin,
|
||||
search_iterator_type SearchEnd,
|
||||
int Nth,
|
||||
PredicateT Comp) :
|
||||
m_Search(SearchBegin, SearchEnd),
|
||||
m_Nth(Nth),
|
||||
m_Comp(Comp) {}
|
||||
|
||||
// Operation
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
operator()(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End ) const
|
||||
{
|
||||
if(m_Nth>=0)
|
||||
{
|
||||
return find_forward(Begin, End, m_Nth);
|
||||
}
|
||||
else
|
||||
{
|
||||
return find_backward(Begin, End, -m_Nth);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
// Implementation helpers
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
find_forward(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End,
|
||||
unsigned int N) const
|
||||
{
|
||||
typedef iterator_range<ForwardIteratorT> result_type;
|
||||
|
||||
// Sanity check
|
||||
if( boost::empty(m_Search) )
|
||||
return result_type( End, End );
|
||||
|
||||
// Instantiate find functor
|
||||
first_finder_type first_finder(
|
||||
m_Search.begin(), m_Search.end(), m_Comp );
|
||||
|
||||
result_type M( Begin, Begin );
|
||||
|
||||
for( unsigned int n=0; n<=N; ++n )
|
||||
{
|
||||
// find next match
|
||||
M=first_finder( ::boost::end(M), End );
|
||||
|
||||
if ( !M )
|
||||
{
|
||||
// Subsequence not found, return
|
||||
return M;
|
||||
}
|
||||
}
|
||||
|
||||
return M;
|
||||
}
|
||||
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
find_backward(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End,
|
||||
unsigned int N) const
|
||||
{
|
||||
typedef iterator_range<ForwardIteratorT> result_type;
|
||||
|
||||
// Sanity check
|
||||
if( boost::empty(m_Search) )
|
||||
return result_type( End, End );
|
||||
|
||||
// Instantiate find functor
|
||||
last_finder_type last_finder(
|
||||
m_Search.begin(), m_Search.end(), m_Comp );
|
||||
|
||||
result_type M( End, End );
|
||||
|
||||
for( unsigned int n=1; n<=N; ++n )
|
||||
{
|
||||
// find next match
|
||||
M=last_finder( Begin, ::boost::begin(M) );
|
||||
|
||||
if ( !M )
|
||||
{
|
||||
// Subsequence not found, return
|
||||
return M;
|
||||
}
|
||||
}
|
||||
|
||||
return M;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
iterator_range<search_iterator_type> m_Search;
|
||||
int m_Nth;
|
||||
PredicateT m_Comp;
|
||||
};
|
||||
|
||||
// find head/tail implementation helpers ---------------------------//
|
||||
|
||||
template<typename ForwardIteratorT>
|
||||
iterator_range<ForwardIteratorT>
|
||||
find_head_impl(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End,
|
||||
unsigned int N,
|
||||
std::forward_iterator_tag )
|
||||
{
|
||||
typedef ForwardIteratorT input_iterator_type;
|
||||
typedef iterator_range<ForwardIteratorT> result_type;
|
||||
|
||||
input_iterator_type It=Begin;
|
||||
for(
|
||||
unsigned int Index=0;
|
||||
Index<N && It!=End; ++Index,++It ) {};
|
||||
|
||||
return result_type( Begin, It );
|
||||
}
|
||||
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
find_head_impl(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End,
|
||||
unsigned int N,
|
||||
std::random_access_iterator_tag )
|
||||
{
|
||||
typedef iterator_range<ForwardIteratorT> result_type;
|
||||
|
||||
if ( (End<=Begin) || ( static_cast<unsigned int>(End-Begin) < N ) )
|
||||
return result_type( Begin, End );
|
||||
|
||||
return result_type(Begin,Begin+N);
|
||||
}
|
||||
|
||||
// Find head implementation
|
||||
template<typename ForwardIteratorT>
|
||||
iterator_range<ForwardIteratorT>
|
||||
find_head_impl(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End,
|
||||
unsigned int N )
|
||||
{
|
||||
typedef BOOST_STRING_TYPENAME boost::detail::
|
||||
iterator_traits<ForwardIteratorT>::iterator_category category;
|
||||
|
||||
return ::boost::algorithm::detail::find_head_impl( Begin, End, N, category() );
|
||||
}
|
||||
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
find_tail_impl(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End,
|
||||
unsigned int N,
|
||||
std::forward_iterator_tag )
|
||||
{
|
||||
typedef ForwardIteratorT input_iterator_type;
|
||||
typedef iterator_range<ForwardIteratorT> result_type;
|
||||
|
||||
unsigned int Index=0;
|
||||
input_iterator_type It=Begin;
|
||||
input_iterator_type It2=Begin;
|
||||
|
||||
// Advance It2 by N increments
|
||||
for( Index=0; Index<N && It2!=End; ++Index,++It2 ) {};
|
||||
|
||||
// Advance It, It2 to the end
|
||||
for(; It2!=End; ++It,++It2 ) {};
|
||||
|
||||
return result_type( It, It2 );
|
||||
}
|
||||
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
find_tail_impl(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End,
|
||||
unsigned int N,
|
||||
std::bidirectional_iterator_tag )
|
||||
{
|
||||
typedef ForwardIteratorT input_iterator_type;
|
||||
typedef iterator_range<ForwardIteratorT> result_type;
|
||||
|
||||
input_iterator_type It=End;
|
||||
for(
|
||||
unsigned int Index=0;
|
||||
Index<N && It!=Begin; ++Index,--It ) {};
|
||||
|
||||
return result_type( It, End );
|
||||
}
|
||||
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
find_tail_impl(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End,
|
||||
unsigned int N,
|
||||
std::random_access_iterator_tag )
|
||||
{
|
||||
typedef iterator_range<ForwardIteratorT> result_type;
|
||||
|
||||
if ( (End<=Begin) || ( static_cast<unsigned int>(End-Begin) < N ) )
|
||||
return result_type( Begin, End );
|
||||
|
||||
return result_type( End-N, End );
|
||||
}
|
||||
|
||||
// Operation
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
find_tail_impl(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End,
|
||||
unsigned int N )
|
||||
{
|
||||
typedef BOOST_STRING_TYPENAME boost::detail::
|
||||
iterator_traits<ForwardIteratorT>::iterator_category category;
|
||||
|
||||
return ::boost::algorithm::detail::find_tail_impl( Begin, End, N, category() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// find head functor -----------------------------------------------//
|
||||
|
||||
|
||||
// find a head in the sequence ( functor )
|
||||
/*
|
||||
This functor find a head of the specified range. For
|
||||
a specified N, the head is a subsequence of N starting
|
||||
elements of the range.
|
||||
*/
|
||||
struct head_finderF
|
||||
{
|
||||
// Construction
|
||||
head_finderF( int N ) : m_N(N) {}
|
||||
|
||||
// Operation
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
operator()(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End ) const
|
||||
{
|
||||
if(m_N>=0)
|
||||
{
|
||||
return ::boost::algorithm::detail::find_head_impl( Begin, End, m_N );
|
||||
}
|
||||
else
|
||||
{
|
||||
iterator_range<ForwardIteratorT> Res=
|
||||
::boost::algorithm::detail::find_tail_impl( Begin, End, -m_N );
|
||||
|
||||
return ::boost::make_iterator_range(Begin, Res.begin());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int m_N;
|
||||
};
|
||||
|
||||
// find tail functor -----------------------------------------------//
|
||||
|
||||
|
||||
// find a tail in the sequence ( functor )
|
||||
/*
|
||||
This functor find a tail of the specified range. For
|
||||
a specified N, the head is a subsequence of N starting
|
||||
elements of the range.
|
||||
*/
|
||||
struct tail_finderF
|
||||
{
|
||||
// Construction
|
||||
tail_finderF( int N ) : m_N(N) {}
|
||||
|
||||
// Operation
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
operator()(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End ) const
|
||||
{
|
||||
if(m_N>=0)
|
||||
{
|
||||
return ::boost::algorithm::detail::find_tail_impl( Begin, End, m_N );
|
||||
}
|
||||
else
|
||||
{
|
||||
iterator_range<ForwardIteratorT> Res=
|
||||
::boost::algorithm::detail::find_head_impl( Begin, End, -m_N );
|
||||
|
||||
return ::boost::make_iterator_range(Res.end(), End);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int m_N;
|
||||
};
|
||||
|
||||
// find token functor -----------------------------------------------//
|
||||
|
||||
// find a token in a sequence ( functor )
|
||||
/*
|
||||
This find functor finds a token specified be a predicate
|
||||
in a sequence. It is equivalent of std::find algorithm,
|
||||
with an exception that it return range instead of a single
|
||||
iterator.
|
||||
|
||||
If bCompress is set to true, adjacent matching tokens are
|
||||
concatenated into one match.
|
||||
*/
|
||||
template< typename PredicateT >
|
||||
struct token_finderF
|
||||
{
|
||||
// Construction
|
||||
token_finderF(
|
||||
PredicateT Pred,
|
||||
token_compress_mode_type eCompress=token_compress_off ) :
|
||||
m_Pred(Pred), m_eCompress(eCompress) {}
|
||||
|
||||
// Operation
|
||||
template< typename ForwardIteratorT >
|
||||
iterator_range<ForwardIteratorT>
|
||||
operator()(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End ) const
|
||||
{
|
||||
typedef iterator_range<ForwardIteratorT> result_type;
|
||||
|
||||
ForwardIteratorT It=std::find_if( Begin, End, m_Pred );
|
||||
|
||||
if( It==End )
|
||||
{
|
||||
return result_type( End, End );
|
||||
}
|
||||
else
|
||||
{
|
||||
ForwardIteratorT It2=It;
|
||||
|
||||
if( m_eCompress==token_compress_on )
|
||||
{
|
||||
// Find first non-matching character
|
||||
while( It2!=End && m_Pred(*It2) ) ++It2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Advance by one position
|
||||
++It2;
|
||||
}
|
||||
|
||||
return result_type( It, It2 );
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
PredicateT m_Pred;
|
||||
token_compress_mode_type m_eCompress;
|
||||
};
|
||||
|
||||
// find range functor -----------------------------------------------//
|
||||
|
||||
// find a range in the sequence ( functor )
|
||||
/*
|
||||
This functor actually does not perform any find operation.
|
||||
It always returns given iterator range as a result.
|
||||
*/
|
||||
template<typename ForwardIterator1T>
|
||||
struct range_finderF
|
||||
{
|
||||
typedef ForwardIterator1T input_iterator_type;
|
||||
typedef iterator_range<input_iterator_type> result_type;
|
||||
|
||||
// Construction
|
||||
range_finderF(
|
||||
input_iterator_type Begin,
|
||||
input_iterator_type End ) : m_Range(Begin, End) {}
|
||||
|
||||
range_finderF(const iterator_range<input_iterator_type>& Range) :
|
||||
m_Range(Range) {}
|
||||
|
||||
// Operation
|
||||
template< typename ForwardIterator2T >
|
||||
iterator_range<ForwardIterator2T>
|
||||
operator()(
|
||||
ForwardIterator2T,
|
||||
ForwardIterator2T ) const
|
||||
{
|
||||
#if BOOST_WORKAROUND( __MWERKS__, <= 0x3003 )
|
||||
return iterator_range<const ForwardIterator2T>(this->m_Range);
|
||||
#else
|
||||
return m_Range;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
iterator_range<input_iterator_type> m_Range;
|
||||
};
|
||||
|
||||
|
||||
} // namespace detail
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_STRING_FINDER_DETAIL_HPP
|
||||
@ -1,119 +0,0 @@
|
||||
// Boost string_algo library formatter.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_FORMATTER_DETAIL_HPP
|
||||
#define BOOST_STRING_FORMATTER_DETAIL_HPP
|
||||
|
||||
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/range/const_iterator.hpp>
|
||||
|
||||
#include <boost/algorithm/string/detail/util.hpp>
|
||||
|
||||
// generic replace functors -----------------------------------------------//
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
namespace detail {
|
||||
|
||||
// const format functor ----------------------------------------------------//
|
||||
|
||||
// constant format functor
|
||||
template<typename RangeT>
|
||||
struct const_formatF
|
||||
{
|
||||
private:
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
range_const_iterator<RangeT>::type format_iterator;
|
||||
typedef iterator_range<format_iterator> result_type;
|
||||
|
||||
public:
|
||||
// Construction
|
||||
const_formatF(const RangeT& Format) :
|
||||
m_Format(::boost::begin(Format), ::boost::end(Format)) {}
|
||||
|
||||
// Operation
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||||
template<typename Range2T>
|
||||
result_type& operator()(const Range2T&)
|
||||
{
|
||||
return m_Format;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename Range2T>
|
||||
const result_type& operator()(const Range2T&) const
|
||||
{
|
||||
return m_Format;
|
||||
}
|
||||
|
||||
private:
|
||||
result_type m_Format;
|
||||
};
|
||||
|
||||
// identity format functor ----------------------------------------------------//
|
||||
|
||||
// identity format functor
|
||||
template<typename RangeT>
|
||||
struct identity_formatF
|
||||
{
|
||||
// Operation
|
||||
template< typename Range2T >
|
||||
const RangeT& operator()(const Range2T& Replace) const
|
||||
{
|
||||
return RangeT(::boost::begin(Replace), ::boost::end(Replace));
|
||||
}
|
||||
};
|
||||
|
||||
// empty format functor ( used by erase ) ------------------------------------//
|
||||
|
||||
// empty format functor
|
||||
template< typename CharT >
|
||||
struct empty_formatF
|
||||
{
|
||||
template< typename ReplaceT >
|
||||
empty_container<CharT> operator()(const ReplaceT&) const
|
||||
{
|
||||
return empty_container<CharT>();
|
||||
}
|
||||
};
|
||||
|
||||
// dissect format functor ----------------------------------------------------//
|
||||
|
||||
// dissect format functor
|
||||
template<typename FinderT>
|
||||
struct dissect_formatF
|
||||
{
|
||||
public:
|
||||
// Construction
|
||||
dissect_formatF(FinderT Finder) :
|
||||
m_Finder(Finder) {}
|
||||
|
||||
// Operation
|
||||
template<typename RangeT>
|
||||
inline iterator_range<
|
||||
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type>
|
||||
operator()(const RangeT& Replace) const
|
||||
{
|
||||
return m_Finder(::boost::begin(Replace), ::boost::end(Replace));
|
||||
}
|
||||
|
||||
private:
|
||||
FinderT m_Finder;
|
||||
};
|
||||
|
||||
|
||||
} // namespace detail
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_STRING_FORMATTER_DETAIL_HPP
|
||||
@ -1,77 +0,0 @@
|
||||
// Boost string_algo library predicate.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_PREDICATE_DETAIL_HPP
|
||||
#define BOOST_STRING_PREDICATE_DETAIL_HPP
|
||||
|
||||
#include <iterator>
|
||||
#include <boost/algorithm/string/find.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
namespace detail {
|
||||
|
||||
// ends_with predicate implementation ----------------------------------//
|
||||
|
||||
template<
|
||||
typename ForwardIterator1T,
|
||||
typename ForwardIterator2T,
|
||||
typename PredicateT>
|
||||
inline bool ends_with_iter_select(
|
||||
ForwardIterator1T Begin,
|
||||
ForwardIterator1T End,
|
||||
ForwardIterator2T SubBegin,
|
||||
ForwardIterator2T SubEnd,
|
||||
PredicateT Comp,
|
||||
std::bidirectional_iterator_tag)
|
||||
{
|
||||
ForwardIterator1T it=End;
|
||||
ForwardIterator2T pit=SubEnd;
|
||||
for(;it!=Begin && pit!=SubBegin;)
|
||||
{
|
||||
if( !(Comp(*(--it),*(--pit))) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return pit==SubBegin;
|
||||
}
|
||||
|
||||
template<
|
||||
typename ForwardIterator1T,
|
||||
typename ForwardIterator2T,
|
||||
typename PredicateT>
|
||||
inline bool ends_with_iter_select(
|
||||
ForwardIterator1T Begin,
|
||||
ForwardIterator1T End,
|
||||
ForwardIterator2T SubBegin,
|
||||
ForwardIterator2T SubEnd,
|
||||
PredicateT Comp,
|
||||
std::forward_iterator_tag)
|
||||
{
|
||||
if ( SubBegin==SubEnd )
|
||||
{
|
||||
// empty subsequence check
|
||||
return true;
|
||||
}
|
||||
|
||||
iterator_range<ForwardIterator1T> Result
|
||||
=last_finder(
|
||||
::boost::make_iterator_range(SubBegin, SubEnd),
|
||||
Comp)(Begin, End);
|
||||
|
||||
return !Result.empty() && Result.end()==End;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_PREDICATE_DETAIL_HPP
|
||||
@ -1,159 +0,0 @@
|
||||
// Boost string_algo library replace_storage.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_REPLACE_STORAGE_DETAIL_HPP
|
||||
#define BOOST_STRING_REPLACE_STORAGE_DETAIL_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/algorithm/string/sequence_traits.hpp>
|
||||
#include <boost/algorithm/string/detail/sequence.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
namespace detail {
|
||||
|
||||
// storage handling routines -----------------------------------------------//
|
||||
|
||||
template< typename StorageT, typename OutputIteratorT >
|
||||
inline OutputIteratorT move_from_storage(
|
||||
StorageT& Storage,
|
||||
OutputIteratorT DestBegin,
|
||||
OutputIteratorT DestEnd )
|
||||
{
|
||||
OutputIteratorT OutputIt=DestBegin;
|
||||
|
||||
while( !Storage.empty() && OutputIt!=DestEnd )
|
||||
{
|
||||
*OutputIt=Storage.front();
|
||||
Storage.pop_front();
|
||||
++OutputIt;
|
||||
}
|
||||
|
||||
return OutputIt;
|
||||
}
|
||||
|
||||
template< typename StorageT, typename WhatT >
|
||||
inline void copy_to_storage(
|
||||
StorageT& Storage,
|
||||
const WhatT& What )
|
||||
{
|
||||
Storage.insert( Storage.end(), ::boost::begin(What), ::boost::end(What) );
|
||||
}
|
||||
|
||||
|
||||
// process segment routine -----------------------------------------------//
|
||||
|
||||
template< bool HasStableIterators >
|
||||
struct process_segment_helper
|
||||
{
|
||||
// Optimized version of process_segment for generic sequence
|
||||
template<
|
||||
typename StorageT,
|
||||
typename InputT,
|
||||
typename ForwardIteratorT >
|
||||
ForwardIteratorT operator()(
|
||||
StorageT& Storage,
|
||||
InputT& /*Input*/,
|
||||
ForwardIteratorT InsertIt,
|
||||
ForwardIteratorT SegmentBegin,
|
||||
ForwardIteratorT SegmentEnd )
|
||||
{
|
||||
// Copy data from the storage until the beginning of the segment
|
||||
ForwardIteratorT It=::boost::algorithm::detail::move_from_storage( Storage, InsertIt, SegmentBegin );
|
||||
|
||||
// 3 cases are possible :
|
||||
// a) Storage is empty, It==SegmentBegin
|
||||
// b) Storage is empty, It!=SegmentBegin
|
||||
// c) Storage is not empty
|
||||
|
||||
if( Storage.empty() )
|
||||
{
|
||||
if( It==SegmentBegin )
|
||||
{
|
||||
// Case a) everything is grand, just return end of segment
|
||||
return SegmentEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Case b) move the segment backwards
|
||||
return std::copy( SegmentBegin, SegmentEnd, It );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Case c) -> shift the segment to the left and keep the overlap in the storage
|
||||
while( It!=SegmentEnd )
|
||||
{
|
||||
// Store value into storage
|
||||
Storage.push_back( *It );
|
||||
// Get the top from the storage and put it here
|
||||
*It=Storage.front();
|
||||
Storage.pop_front();
|
||||
|
||||
// Advance
|
||||
++It;
|
||||
}
|
||||
|
||||
return It;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct process_segment_helper< true >
|
||||
{
|
||||
// Optimized version of process_segment for list-like sequence
|
||||
template<
|
||||
typename StorageT,
|
||||
typename InputT,
|
||||
typename ForwardIteratorT >
|
||||
ForwardIteratorT operator()(
|
||||
StorageT& Storage,
|
||||
InputT& Input,
|
||||
ForwardIteratorT InsertIt,
|
||||
ForwardIteratorT SegmentBegin,
|
||||
ForwardIteratorT SegmentEnd )
|
||||
|
||||
{
|
||||
// Call replace to do the job
|
||||
::boost::algorithm::detail::replace( Input, InsertIt, SegmentBegin, Storage );
|
||||
// Empty the storage
|
||||
Storage.clear();
|
||||
// Iterators were not changed, simply return the end of segment
|
||||
return SegmentEnd;
|
||||
}
|
||||
};
|
||||
|
||||
// Process one segment in the replace_all algorithm
|
||||
template<
|
||||
typename StorageT,
|
||||
typename InputT,
|
||||
typename ForwardIteratorT >
|
||||
inline ForwardIteratorT process_segment(
|
||||
StorageT& Storage,
|
||||
InputT& Input,
|
||||
ForwardIteratorT InsertIt,
|
||||
ForwardIteratorT SegmentBegin,
|
||||
ForwardIteratorT SegmentEnd )
|
||||
{
|
||||
return
|
||||
process_segment_helper<
|
||||
has_stable_iterators<InputT>::value>()(
|
||||
Storage, Input, InsertIt, SegmentBegin, SegmentEnd );
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_STRING_REPLACE_STORAGE_DETAIL_HPP
|
||||
@ -1,200 +0,0 @@
|
||||
// Boost string_algo library sequence.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_DETAIL_SEQUENCE_HPP
|
||||
#define BOOST_STRING_DETAIL_SEQUENCE_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/mpl/logical.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
|
||||
#include <boost/algorithm/string/sequence_traits.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
namespace detail {
|
||||
|
||||
// insert helpers -------------------------------------------------//
|
||||
|
||||
template< typename InputT, typename ForwardIteratorT >
|
||||
inline void insert(
|
||||
InputT& Input,
|
||||
BOOST_STRING_TYPENAME InputT::iterator At,
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End )
|
||||
{
|
||||
Input.insert( At, Begin, End );
|
||||
}
|
||||
|
||||
template< typename InputT, typename InsertT >
|
||||
inline void insert(
|
||||
InputT& Input,
|
||||
BOOST_STRING_TYPENAME InputT::iterator At,
|
||||
const InsertT& Insert )
|
||||
{
|
||||
::boost::algorithm::detail::insert( Input, At, ::boost::begin(Insert), ::boost::end(Insert) );
|
||||
}
|
||||
|
||||
// erase helper ---------------------------------------------------//
|
||||
|
||||
// Erase a range in the sequence
|
||||
/*
|
||||
Returns the iterator pointing just after the erase subrange
|
||||
*/
|
||||
template< typename InputT >
|
||||
inline typename InputT::iterator erase(
|
||||
InputT& Input,
|
||||
BOOST_STRING_TYPENAME InputT::iterator From,
|
||||
BOOST_STRING_TYPENAME InputT::iterator To )
|
||||
{
|
||||
return Input.erase( From, To );
|
||||
}
|
||||
|
||||
// replace helper implementation ----------------------------------//
|
||||
|
||||
// Optimized version of replace for generic sequence containers
|
||||
// Assumption: insert and erase are expensive
|
||||
template< bool HasConstTimeOperations >
|
||||
struct replace_const_time_helper
|
||||
{
|
||||
template< typename InputT, typename ForwardIteratorT >
|
||||
void operator()(
|
||||
InputT& Input,
|
||||
BOOST_STRING_TYPENAME InputT::iterator From,
|
||||
BOOST_STRING_TYPENAME InputT::iterator To,
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End )
|
||||
{
|
||||
// Copy data to the container ( as much as possible )
|
||||
ForwardIteratorT InsertIt=Begin;
|
||||
BOOST_STRING_TYPENAME InputT::iterator InputIt=From;
|
||||
for(; InsertIt!=End && InputIt!=To; InsertIt++, InputIt++ )
|
||||
{
|
||||
*InputIt=*InsertIt;
|
||||
}
|
||||
|
||||
if ( InsertIt!=End )
|
||||
{
|
||||
// Replace sequence is longer, insert it
|
||||
Input.insert( InputIt, InsertIt, End );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( InputIt!=To )
|
||||
{
|
||||
// Replace sequence is shorter, erase the rest
|
||||
Input.erase( InputIt, To );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct replace_const_time_helper< true >
|
||||
{
|
||||
// Const-time erase and insert methods -> use them
|
||||
template< typename InputT, typename ForwardIteratorT >
|
||||
void operator()(
|
||||
InputT& Input,
|
||||
BOOST_STRING_TYPENAME InputT::iterator From,
|
||||
BOOST_STRING_TYPENAME InputT::iterator To,
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End )
|
||||
{
|
||||
BOOST_STRING_TYPENAME InputT::iterator At=Input.erase( From, To );
|
||||
if ( Begin!=End )
|
||||
{
|
||||
if(!Input.empty())
|
||||
{
|
||||
Input.insert( At, Begin, End );
|
||||
}
|
||||
else
|
||||
{
|
||||
Input.insert( Input.begin(), Begin, End );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// No native replace method
|
||||
template< bool HasNative >
|
||||
struct replace_native_helper
|
||||
{
|
||||
template< typename InputT, typename ForwardIteratorT >
|
||||
void operator()(
|
||||
InputT& Input,
|
||||
BOOST_STRING_TYPENAME InputT::iterator From,
|
||||
BOOST_STRING_TYPENAME InputT::iterator To,
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End )
|
||||
{
|
||||
replace_const_time_helper<
|
||||
boost::mpl::and_<
|
||||
has_const_time_insert<InputT>,
|
||||
has_const_time_erase<InputT> >::value >()(
|
||||
Input, From, To, Begin, End );
|
||||
}
|
||||
};
|
||||
|
||||
// Container has native replace method
|
||||
template<>
|
||||
struct replace_native_helper< true >
|
||||
{
|
||||
template< typename InputT, typename ForwardIteratorT >
|
||||
void operator()(
|
||||
InputT& Input,
|
||||
BOOST_STRING_TYPENAME InputT::iterator From,
|
||||
BOOST_STRING_TYPENAME InputT::iterator To,
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End )
|
||||
{
|
||||
Input.replace( From, To, Begin, End );
|
||||
}
|
||||
};
|
||||
|
||||
// replace helper -------------------------------------------------//
|
||||
|
||||
template< typename InputT, typename ForwardIteratorT >
|
||||
inline void replace(
|
||||
InputT& Input,
|
||||
BOOST_STRING_TYPENAME InputT::iterator From,
|
||||
BOOST_STRING_TYPENAME InputT::iterator To,
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End )
|
||||
{
|
||||
replace_native_helper< has_native_replace<InputT>::value >()(
|
||||
Input, From, To, Begin, End );
|
||||
}
|
||||
|
||||
template< typename InputT, typename InsertT >
|
||||
inline void replace(
|
||||
InputT& Input,
|
||||
BOOST_STRING_TYPENAME InputT::iterator From,
|
||||
BOOST_STRING_TYPENAME InputT::iterator To,
|
||||
const InsertT& Insert )
|
||||
{
|
||||
if(From!=To)
|
||||
{
|
||||
::boost::algorithm::detail::replace( Input, From, To, ::boost::begin(Insert), ::boost::end(Insert) );
|
||||
}
|
||||
else
|
||||
{
|
||||
::boost::algorithm::detail::insert( Input, From, ::boost::begin(Insert), ::boost::end(Insert) );
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_DETAIL_SEQUENCE_HPP
|
||||
@ -1,95 +0,0 @@
|
||||
// Boost string_algo library trim.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_TRIM_DETAIL_HPP
|
||||
#define BOOST_STRING_TRIM_DETAIL_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <boost/detail/iterator.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
namespace detail {
|
||||
|
||||
// trim iterator helper -----------------------------------------------//
|
||||
|
||||
template< typename ForwardIteratorT, typename PredicateT >
|
||||
inline ForwardIteratorT trim_end_iter_select(
|
||||
ForwardIteratorT InBegin,
|
||||
ForwardIteratorT InEnd,
|
||||
PredicateT IsSpace,
|
||||
std::forward_iterator_tag )
|
||||
{
|
||||
ForwardIteratorT TrimIt=InBegin;
|
||||
|
||||
for( ForwardIteratorT It=InBegin; It!=InEnd; ++It )
|
||||
{
|
||||
if ( !IsSpace(*It) )
|
||||
{
|
||||
TrimIt=It;
|
||||
++TrimIt;
|
||||
}
|
||||
}
|
||||
|
||||
return TrimIt;
|
||||
}
|
||||
|
||||
template< typename ForwardIteratorT, typename PredicateT >
|
||||
inline ForwardIteratorT trim_end_iter_select(
|
||||
ForwardIteratorT InBegin,
|
||||
ForwardIteratorT InEnd,
|
||||
PredicateT IsSpace,
|
||||
std::bidirectional_iterator_tag )
|
||||
{
|
||||
for( ForwardIteratorT It=InEnd; It!=InBegin; )
|
||||
{
|
||||
if ( !IsSpace(*(--It)) )
|
||||
return ++It;
|
||||
}
|
||||
|
||||
return InBegin;
|
||||
}
|
||||
// Search for first non matching character from the beginning of the sequence
|
||||
template< typename ForwardIteratorT, typename PredicateT >
|
||||
inline ForwardIteratorT trim_begin(
|
||||
ForwardIteratorT InBegin,
|
||||
ForwardIteratorT InEnd,
|
||||
PredicateT IsSpace )
|
||||
{
|
||||
ForwardIteratorT It=InBegin;
|
||||
for(; It!=InEnd; ++It )
|
||||
{
|
||||
if (!IsSpace(*It))
|
||||
return It;
|
||||
}
|
||||
|
||||
return It;
|
||||
}
|
||||
|
||||
// Search for first non matching character from the end of the sequence
|
||||
template< typename ForwardIteratorT, typename PredicateT >
|
||||
inline ForwardIteratorT trim_end(
|
||||
ForwardIteratorT InBegin,
|
||||
ForwardIteratorT InEnd,
|
||||
PredicateT IsSpace )
|
||||
{
|
||||
typedef BOOST_STRING_TYPENAME boost::detail::
|
||||
iterator_traits<ForwardIteratorT>::iterator_category category;
|
||||
|
||||
return ::boost::algorithm::detail::trim_end_iter_select( InBegin, InEnd, IsSpace, category() );
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_TRIM_DETAIL_HPP
|
||||
@ -1,107 +0,0 @@
|
||||
// Boost string_algo library util.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_UTIL_DETAIL_HPP
|
||||
#define BOOST_STRING_UTIL_DETAIL_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <functional>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
namespace detail {
|
||||
|
||||
// empty container -----------------------------------------------//
|
||||
|
||||
// empty_container
|
||||
/*
|
||||
This class represents always empty container,
|
||||
containing elements of type CharT.
|
||||
|
||||
It is supposed to be used in a const version only
|
||||
*/
|
||||
template< typename CharT >
|
||||
struct empty_container
|
||||
{
|
||||
typedef empty_container<CharT> type;
|
||||
typedef CharT value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef const value_type& reference;
|
||||
typedef const value_type& const_reference;
|
||||
typedef const value_type* iterator;
|
||||
typedef const value_type* const_iterator;
|
||||
|
||||
|
||||
// Operations
|
||||
const_iterator begin() const
|
||||
{
|
||||
return reinterpret_cast<const_iterator>(0);
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return reinterpret_cast<const_iterator>(0);
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_type size() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// bounded copy algorithm -----------------------------------------------//
|
||||
|
||||
// Bounded version of the std::copy algorithm
|
||||
template<typename InputIteratorT, typename OutputIteratorT>
|
||||
inline OutputIteratorT bounded_copy(
|
||||
InputIteratorT First,
|
||||
InputIteratorT Last,
|
||||
OutputIteratorT DestFirst,
|
||||
OutputIteratorT DestLast )
|
||||
{
|
||||
InputIteratorT InputIt=First;
|
||||
OutputIteratorT OutputIt=DestFirst;
|
||||
for(; InputIt!=Last && OutputIt!=DestLast; InputIt++, OutputIt++ )
|
||||
{
|
||||
*OutputIt=*InputIt;
|
||||
}
|
||||
|
||||
return OutputIt;
|
||||
}
|
||||
|
||||
// iterator range utilities -----------------------------------------//
|
||||
|
||||
// copy range functor
|
||||
template<
|
||||
typename SeqT,
|
||||
typename IteratorT=BOOST_STRING_TYPENAME SeqT::const_iterator >
|
||||
struct copy_iterator_rangeF
|
||||
{
|
||||
typedef iterator_range<IteratorT> argument_type;
|
||||
typedef SeqT result_type;
|
||||
SeqT operator()( const iterator_range<IteratorT>& Range ) const
|
||||
{
|
||||
return copy_range<SeqT>(Range);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_UTIL_DETAIL_HPP
|
||||
@ -1,844 +0,0 @@
|
||||
// Boost string_algo library erase.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2006.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_ERASE_HPP
|
||||
#define BOOST_STRING_ERASE_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/range/iterator.hpp>
|
||||
#include <boost/range/const_iterator.hpp>
|
||||
|
||||
#include <boost/algorithm/string/find_format.hpp>
|
||||
#include <boost/algorithm/string/finder.hpp>
|
||||
#include <boost/algorithm/string/formatter.hpp>
|
||||
|
||||
/*! \file
|
||||
Defines various erase algorithms. Each algorithm removes
|
||||
part(s) of the input according to a searching criteria.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// erase_range -------------------------------------------------------//
|
||||
|
||||
//! Erase range algorithm
|
||||
/*!
|
||||
Remove the given range from the input. The result is a modified copy of
|
||||
the input. It is returned as a sequence or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input sequence
|
||||
\param SearchRange A range in the input to be removed
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename OutputIteratorT, typename RangeT>
|
||||
inline OutputIteratorT erase_range_copy(
|
||||
OutputIteratorT Output,
|
||||
const RangeT& Input,
|
||||
const iterator_range<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_const_iterator<RangeT>::type>& SearchRange )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::range_finder(SearchRange),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase range algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT>
|
||||
inline SequenceT erase_range_copy(
|
||||
const SequenceT& Input,
|
||||
const iterator_range<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_const_iterator<SequenceT>::type>& SearchRange )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::range_finder(SearchRange),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase range algorithm
|
||||
/*!
|
||||
Remove the given range from the input.
|
||||
The input sequence is modified in-place.
|
||||
|
||||
\param Input An input sequence
|
||||
\param SearchRange A range in the input to be removed
|
||||
*/
|
||||
template<typename SequenceT>
|
||||
inline void erase_range(
|
||||
SequenceT& Input,
|
||||
const iterator_range<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_iterator<SequenceT>::type>& SearchRange )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::range_finder(SearchRange),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
// erase_first --------------------------------------------------------//
|
||||
|
||||
//! Erase first algorithm
|
||||
/*!
|
||||
Remove the first occurrence of the substring from the input.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T>
|
||||
inline OutputIteratorT erase_first_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase first algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline SequenceT erase_first_copy(
|
||||
const SequenceT& Input,
|
||||
const RangeT& Search )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase first algorithm
|
||||
/*!
|
||||
Remove the first occurrence of the substring from the input.
|
||||
The input sequence is modified in-place.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for.
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline void erase_first(
|
||||
SequenceT& Input,
|
||||
const RangeT& Search )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
// erase_first ( case insensitive ) ------------------------------------//
|
||||
|
||||
//! Erase first algorithm ( case insensitive )
|
||||
/*!
|
||||
Remove the first occurrence of the substring from the input.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T>
|
||||
inline OutputIteratorT ierase_first_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase first algorithm ( case insensitive )
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline SequenceT ierase_first_copy(
|
||||
const SequenceT& Input,
|
||||
const RangeT& Search,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase first algorithm ( case insensitive )
|
||||
/*!
|
||||
Remove the first occurrence of the substring from the input.
|
||||
The input sequence is modified in-place. Searching is case insensitive.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline void ierase_first(
|
||||
SequenceT& Input,
|
||||
const RangeT& Search,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
// erase_last --------------------------------------------------------//
|
||||
|
||||
//! Erase last algorithm
|
||||
/*!
|
||||
Remove the last occurrence of the substring from the input.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for.
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T>
|
||||
inline OutputIteratorT erase_last_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::last_finder(Search),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase last algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline SequenceT erase_last_copy(
|
||||
const SequenceT& Input,
|
||||
const RangeT& Search )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::last_finder(Search),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase last algorithm
|
||||
/*!
|
||||
Remove the last occurrence of the substring from the input.
|
||||
The input sequence is modified in-place.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline void erase_last(
|
||||
SequenceT& Input,
|
||||
const RangeT& Search )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::last_finder(Search),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
// erase_last ( case insensitive ) ------------------------------------//
|
||||
|
||||
//! Erase last algorithm ( case insensitive )
|
||||
/*!
|
||||
Remove the last occurrence of the substring from the input.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T>
|
||||
inline OutputIteratorT ierase_last_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::last_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase last algorithm ( case insensitive )
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline SequenceT ierase_last_copy(
|
||||
const SequenceT& Input,
|
||||
const RangeT& Search,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::last_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase last algorithm ( case insensitive )
|
||||
/*!
|
||||
Remove the last occurrence of the substring from the input.
|
||||
The input sequence is modified in-place. Searching is case insensitive.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline void ierase_last(
|
||||
SequenceT& Input,
|
||||
const RangeT& Search,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::last_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
// erase_nth --------------------------------------------------------------------//
|
||||
|
||||
//! Erase nth algorithm
|
||||
/*!
|
||||
Remove the Nth occurrence of the substring in the input.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Nth An index of the match to be replaced. The index is 0-based.
|
||||
For negative N, matches are counted from the end of string.
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T>
|
||||
inline OutputIteratorT erase_nth_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search,
|
||||
int Nth )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::nth_finder(Search, Nth),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase nth algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline SequenceT erase_nth_copy(
|
||||
const SequenceT& Input,
|
||||
const RangeT& Search,
|
||||
int Nth )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::nth_finder(Search, Nth),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase nth algorithm
|
||||
/*!
|
||||
Remove the Nth occurrence of the substring in the input.
|
||||
The input sequence is modified in-place.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for.
|
||||
\param Nth An index of the match to be replaced. The index is 0-based.
|
||||
For negative N, matches are counted from the end of string.
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline void erase_nth(
|
||||
SequenceT& Input,
|
||||
const RangeT& Search,
|
||||
int Nth )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::nth_finder(Search, Nth),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
// erase_nth ( case insensitive ) ---------------------------------------------//
|
||||
|
||||
//! Erase nth algorithm ( case insensitive )
|
||||
/*!
|
||||
Remove the Nth occurrence of the substring in the input.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for.
|
||||
\param Nth An index of the match to be replaced. The index is 0-based.
|
||||
For negative N, matches are counted from the end of string.
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T>
|
||||
inline OutputIteratorT ierase_nth_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search,
|
||||
int Nth,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase nth algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline SequenceT ierase_nth_copy(
|
||||
const SequenceT& Input,
|
||||
const RangeT& Search,
|
||||
int Nth,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)),
|
||||
empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase nth algorithm
|
||||
/*!
|
||||
Remove the Nth occurrence of the substring in the input.
|
||||
The input sequence is modified in-place. Searching is case insensitive.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for.
|
||||
\param Nth An index of the match to be replaced. The index is 0-based.
|
||||
For negative N, matches are counted from the end of string.
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline void ierase_nth(
|
||||
SequenceT& Input,
|
||||
const RangeT& Search,
|
||||
int Nth,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
|
||||
// erase_all --------------------------------------------------------//
|
||||
|
||||
//! Erase all algorithm
|
||||
/*!
|
||||
Remove all the occurrences of the string from the input.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input sequence
|
||||
\param Search A substring to be searched for.
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T>
|
||||
inline OutputIteratorT erase_all_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search )
|
||||
{
|
||||
return ::boost::algorithm::find_format_all_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase all algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline SequenceT erase_all_copy(
|
||||
const SequenceT& Input,
|
||||
const RangeT& Search )
|
||||
{
|
||||
return ::boost::algorithm::find_format_all_copy(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase all algorithm
|
||||
/*!
|
||||
Remove all the occurrences of the string from the input.
|
||||
The input sequence is modified in-place.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for.
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline void erase_all(
|
||||
SequenceT& Input,
|
||||
const RangeT& Search )
|
||||
{
|
||||
::boost::algorithm::find_format_all(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
// erase_all ( case insensitive ) ------------------------------------//
|
||||
|
||||
//! Erase all algorithm ( case insensitive )
|
||||
/*!
|
||||
Remove all the occurrences of the string from the input.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T>
|
||||
inline OutputIteratorT ierase_all_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_all_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase all algorithm ( case insensitive )
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline SequenceT ierase_all_copy(
|
||||
const SequenceT& Input,
|
||||
const RangeT& Search,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_all_copy(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
//! Erase all algorithm ( case insensitive )
|
||||
/*!
|
||||
Remove all the occurrences of the string from the input.
|
||||
The input sequence is modified in-place. Searching is case insensitive.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for.
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline void ierase_all(
|
||||
SequenceT& Input,
|
||||
const RangeT& Search,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
::boost::algorithm::find_format_all(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::empty_formatter(Input) );
|
||||
}
|
||||
|
||||
// erase_head --------------------------------------------------------------------//
|
||||
|
||||
//! Erase head algorithm
|
||||
/*!
|
||||
Remove the head from the input. The head is a prefix of a sequence of given size.
|
||||
If the sequence is shorter then required, the whole string is
|
||||
considered to be the head. The result is a modified copy of the input.
|
||||
It is returned as a sequence or copied to the output iterator.
|
||||
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param N Length of the head.
|
||||
For N>=0, at most N characters are extracted.
|
||||
For N<0, size(Input)-|N| characters are extracted.
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename RangeT>
|
||||
inline OutputIteratorT erase_head_copy(
|
||||
OutputIteratorT Output,
|
||||
const RangeT& Input,
|
||||
int N )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::head_finder(N),
|
||||
::boost::algorithm::empty_formatter( Input ) );
|
||||
}
|
||||
|
||||
//! Erase head algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT>
|
||||
inline SequenceT erase_head_copy(
|
||||
const SequenceT& Input,
|
||||
int N )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::head_finder(N),
|
||||
::boost::algorithm::empty_formatter( Input ) );
|
||||
}
|
||||
|
||||
//! Erase head algorithm
|
||||
/*!
|
||||
Remove the head from the input. The head is a prefix of a sequence of given size.
|
||||
If the sequence is shorter then required, the whole string is
|
||||
considered to be the head. The input sequence is modified in-place.
|
||||
|
||||
\param Input An input string
|
||||
\param N Length of the head
|
||||
For N>=0, at most N characters are extracted.
|
||||
For N<0, size(Input)-|N| characters are extracted.
|
||||
*/
|
||||
template<typename SequenceT>
|
||||
inline void erase_head(
|
||||
SequenceT& Input,
|
||||
int N )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::head_finder(N),
|
||||
::boost::algorithm::empty_formatter( Input ) );
|
||||
}
|
||||
|
||||
// erase_tail --------------------------------------------------------------------//
|
||||
|
||||
//! Erase tail algorithm
|
||||
/*!
|
||||
Remove the tail from the input. The tail is a suffix of a sequence of given size.
|
||||
If the sequence is shorter then required, the whole string is
|
||||
considered to be the tail.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param N Length of the tail.
|
||||
For N>=0, at most N characters are extracted.
|
||||
For N<0, size(Input)-|N| characters are extracted.
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename RangeT>
|
||||
inline OutputIteratorT erase_tail_copy(
|
||||
OutputIteratorT Output,
|
||||
const RangeT& Input,
|
||||
int N )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::tail_finder(N),
|
||||
::boost::algorithm::empty_formatter( Input ) );
|
||||
}
|
||||
|
||||
//! Erase tail algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT>
|
||||
inline SequenceT erase_tail_copy(
|
||||
const SequenceT& Input,
|
||||
int N )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::tail_finder(N),
|
||||
::boost::algorithm::empty_formatter( Input ) );
|
||||
}
|
||||
|
||||
//! Erase tail algorithm
|
||||
/*!
|
||||
Remove the tail from the input. The tail is a suffix of a sequence of given size.
|
||||
If the sequence is shorter then required, the whole string is
|
||||
considered to be the tail. The input sequence is modified in-place.
|
||||
|
||||
\param Input An input string
|
||||
\param N Length of the tail
|
||||
For N>=0, at most N characters are extracted.
|
||||
For N<0, size(Input)-|N| characters are extracted.
|
||||
*/
|
||||
template<typename SequenceT>
|
||||
inline void erase_tail(
|
||||
SequenceT& Input,
|
||||
int N )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::tail_finder(N),
|
||||
::boost::algorithm::empty_formatter( Input ) );
|
||||
}
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull names into the boost namespace
|
||||
using algorithm::erase_range_copy;
|
||||
using algorithm::erase_range;
|
||||
using algorithm::erase_first_copy;
|
||||
using algorithm::erase_first;
|
||||
using algorithm::ierase_first_copy;
|
||||
using algorithm::ierase_first;
|
||||
using algorithm::erase_last_copy;
|
||||
using algorithm::erase_last;
|
||||
using algorithm::ierase_last_copy;
|
||||
using algorithm::ierase_last;
|
||||
using algorithm::erase_nth_copy;
|
||||
using algorithm::erase_nth;
|
||||
using algorithm::ierase_nth_copy;
|
||||
using algorithm::ierase_nth;
|
||||
using algorithm::erase_all_copy;
|
||||
using algorithm::erase_all;
|
||||
using algorithm::ierase_all_copy;
|
||||
using algorithm::ierase_all;
|
||||
using algorithm::erase_head_copy;
|
||||
using algorithm::erase_head;
|
||||
using algorithm::erase_tail_copy;
|
||||
using algorithm::erase_tail;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_ERASE_HPP
|
||||
@ -1,334 +0,0 @@
|
||||
// Boost string_algo library find.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_FIND_HPP
|
||||
#define BOOST_STRING_FIND_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/range/iterator.hpp>
|
||||
#include <boost/range/as_literal.hpp>
|
||||
|
||||
#include <boost/algorithm/string/finder.hpp>
|
||||
#include <boost/algorithm/string/compare.hpp>
|
||||
#include <boost/algorithm/string/constants.hpp>
|
||||
|
||||
/*! \file
|
||||
Defines a set of find algorithms. The algorithms are searching
|
||||
for a substring of the input. The result is given as an \c iterator_range
|
||||
delimiting the substring.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// Generic find -----------------------------------------------//
|
||||
|
||||
//! Generic find algorithm
|
||||
/*!
|
||||
Search the input using the given finder.
|
||||
|
||||
\param Input A string which will be searched.
|
||||
\param Finder Finder object used for searching.
|
||||
\return
|
||||
An \c iterator_range delimiting the match.
|
||||
Returned iterator is either \c RangeT::iterator or
|
||||
\c RangeT::const_iterator, depending on the constness of
|
||||
the input parameter.
|
||||
*/
|
||||
template<typename RangeT, typename FinderT>
|
||||
inline iterator_range<
|
||||
BOOST_STRING_TYPENAME range_iterator<RangeT>::type>
|
||||
find(
|
||||
RangeT& Input,
|
||||
const FinderT& Finder)
|
||||
{
|
||||
iterator_range<BOOST_STRING_TYPENAME range_iterator<RangeT>::type> lit_input(::boost::as_literal(Input));
|
||||
|
||||
return Finder(::boost::begin(lit_input),::boost::end(lit_input));
|
||||
}
|
||||
|
||||
// find_first -----------------------------------------------//
|
||||
|
||||
//! Find first algorithm
|
||||
/*!
|
||||
Search for the first occurrence of the substring in the input.
|
||||
|
||||
\param Input A string which will be searched.
|
||||
\param Search A substring to be searched for.
|
||||
\return
|
||||
An \c iterator_range delimiting the match.
|
||||
Returned iterator is either \c RangeT::iterator or
|
||||
\c RangeT::const_iterator, depending on the constness of
|
||||
the input parameter.
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline iterator_range<
|
||||
BOOST_STRING_TYPENAME range_iterator<Range1T>::type>
|
||||
find_first(
|
||||
Range1T& Input,
|
||||
const Range2T& Search)
|
||||
{
|
||||
return ::boost::algorithm::find(Input, ::boost::algorithm::first_finder(Search));
|
||||
}
|
||||
|
||||
//! Find first algorithm ( case insensitive )
|
||||
/*!
|
||||
Search for the first occurrence of the substring in the input.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Input A string which will be searched.
|
||||
\param Search A substring to be searched for.
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return
|
||||
An \c iterator_range delimiting the match.
|
||||
Returned iterator is either \c Range1T::iterator or
|
||||
\c Range1T::const_iterator, depending on the constness of
|
||||
the input parameter.
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline iterator_range<
|
||||
BOOST_STRING_TYPENAME range_iterator<Range1T>::type>
|
||||
ifind_first(
|
||||
Range1T& Input,
|
||||
const Range2T& Search,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
return ::boost::algorithm::find(Input, ::boost::algorithm::first_finder(Search,is_iequal(Loc)));
|
||||
}
|
||||
|
||||
// find_last -----------------------------------------------//
|
||||
|
||||
//! Find last algorithm
|
||||
/*!
|
||||
Search for the last occurrence of the substring in the input.
|
||||
|
||||
\param Input A string which will be searched.
|
||||
\param Search A substring to be searched for.
|
||||
\return
|
||||
An \c iterator_range delimiting the match.
|
||||
Returned iterator is either \c Range1T::iterator or
|
||||
\c Range1T::const_iterator, depending on the constness of
|
||||
the input parameter.
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline iterator_range<
|
||||
BOOST_STRING_TYPENAME range_iterator<Range1T>::type>
|
||||
find_last(
|
||||
Range1T& Input,
|
||||
const Range2T& Search)
|
||||
{
|
||||
return ::boost::algorithm::find(Input, ::boost::algorithm::last_finder(Search));
|
||||
}
|
||||
|
||||
//! Find last algorithm ( case insensitive )
|
||||
/*!
|
||||
Search for the last match a string in the input.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Input A string which will be searched.
|
||||
\param Search A substring to be searched for.
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return
|
||||
An \c iterator_range delimiting the match.
|
||||
Returned iterator is either \c Range1T::iterator or
|
||||
\c Range1T::const_iterator, depending on the constness of
|
||||
the input parameter.
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline iterator_range<
|
||||
BOOST_STRING_TYPENAME range_iterator<Range1T>::type>
|
||||
ifind_last(
|
||||
Range1T& Input,
|
||||
const Range2T& Search,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
return ::boost::algorithm::find(Input, ::boost::algorithm::last_finder(Search, is_iequal(Loc)));
|
||||
}
|
||||
|
||||
// find_nth ----------------------------------------------------------------------//
|
||||
|
||||
//! Find n-th algorithm
|
||||
/*!
|
||||
Search for the n-th (zero-indexed) occurrence of the substring in the
|
||||
input.
|
||||
|
||||
\param Input A string which will be searched.
|
||||
\param Search A substring to be searched for.
|
||||
\param Nth An index (zero-indexed) of the match to be found.
|
||||
For negative N, the matches are counted from the end of string.
|
||||
\return
|
||||
An \c iterator_range delimiting the match.
|
||||
Returned iterator is either \c Range1T::iterator or
|
||||
\c Range1T::const_iterator, depending on the constness of
|
||||
the input parameter.
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline iterator_range<
|
||||
BOOST_STRING_TYPENAME range_iterator<Range1T>::type>
|
||||
find_nth(
|
||||
Range1T& Input,
|
||||
const Range2T& Search,
|
||||
int Nth)
|
||||
{
|
||||
return ::boost::algorithm::find(Input, ::boost::algorithm::nth_finder(Search,Nth));
|
||||
}
|
||||
|
||||
//! Find n-th algorithm ( case insensitive ).
|
||||
/*!
|
||||
Search for the n-th (zero-indexed) occurrence of the substring in the
|
||||
input. Searching is case insensitive.
|
||||
|
||||
\param Input A string which will be searched.
|
||||
\param Search A substring to be searched for.
|
||||
\param Nth An index (zero-indexed) of the match to be found.
|
||||
For negative N, the matches are counted from the end of string.
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return
|
||||
An \c iterator_range delimiting the match.
|
||||
Returned iterator is either \c Range1T::iterator or
|
||||
\c Range1T::const_iterator, depending on the constness of
|
||||
the input parameter.
|
||||
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline iterator_range<
|
||||
BOOST_STRING_TYPENAME range_iterator<Range1T>::type>
|
||||
ifind_nth(
|
||||
Range1T& Input,
|
||||
const Range2T& Search,
|
||||
int Nth,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
return ::boost::algorithm::find(Input, ::boost::algorithm::nth_finder(Search,Nth,is_iequal(Loc)));
|
||||
}
|
||||
|
||||
// find_head ----------------------------------------------------------------------//
|
||||
|
||||
//! Find head algorithm
|
||||
/*!
|
||||
Get the head of the input. Head is a prefix of the string of the
|
||||
given size. If the input is shorter then required, whole input is considered
|
||||
to be the head.
|
||||
|
||||
\param Input An input string
|
||||
\param N Length of the head
|
||||
For N>=0, at most N characters are extracted.
|
||||
For N<0, at most size(Input)-|N| characters are extracted.
|
||||
\return
|
||||
An \c iterator_range delimiting the match.
|
||||
Returned iterator is either \c Range1T::iterator or
|
||||
\c Range1T::const_iterator, depending on the constness of
|
||||
the input parameter.
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename RangeT>
|
||||
inline iterator_range<
|
||||
BOOST_STRING_TYPENAME range_iterator<RangeT>::type>
|
||||
find_head(
|
||||
RangeT& Input,
|
||||
int N)
|
||||
{
|
||||
return ::boost::algorithm::find(Input, ::boost::algorithm::head_finder(N));
|
||||
}
|
||||
|
||||
// find_tail ----------------------------------------------------------------------//
|
||||
|
||||
//! Find tail algorithm
|
||||
/*!
|
||||
Get the tail of the input. Tail is a suffix of the string of the
|
||||
given size. If the input is shorter then required, whole input is considered
|
||||
to be the tail.
|
||||
|
||||
\param Input An input string
|
||||
\param N Length of the tail.
|
||||
For N>=0, at most N characters are extracted.
|
||||
For N<0, at most size(Input)-|N| characters are extracted.
|
||||
\return
|
||||
An \c iterator_range delimiting the match.
|
||||
Returned iterator is either \c RangeT::iterator or
|
||||
\c RangeT::const_iterator, depending on the constness of
|
||||
the input parameter.
|
||||
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename RangeT>
|
||||
inline iterator_range<
|
||||
BOOST_STRING_TYPENAME range_iterator<RangeT>::type>
|
||||
find_tail(
|
||||
RangeT& Input,
|
||||
int N)
|
||||
{
|
||||
return ::boost::algorithm::find(Input, ::boost::algorithm::tail_finder(N));
|
||||
}
|
||||
|
||||
// find_token --------------------------------------------------------------------//
|
||||
|
||||
//! Find token algorithm
|
||||
/*!
|
||||
Look for a given token in the string. Token is a character that matches the
|
||||
given predicate.
|
||||
If the "token compress mode" is enabled, adjacent tokens are considered to be one match.
|
||||
|
||||
\param Input A input string.
|
||||
\param Pred A unary predicate to identify a token
|
||||
\param eCompress Enable/Disable compressing of adjacent tokens
|
||||
\return
|
||||
An \c iterator_range delimiting the match.
|
||||
Returned iterator is either \c RangeT::iterator or
|
||||
\c RangeT::const_iterator, depending on the constness of
|
||||
the input parameter.
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename RangeT, typename PredicateT>
|
||||
inline iterator_range<
|
||||
BOOST_STRING_TYPENAME range_iterator<RangeT>::type>
|
||||
find_token(
|
||||
RangeT& Input,
|
||||
PredicateT Pred,
|
||||
token_compress_mode_type eCompress=token_compress_off)
|
||||
{
|
||||
return ::boost::algorithm::find(Input, ::boost::algorithm::token_finder(Pred, eCompress));
|
||||
}
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull names to the boost namespace
|
||||
using algorithm::find;
|
||||
using algorithm::find_first;
|
||||
using algorithm::ifind_first;
|
||||
using algorithm::find_last;
|
||||
using algorithm::ifind_last;
|
||||
using algorithm::find_nth;
|
||||
using algorithm::ifind_nth;
|
||||
using algorithm::find_head;
|
||||
using algorithm::find_tail;
|
||||
using algorithm::find_token;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_FIND_HPP
|
||||
@ -1,287 +0,0 @@
|
||||
// Boost string_algo library find_format.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_FIND_FORMAT_HPP
|
||||
#define BOOST_STRING_FIND_FORMAT_HPP
|
||||
|
||||
#include <deque>
|
||||
#include <boost/detail/iterator.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/range/const_iterator.hpp>
|
||||
#include <boost/range/as_literal.hpp>
|
||||
|
||||
#include <boost/algorithm/string/concept.hpp>
|
||||
#include <boost/algorithm/string/detail/find_format.hpp>
|
||||
#include <boost/algorithm/string/detail/find_format_all.hpp>
|
||||
|
||||
/*! \file
|
||||
Defines generic replace algorithms. Each algorithm replaces
|
||||
part(s) of the input. The part to be replaced is looked up using a Finder object.
|
||||
Result of finding is then used by a Formatter object to generate the replacement.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// generic replace -----------------------------------------------------------------//
|
||||
|
||||
//! Generic replace algorithm
|
||||
/*!
|
||||
Use the Finder to search for a substring. Use the Formatter to format
|
||||
this substring and replace it in the input.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input sequence
|
||||
\param Finder A Finder object used to search for a match to be replaced
|
||||
\param Formatter A Formatter object used to format a match
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename RangeT,
|
||||
typename FinderT,
|
||||
typename FormatterT>
|
||||
inline OutputIteratorT find_format_copy(
|
||||
OutputIteratorT Output,
|
||||
const RangeT& Input,
|
||||
FinderT Finder,
|
||||
FormatterT Formatter )
|
||||
{
|
||||
// Concept check
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FinderConcept<
|
||||
FinderT,
|
||||
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type>
|
||||
));
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FormatterConcept<
|
||||
FormatterT,
|
||||
FinderT,BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type>
|
||||
));
|
||||
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> lit_input(::boost::as_literal(Input));
|
||||
|
||||
return detail::find_format_copy_impl(
|
||||
Output,
|
||||
lit_input,
|
||||
Formatter,
|
||||
Finder( ::boost::begin(lit_input), ::boost::end(lit_input) ) );
|
||||
}
|
||||
|
||||
//! Generic replace algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<
|
||||
typename SequenceT,
|
||||
typename FinderT,
|
||||
typename FormatterT>
|
||||
inline SequenceT find_format_copy(
|
||||
const SequenceT& Input,
|
||||
FinderT Finder,
|
||||
FormatterT Formatter )
|
||||
{
|
||||
// Concept check
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FinderConcept<
|
||||
FinderT,
|
||||
BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
|
||||
));
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FormatterConcept<
|
||||
FormatterT,
|
||||
FinderT,BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
|
||||
));
|
||||
|
||||
return detail::find_format_copy_impl(
|
||||
Input,
|
||||
Formatter,
|
||||
Finder(::boost::begin(Input), ::boost::end(Input)));
|
||||
}
|
||||
|
||||
//! Generic replace algorithm
|
||||
/*!
|
||||
Use the Finder to search for a substring. Use the Formatter to format
|
||||
this substring and replace it in the input. The input is modified in-place.
|
||||
|
||||
\param Input An input sequence
|
||||
\param Finder A Finder object used to search for a match to be replaced
|
||||
\param Formatter A Formatter object used to format a match
|
||||
*/
|
||||
template<
|
||||
typename SequenceT,
|
||||
typename FinderT,
|
||||
typename FormatterT>
|
||||
inline void find_format(
|
||||
SequenceT& Input,
|
||||
FinderT Finder,
|
||||
FormatterT Formatter)
|
||||
{
|
||||
// Concept check
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FinderConcept<
|
||||
FinderT,
|
||||
BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
|
||||
));
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FormatterConcept<
|
||||
FormatterT,
|
||||
FinderT,BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
|
||||
));
|
||||
|
||||
detail::find_format_impl(
|
||||
Input,
|
||||
Formatter,
|
||||
Finder(::boost::begin(Input), ::boost::end(Input)));
|
||||
}
|
||||
|
||||
|
||||
// find_format_all generic ----------------------------------------------------------------//
|
||||
|
||||
//! Generic replace all algorithm
|
||||
/*!
|
||||
Use the Finder to search for a substring. Use the Formatter to format
|
||||
this substring and replace it in the input. Repeat this for all matching
|
||||
substrings.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input sequence
|
||||
\param Finder A Finder object used to search for a match to be replaced
|
||||
\param Formatter A Formatter object used to format a match
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename RangeT,
|
||||
typename FinderT,
|
||||
typename FormatterT>
|
||||
inline OutputIteratorT find_format_all_copy(
|
||||
OutputIteratorT Output,
|
||||
const RangeT& Input,
|
||||
FinderT Finder,
|
||||
FormatterT Formatter)
|
||||
{
|
||||
// Concept check
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FinderConcept<
|
||||
FinderT,
|
||||
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type>
|
||||
));
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FormatterConcept<
|
||||
FormatterT,
|
||||
FinderT,BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type>
|
||||
));
|
||||
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> lit_input(::boost::as_literal(Input));
|
||||
|
||||
return detail::find_format_all_copy_impl(
|
||||
Output,
|
||||
lit_input,
|
||||
Finder,
|
||||
Formatter,
|
||||
Finder(::boost::begin(lit_input), ::boost::end(lit_input)));
|
||||
}
|
||||
|
||||
//! Generic replace all algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<
|
||||
typename SequenceT,
|
||||
typename FinderT,
|
||||
typename FormatterT >
|
||||
inline SequenceT find_format_all_copy(
|
||||
const SequenceT& Input,
|
||||
FinderT Finder,
|
||||
FormatterT Formatter )
|
||||
{
|
||||
// Concept check
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FinderConcept<
|
||||
FinderT,
|
||||
BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
|
||||
));
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FormatterConcept<
|
||||
FormatterT,
|
||||
FinderT,BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
|
||||
));
|
||||
|
||||
return detail::find_format_all_copy_impl(
|
||||
Input,
|
||||
Finder,
|
||||
Formatter,
|
||||
Finder( ::boost::begin(Input), ::boost::end(Input) ) );
|
||||
}
|
||||
|
||||
//! Generic replace all algorithm
|
||||
/*!
|
||||
Use the Finder to search for a substring. Use the Formatter to format
|
||||
this substring and replace it in the input. Repeat this for all matching
|
||||
substrings.The input is modified in-place.
|
||||
|
||||
\param Input An input sequence
|
||||
\param Finder A Finder object used to search for a match to be replaced
|
||||
\param Formatter A Formatter object used to format a match
|
||||
*/
|
||||
template<
|
||||
typename SequenceT,
|
||||
typename FinderT,
|
||||
typename FormatterT >
|
||||
inline void find_format_all(
|
||||
SequenceT& Input,
|
||||
FinderT Finder,
|
||||
FormatterT Formatter )
|
||||
{
|
||||
// Concept check
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FinderConcept<
|
||||
FinderT,
|
||||
BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
|
||||
));
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FormatterConcept<
|
||||
FormatterT,
|
||||
FinderT,BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
|
||||
));
|
||||
|
||||
detail::find_format_all_impl(
|
||||
Input,
|
||||
Finder,
|
||||
Formatter,
|
||||
Finder(::boost::begin(Input), ::boost::end(Input)));
|
||||
|
||||
}
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull the names to the boost namespace
|
||||
using algorithm::find_format_copy;
|
||||
using algorithm::find_format;
|
||||
using algorithm::find_format_all_copy;
|
||||
using algorithm::find_format_all;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_FIND_FORMAT_HPP
|
||||
@ -1,388 +0,0 @@
|
||||
// Boost string_algo library find_iterator.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2004.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_FIND_ITERATOR_HPP
|
||||
#define BOOST_STRING_FIND_ITERATOR_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/iterator/iterator_categories.hpp>
|
||||
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/range/iterator.hpp>
|
||||
#include <boost/range/as_literal.hpp>
|
||||
|
||||
#include <boost/algorithm/string/detail/find_iterator.hpp>
|
||||
|
||||
/*! \file
|
||||
Defines find iterator classes. Find iterator repeatedly applies a Finder
|
||||
to the specified input string to search for matches. Dereferencing
|
||||
the iterator yields the current match or a range between the last and the current
|
||||
match depending on the iterator used.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// find_iterator -----------------------------------------------//
|
||||
|
||||
//! find_iterator
|
||||
/*!
|
||||
Find iterator encapsulates a Finder and allows
|
||||
for incremental searching in a string.
|
||||
Each increment moves the iterator to the next match.
|
||||
|
||||
Find iterator is a readable forward traversal iterator.
|
||||
|
||||
Dereferencing the iterator yields an iterator_range delimiting
|
||||
the current match.
|
||||
*/
|
||||
template<typename IteratorT>
|
||||
class find_iterator :
|
||||
public iterator_facade<
|
||||
find_iterator<IteratorT>,
|
||||
const iterator_range<IteratorT>,
|
||||
forward_traversal_tag >,
|
||||
private detail::find_iterator_base<IteratorT>
|
||||
{
|
||||
private:
|
||||
// facade support
|
||||
friend class ::boost::iterator_core_access;
|
||||
|
||||
private:
|
||||
// typedefs
|
||||
|
||||
typedef detail::find_iterator_base<IteratorT> base_type;
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
base_type::input_iterator_type input_iterator_type;
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
base_type::match_type match_type;
|
||||
|
||||
public:
|
||||
//! Default constructor
|
||||
/*!
|
||||
Construct null iterator. All null iterators are equal.
|
||||
|
||||
\post eof()==true
|
||||
*/
|
||||
find_iterator() {}
|
||||
|
||||
//! Copy constructor
|
||||
/*!
|
||||
Construct a copy of the find_iterator
|
||||
*/
|
||||
find_iterator( const find_iterator& Other ) :
|
||||
base_type(Other),
|
||||
m_Match(Other.m_Match),
|
||||
m_End(Other.m_End) {}
|
||||
|
||||
//! Constructor
|
||||
/*!
|
||||
Construct new find_iterator for a given finder
|
||||
and a range.
|
||||
*/
|
||||
template<typename FinderT>
|
||||
find_iterator(
|
||||
IteratorT Begin,
|
||||
IteratorT End,
|
||||
FinderT Finder ) :
|
||||
detail::find_iterator_base<IteratorT>(Finder,0),
|
||||
m_Match(Begin,Begin),
|
||||
m_End(End)
|
||||
{
|
||||
increment();
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
/*!
|
||||
Construct new find_iterator for a given finder
|
||||
and a range.
|
||||
*/
|
||||
template<typename FinderT, typename RangeT>
|
||||
find_iterator(
|
||||
RangeT& Col,
|
||||
FinderT Finder ) :
|
||||
detail::find_iterator_base<IteratorT>(Finder,0)
|
||||
{
|
||||
iterator_range<BOOST_STRING_TYPENAME range_iterator<RangeT>::type> lit_col(::boost::as_literal(Col));
|
||||
m_Match=::boost::make_iterator_range(::boost::begin(lit_col), ::boost::begin(lit_col));
|
||||
m_End=::boost::end(lit_col);
|
||||
|
||||
increment();
|
||||
}
|
||||
|
||||
private:
|
||||
// iterator operations
|
||||
|
||||
// dereference
|
||||
const match_type& dereference() const
|
||||
{
|
||||
return m_Match;
|
||||
}
|
||||
|
||||
// increment
|
||||
void increment()
|
||||
{
|
||||
m_Match=this->do_find(m_Match.end(),m_End);
|
||||
}
|
||||
|
||||
// comparison
|
||||
bool equal( const find_iterator& Other ) const
|
||||
{
|
||||
bool bEof=eof();
|
||||
bool bOtherEof=Other.eof();
|
||||
|
||||
return bEof || bOtherEof ? bEof==bOtherEof :
|
||||
(
|
||||
m_Match==Other.m_Match &&
|
||||
m_End==Other.m_End
|
||||
);
|
||||
}
|
||||
|
||||
public:
|
||||
// operations
|
||||
|
||||
//! Eof check
|
||||
/*!
|
||||
Check the eof condition. Eof condition means that
|
||||
there is nothing more to be searched i.e. find_iterator
|
||||
is after the last match.
|
||||
*/
|
||||
bool eof() const
|
||||
{
|
||||
return
|
||||
this->is_null() ||
|
||||
(
|
||||
m_Match.begin() == m_End &&
|
||||
m_Match.end() == m_End
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
// Attributes
|
||||
match_type m_Match;
|
||||
input_iterator_type m_End;
|
||||
};
|
||||
|
||||
//! find iterator construction helper
|
||||
/*!
|
||||
* Construct a find iterator to iterate through the specified string
|
||||
*/
|
||||
template<typename RangeT, typename FinderT>
|
||||
inline find_iterator<
|
||||
BOOST_STRING_TYPENAME range_iterator<RangeT>::type>
|
||||
make_find_iterator(
|
||||
RangeT& Collection,
|
||||
FinderT Finder)
|
||||
{
|
||||
return find_iterator<BOOST_STRING_TYPENAME range_iterator<RangeT>::type>(
|
||||
Collection, Finder);
|
||||
}
|
||||
|
||||
// split iterator -----------------------------------------------//
|
||||
|
||||
//! split_iterator
|
||||
/*!
|
||||
Split iterator encapsulates a Finder and allows
|
||||
for incremental searching in a string.
|
||||
Unlike the find iterator, split iterator iterates
|
||||
through gaps between matches.
|
||||
|
||||
Find iterator is a readable forward traversal iterator.
|
||||
|
||||
Dereferencing the iterator yields an iterator_range delimiting
|
||||
the current match.
|
||||
*/
|
||||
template<typename IteratorT>
|
||||
class split_iterator :
|
||||
public iterator_facade<
|
||||
split_iterator<IteratorT>,
|
||||
const iterator_range<IteratorT>,
|
||||
forward_traversal_tag >,
|
||||
private detail::find_iterator_base<IteratorT>
|
||||
{
|
||||
private:
|
||||
// facade support
|
||||
friend class ::boost::iterator_core_access;
|
||||
|
||||
private:
|
||||
// typedefs
|
||||
|
||||
typedef detail::find_iterator_base<IteratorT> base_type;
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
base_type::input_iterator_type input_iterator_type;
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
base_type::match_type match_type;
|
||||
|
||||
public:
|
||||
//! Default constructor
|
||||
/*!
|
||||
Construct null iterator. All null iterators are equal.
|
||||
|
||||
\post eof()==true
|
||||
*/
|
||||
split_iterator() :
|
||||
m_Next(),
|
||||
m_End(),
|
||||
m_bEof(true)
|
||||
{}
|
||||
|
||||
//! Copy constructor
|
||||
/*!
|
||||
Construct a copy of the split_iterator
|
||||
*/
|
||||
split_iterator( const split_iterator& Other ) :
|
||||
base_type(Other),
|
||||
m_Match(Other.m_Match),
|
||||
m_Next(Other.m_Next),
|
||||
m_End(Other.m_End),
|
||||
m_bEof(Other.m_bEof)
|
||||
{}
|
||||
|
||||
//! Constructor
|
||||
/*!
|
||||
Construct new split_iterator for a given finder
|
||||
and a range.
|
||||
*/
|
||||
template<typename FinderT>
|
||||
split_iterator(
|
||||
IteratorT Begin,
|
||||
IteratorT End,
|
||||
FinderT Finder ) :
|
||||
detail::find_iterator_base<IteratorT>(Finder,0),
|
||||
m_Match(Begin,Begin),
|
||||
m_Next(Begin),
|
||||
m_End(End),
|
||||
m_bEof(false)
|
||||
{
|
||||
// force the correct behavior for empty sequences and yield at least one token
|
||||
if(Begin!=End)
|
||||
{
|
||||
increment();
|
||||
}
|
||||
}
|
||||
//! Constructor
|
||||
/*!
|
||||
Construct new split_iterator for a given finder
|
||||
and a collection.
|
||||
*/
|
||||
template<typename FinderT, typename RangeT>
|
||||
split_iterator(
|
||||
RangeT& Col,
|
||||
FinderT Finder ) :
|
||||
detail::find_iterator_base<IteratorT>(Finder,0),
|
||||
m_bEof(false)
|
||||
{
|
||||
iterator_range<BOOST_STRING_TYPENAME range_iterator<RangeT>::type> lit_col(::boost::as_literal(Col));
|
||||
m_Match=make_iterator_range(::boost::begin(lit_col), ::boost::begin(lit_col));
|
||||
m_Next=::boost::begin(lit_col);
|
||||
m_End=::boost::end(lit_col);
|
||||
|
||||
// force the correct behavior for empty sequences and yield at least one token
|
||||
if(m_Next!=m_End)
|
||||
{
|
||||
increment();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// iterator operations
|
||||
|
||||
// dereference
|
||||
const match_type& dereference() const
|
||||
{
|
||||
return m_Match;
|
||||
}
|
||||
|
||||
// increment
|
||||
void increment()
|
||||
{
|
||||
match_type FindMatch=this->do_find( m_Next, m_End );
|
||||
|
||||
if(FindMatch.begin()==m_End && FindMatch.end()==m_End)
|
||||
{
|
||||
if(m_Match.end()==m_End)
|
||||
{
|
||||
// Mark iterator as eof
|
||||
m_bEof=true;
|
||||
}
|
||||
}
|
||||
|
||||
m_Match=match_type( m_Next, FindMatch.begin() );
|
||||
m_Next=FindMatch.end();
|
||||
}
|
||||
|
||||
// comparison
|
||||
bool equal( const split_iterator& Other ) const
|
||||
{
|
||||
bool bEof=eof();
|
||||
bool bOtherEof=Other.eof();
|
||||
|
||||
return bEof || bOtherEof ? bEof==bOtherEof :
|
||||
(
|
||||
m_Match==Other.m_Match &&
|
||||
m_Next==Other.m_Next &&
|
||||
m_End==Other.m_End
|
||||
);
|
||||
}
|
||||
|
||||
public:
|
||||
// operations
|
||||
|
||||
//! Eof check
|
||||
/*!
|
||||
Check the eof condition. Eof condition means that
|
||||
there is nothing more to be searched i.e. find_iterator
|
||||
is after the last match.
|
||||
*/
|
||||
bool eof() const
|
||||
{
|
||||
return this->is_null() || m_bEof;
|
||||
}
|
||||
|
||||
private:
|
||||
// Attributes
|
||||
match_type m_Match;
|
||||
input_iterator_type m_Next;
|
||||
input_iterator_type m_End;
|
||||
bool m_bEof;
|
||||
};
|
||||
|
||||
//! split iterator construction helper
|
||||
/*!
|
||||
* Construct a split iterator to iterate through the specified collection
|
||||
*/
|
||||
template<typename RangeT, typename FinderT>
|
||||
inline split_iterator<
|
||||
BOOST_STRING_TYPENAME range_iterator<RangeT>::type>
|
||||
make_split_iterator(
|
||||
RangeT& Collection,
|
||||
FinderT Finder)
|
||||
{
|
||||
return split_iterator<BOOST_STRING_TYPENAME range_iterator<RangeT>::type>(
|
||||
Collection, Finder);
|
||||
}
|
||||
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull names to the boost namespace
|
||||
using algorithm::find_iterator;
|
||||
using algorithm::make_find_iterator;
|
||||
using algorithm::split_iterator;
|
||||
using algorithm::make_split_iterator;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_FIND_ITERATOR_HPP
|
||||
@ -1,266 +0,0 @@
|
||||
// Boost string_algo library finder.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2006.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_FINDER_HPP
|
||||
#define BOOST_STRING_FINDER_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/range/iterator.hpp>
|
||||
#include <boost/range/const_iterator.hpp>
|
||||
|
||||
#include <boost/algorithm/string/constants.hpp>
|
||||
#include <boost/algorithm/string/detail/finder.hpp>
|
||||
#include <boost/algorithm/string/compare.hpp>
|
||||
|
||||
/*! \file
|
||||
Defines Finder generators. Finder object is a functor which is able to
|
||||
find a substring matching a specific criteria in the input.
|
||||
Finders are used as a pluggable components for replace, find
|
||||
and split facilities. This header contains generator functions
|
||||
for finders provided in this library.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// Finder generators ------------------------------------------//
|
||||
|
||||
//! "First" finder
|
||||
/*!
|
||||
Construct the \c first_finder. The finder searches for the first
|
||||
occurrence of the string in a given input.
|
||||
The result is given as an \c iterator_range delimiting the match.
|
||||
|
||||
\param Search A substring to be searched for.
|
||||
\return An instance of the \c first_finder object
|
||||
*/
|
||||
template<typename RangeT>
|
||||
inline detail::first_finderF<
|
||||
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type,
|
||||
is_equal>
|
||||
first_finder( const RangeT& Search )
|
||||
{
|
||||
return
|
||||
detail::first_finderF<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_const_iterator<RangeT>::type,
|
||||
is_equal>( ::boost::as_literal(Search), is_equal() ) ;
|
||||
}
|
||||
|
||||
//! "First" finder
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename RangeT,typename PredicateT>
|
||||
inline detail::first_finderF<
|
||||
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type,
|
||||
PredicateT>
|
||||
first_finder(
|
||||
const RangeT& Search, PredicateT Comp )
|
||||
{
|
||||
return
|
||||
detail::first_finderF<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_const_iterator<RangeT>::type,
|
||||
PredicateT>( ::boost::as_literal(Search), Comp );
|
||||
}
|
||||
|
||||
//! "Last" finder
|
||||
/*!
|
||||
Construct the \c last_finder. The finder searches for the last
|
||||
occurrence of the string in a given input.
|
||||
The result is given as an \c iterator_range delimiting the match.
|
||||
|
||||
\param Search A substring to be searched for.
|
||||
\return An instance of the \c last_finder object
|
||||
*/
|
||||
template<typename RangeT>
|
||||
inline detail::last_finderF<
|
||||
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type,
|
||||
is_equal>
|
||||
last_finder( const RangeT& Search )
|
||||
{
|
||||
return
|
||||
detail::last_finderF<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_const_iterator<RangeT>::type,
|
||||
is_equal>( ::boost::as_literal(Search), is_equal() );
|
||||
}
|
||||
//! "Last" finder
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename RangeT, typename PredicateT>
|
||||
inline detail::last_finderF<
|
||||
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type,
|
||||
PredicateT>
|
||||
last_finder( const RangeT& Search, PredicateT Comp )
|
||||
{
|
||||
return
|
||||
detail::last_finderF<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_const_iterator<RangeT>::type,
|
||||
PredicateT>( ::boost::as_literal(Search), Comp ) ;
|
||||
}
|
||||
|
||||
//! "Nth" finder
|
||||
/*!
|
||||
Construct the \c nth_finder. The finder searches for the n-th (zero-indexed)
|
||||
occurrence of the string in a given input.
|
||||
The result is given as an \c iterator_range delimiting the match.
|
||||
|
||||
\param Search A substring to be searched for.
|
||||
\param Nth An index of the match to be find
|
||||
\return An instance of the \c nth_finder object
|
||||
*/
|
||||
template<typename RangeT>
|
||||
inline detail::nth_finderF<
|
||||
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type,
|
||||
is_equal>
|
||||
nth_finder(
|
||||
const RangeT& Search,
|
||||
int Nth)
|
||||
{
|
||||
return
|
||||
detail::nth_finderF<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_const_iterator<RangeT>::type,
|
||||
is_equal>( ::boost::as_literal(Search), Nth, is_equal() ) ;
|
||||
}
|
||||
//! "Nth" finder
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename RangeT, typename PredicateT>
|
||||
inline detail::nth_finderF<
|
||||
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type,
|
||||
PredicateT>
|
||||
nth_finder(
|
||||
const RangeT& Search,
|
||||
int Nth,
|
||||
PredicateT Comp )
|
||||
{
|
||||
return
|
||||
detail::nth_finderF<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_const_iterator<RangeT>::type,
|
||||
PredicateT>( ::boost::as_literal(Search), Nth, Comp );
|
||||
}
|
||||
|
||||
//! "Head" finder
|
||||
/*!
|
||||
Construct the \c head_finder. The finder returns a head of a given
|
||||
input. The head is a prefix of a string up to n elements in
|
||||
size. If an input has less then n elements, whole input is
|
||||
considered a head.
|
||||
The result is given as an \c iterator_range delimiting the match.
|
||||
|
||||
\param N The size of the head
|
||||
\return An instance of the \c head_finder object
|
||||
*/
|
||||
inline detail::head_finderF
|
||||
head_finder( int N )
|
||||
{
|
||||
return detail::head_finderF(N);
|
||||
}
|
||||
|
||||
//! "Tail" finder
|
||||
/*!
|
||||
Construct the \c tail_finder. The finder returns a tail of a given
|
||||
input. The tail is a suffix of a string up to n elements in
|
||||
size. If an input has less then n elements, whole input is
|
||||
considered a head.
|
||||
The result is given as an \c iterator_range delimiting the match.
|
||||
|
||||
\param N The size of the head
|
||||
\return An instance of the \c tail_finder object
|
||||
*/
|
||||
inline detail::tail_finderF
|
||||
tail_finder( int N )
|
||||
{
|
||||
return detail::tail_finderF(N);
|
||||
}
|
||||
|
||||
//! "Token" finder
|
||||
/*!
|
||||
Construct the \c token_finder. The finder searches for a token
|
||||
specified by a predicate. It is similar to std::find_if
|
||||
algorithm, with an exception that it return a range of
|
||||
instead of a single iterator.
|
||||
|
||||
If "compress token mode" is enabled, adjacent matching tokens are
|
||||
concatenated into one match. Thus the finder can be used to
|
||||
search for continuous segments of characters satisfying the
|
||||
given predicate.
|
||||
|
||||
The result is given as an \c iterator_range delimiting the match.
|
||||
|
||||
\param Pred An element selection predicate
|
||||
\param eCompress Compress flag
|
||||
\return An instance of the \c token_finder object
|
||||
*/
|
||||
template< typename PredicateT >
|
||||
inline detail::token_finderF<PredicateT>
|
||||
token_finder(
|
||||
PredicateT Pred,
|
||||
token_compress_mode_type eCompress=token_compress_off )
|
||||
{
|
||||
return detail::token_finderF<PredicateT>( Pred, eCompress );
|
||||
}
|
||||
|
||||
//! "Range" finder
|
||||
/*!
|
||||
Construct the \c range_finder. The finder does not perform
|
||||
any operation. It simply returns the given range for
|
||||
any input.
|
||||
|
||||
\param Begin Beginning of the range
|
||||
\param End End of the range
|
||||
\return An instance of the \c range_finger object
|
||||
*/
|
||||
template< typename ForwardIteratorT >
|
||||
inline detail::range_finderF<ForwardIteratorT>
|
||||
range_finder(
|
||||
ForwardIteratorT Begin,
|
||||
ForwardIteratorT End )
|
||||
{
|
||||
return detail::range_finderF<ForwardIteratorT>( Begin, End );
|
||||
}
|
||||
|
||||
//! "Range" finder
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template< typename ForwardIteratorT >
|
||||
inline detail::range_finderF<ForwardIteratorT>
|
||||
range_finder( iterator_range<ForwardIteratorT> Range )
|
||||
{
|
||||
return detail::range_finderF<ForwardIteratorT>( Range );
|
||||
}
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull the names to the boost namespace
|
||||
using algorithm::first_finder;
|
||||
using algorithm::last_finder;
|
||||
using algorithm::nth_finder;
|
||||
using algorithm::head_finder;
|
||||
using algorithm::tail_finder;
|
||||
using algorithm::token_finder;
|
||||
using algorithm::range_finder;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_FINDER_HPP
|
||||
@ -1,120 +0,0 @@
|
||||
// Boost string_algo library formatter.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_FORMATTER_HPP
|
||||
#define BOOST_STRING_FORMATTER_HPP
|
||||
|
||||
#include <boost/detail/iterator.hpp>
|
||||
#include <boost/range/value_type.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/as_literal.hpp>
|
||||
|
||||
#include <boost/algorithm/string/detail/formatter.hpp>
|
||||
|
||||
/*! \file
|
||||
Defines Formatter generators. Formatter is a functor which formats
|
||||
a string according to given parameters. A Formatter works
|
||||
in conjunction with a Finder. A Finder can provide additional information
|
||||
for a specific Formatter. An example of such a cooperation is regex_finder
|
||||
and regex_formatter.
|
||||
|
||||
Formatters are used as pluggable components for replace facilities.
|
||||
This header contains generator functions for the Formatters provided in this library.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// generic formatters ---------------------------------------------------------------//
|
||||
|
||||
//! Constant formatter
|
||||
/*!
|
||||
Constructs a \c const_formatter. Const formatter always returns
|
||||
the same value, regardless of the parameter.
|
||||
|
||||
\param Format A predefined value used as a result for formatting
|
||||
\return An instance of the \c const_formatter object.
|
||||
*/
|
||||
template<typename RangeT>
|
||||
inline detail::const_formatF<
|
||||
iterator_range<
|
||||
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> >
|
||||
const_formatter(const RangeT& Format)
|
||||
{
|
||||
return detail::const_formatF<
|
||||
iterator_range<
|
||||
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> >(::boost::as_literal(Format));
|
||||
}
|
||||
|
||||
//! Identity formatter
|
||||
/*!
|
||||
Constructs an \c identity_formatter. Identity formatter always returns
|
||||
the parameter.
|
||||
|
||||
\return An instance of the \c identity_formatter object.
|
||||
*/
|
||||
template<typename RangeT>
|
||||
inline detail::identity_formatF<
|
||||
iterator_range<
|
||||
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> >
|
||||
identity_formatter()
|
||||
{
|
||||
return detail::identity_formatF<
|
||||
iterator_range<
|
||||
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> >();
|
||||
}
|
||||
|
||||
//! Empty formatter
|
||||
/*!
|
||||
Constructs an \c empty_formatter. Empty formatter always returns an empty
|
||||
sequence.
|
||||
|
||||
\param Input container used to select a correct value_type for the
|
||||
resulting empty_container<>.
|
||||
\return An instance of the \c empty_formatter object.
|
||||
*/
|
||||
template<typename RangeT>
|
||||
inline detail::empty_formatF<
|
||||
BOOST_STRING_TYPENAME range_value<RangeT>::type>
|
||||
empty_formatter(const RangeT&)
|
||||
{
|
||||
return detail::empty_formatF<
|
||||
BOOST_STRING_TYPENAME range_value<RangeT>::type>();
|
||||
}
|
||||
|
||||
//! Empty formatter
|
||||
/*!
|
||||
Constructs a \c dissect_formatter. Dissect formatter uses a specified finder
|
||||
to extract a portion of the formatted sequence. The first finder's match is returned
|
||||
as a result
|
||||
|
||||
\param Finder a finder used to select a portion of the formatted sequence
|
||||
\return An instance of the \c dissect_formatter object.
|
||||
*/
|
||||
template<typename FinderT>
|
||||
inline detail::dissect_formatF< FinderT >
|
||||
dissect_formatter(const FinderT& Finder)
|
||||
{
|
||||
return detail::dissect_formatF<FinderT>(Finder);
|
||||
}
|
||||
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull the names to the boost namespace
|
||||
using algorithm::const_formatter;
|
||||
using algorithm::identity_formatter;
|
||||
using algorithm::empty_formatter;
|
||||
using algorithm::dissect_formatter;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_FORMATTER_HPP
|
||||
@ -1,193 +0,0 @@
|
||||
// Boost string_algo library iter_find.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_ITER_FIND_HPP
|
||||
#define BOOST_STRING_ITER_FIND_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/range/iterator.hpp>
|
||||
#include <boost/range/value_type.hpp>
|
||||
#include <boost/range/as_literal.hpp>
|
||||
|
||||
#include <boost/algorithm/string/concept.hpp>
|
||||
#include <boost/algorithm/string/find_iterator.hpp>
|
||||
#include <boost/algorithm/string/detail/util.hpp>
|
||||
|
||||
/*! \file
|
||||
Defines generic split algorithms. Split algorithms can be
|
||||
used to divide a sequence into several part according
|
||||
to a given criteria. Result is given as a 'container
|
||||
of containers' where elements are copies or references
|
||||
to extracted parts.
|
||||
|
||||
There are two algorithms provided. One iterates over matching
|
||||
substrings, the other one over the gaps between these matches.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// iterate find ---------------------------------------------------//
|
||||
|
||||
//! Iter find algorithm
|
||||
/*!
|
||||
This algorithm executes a given finder in iteration on the input,
|
||||
until the end of input is reached, or no match is found.
|
||||
Iteration is done using built-in find_iterator, so the real
|
||||
searching is performed only when needed.
|
||||
In each iteration new match is found and added to the result.
|
||||
|
||||
\param Result A 'container container' to contain the result of search.
|
||||
Both outer and inner container must have constructor taking a pair
|
||||
of iterators as an argument.
|
||||
Typical type of the result is
|
||||
\c std::vector<boost::iterator_range<iterator>>
|
||||
(each element of such a vector will container a range delimiting
|
||||
a match).
|
||||
\param Input A container which will be searched.
|
||||
\param Finder A Finder object used for searching
|
||||
\return A reference to the result
|
||||
|
||||
\note Prior content of the result will be overwritten.
|
||||
*/
|
||||
template<
|
||||
typename SequenceSequenceT,
|
||||
typename RangeT,
|
||||
typename FinderT >
|
||||
inline SequenceSequenceT&
|
||||
iter_find(
|
||||
SequenceSequenceT& Result,
|
||||
RangeT& Input,
|
||||
FinderT Finder )
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FinderConcept<
|
||||
FinderT,
|
||||
BOOST_STRING_TYPENAME range_iterator<RangeT>::type>
|
||||
));
|
||||
|
||||
iterator_range<BOOST_STRING_TYPENAME range_iterator<RangeT>::type> lit_input(::boost::as_literal(Input));
|
||||
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
range_iterator<RangeT>::type input_iterator_type;
|
||||
typedef find_iterator<input_iterator_type> find_iterator_type;
|
||||
typedef detail::copy_iterator_rangeF<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_value<SequenceSequenceT>::type,
|
||||
input_iterator_type> copy_range_type;
|
||||
|
||||
input_iterator_type InputEnd=::boost::end(lit_input);
|
||||
|
||||
typedef transform_iterator<copy_range_type, find_iterator_type>
|
||||
transform_iter_type;
|
||||
|
||||
transform_iter_type itBegin=
|
||||
::boost::make_transform_iterator(
|
||||
find_iterator_type( ::boost::begin(lit_input), InputEnd, Finder ),
|
||||
copy_range_type());
|
||||
|
||||
transform_iter_type itEnd=
|
||||
::boost::make_transform_iterator(
|
||||
find_iterator_type(),
|
||||
copy_range_type());
|
||||
|
||||
SequenceSequenceT Tmp(itBegin, itEnd);
|
||||
|
||||
Result.swap(Tmp);
|
||||
return Result;
|
||||
}
|
||||
|
||||
// iterate split ---------------------------------------------------//
|
||||
|
||||
//! Split find algorithm
|
||||
/*!
|
||||
This algorithm executes a given finder in iteration on the input,
|
||||
until the end of input is reached, or no match is found.
|
||||
Iteration is done using built-in find_iterator, so the real
|
||||
searching is performed only when needed.
|
||||
Each match is used as a separator of segments. These segments are then
|
||||
returned in the result.
|
||||
|
||||
\param Result A 'container container' to contain the result of search.
|
||||
Both outer and inner container must have constructor taking a pair
|
||||
of iterators as an argument.
|
||||
Typical type of the result is
|
||||
\c std::vector<boost::iterator_range<iterator>>
|
||||
(each element of such a vector will container a range delimiting
|
||||
a match).
|
||||
\param Input A container which will be searched.
|
||||
\param Finder A finder object used for searching
|
||||
\return A reference to the result
|
||||
|
||||
\note Prior content of the result will be overwritten.
|
||||
*/
|
||||
template<
|
||||
typename SequenceSequenceT,
|
||||
typename RangeT,
|
||||
typename FinderT >
|
||||
inline SequenceSequenceT&
|
||||
iter_split(
|
||||
SequenceSequenceT& Result,
|
||||
RangeT& Input,
|
||||
FinderT Finder )
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT((
|
||||
FinderConcept<FinderT,
|
||||
BOOST_STRING_TYPENAME range_iterator<RangeT>::type>
|
||||
));
|
||||
|
||||
iterator_range<BOOST_STRING_TYPENAME range_iterator<RangeT>::type> lit_input(::boost::as_literal(Input));
|
||||
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
range_iterator<RangeT>::type input_iterator_type;
|
||||
typedef split_iterator<input_iterator_type> find_iterator_type;
|
||||
typedef detail::copy_iterator_rangeF<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_value<SequenceSequenceT>::type,
|
||||
input_iterator_type> copy_range_type;
|
||||
|
||||
input_iterator_type InputEnd=::boost::end(lit_input);
|
||||
|
||||
typedef transform_iterator<copy_range_type, find_iterator_type>
|
||||
transform_iter_type;
|
||||
|
||||
transform_iter_type itBegin=
|
||||
::boost::make_transform_iterator(
|
||||
find_iterator_type( ::boost::begin(lit_input), InputEnd, Finder ),
|
||||
copy_range_type() );
|
||||
|
||||
transform_iter_type itEnd=
|
||||
::boost::make_transform_iterator(
|
||||
find_iterator_type(),
|
||||
copy_range_type() );
|
||||
|
||||
SequenceSequenceT Tmp(itBegin, itEnd);
|
||||
|
||||
Result.swap(Tmp);
|
||||
return Result;
|
||||
}
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull names to the boost namespace
|
||||
using algorithm::iter_find;
|
||||
using algorithm::iter_split;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_ITER_FIND_HPP
|
||||
@ -1,145 +0,0 @@
|
||||
// Boost string_algo library join.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2006.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_JOIN_HPP
|
||||
#define BOOST_STRING_JOIN_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <boost/algorithm/string/detail/sequence.hpp>
|
||||
#include <boost/range/value_type.hpp>
|
||||
#include <boost/range/as_literal.hpp>
|
||||
|
||||
/*! \file
|
||||
Defines join algorithm.
|
||||
|
||||
Join algorithm is a counterpart to split algorithms.
|
||||
It joins strings from a 'list' by adding user defined separator.
|
||||
Additionally there is a version that allows simple filtering
|
||||
by providing a predicate.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// join --------------------------------------------------------------//
|
||||
|
||||
//! Join algorithm
|
||||
/*!
|
||||
This algorithm joins all strings in a 'list' into one long string.
|
||||
Segments are concatenated by given separator.
|
||||
|
||||
\param Input A container that holds the input strings. It must be a container-of-containers.
|
||||
\param Separator A string that will separate the joined segments.
|
||||
\return Concatenated string.
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template< typename SequenceSequenceT, typename Range1T>
|
||||
inline typename range_value<SequenceSequenceT>::type
|
||||
join(
|
||||
const SequenceSequenceT& Input,
|
||||
const Range1T& Separator)
|
||||
{
|
||||
// Define working types
|
||||
typedef typename range_value<SequenceSequenceT>::type ResultT;
|
||||
typedef typename range_const_iterator<SequenceSequenceT>::type InputIteratorT;
|
||||
|
||||
// Parse input
|
||||
InputIteratorT itBegin=::boost::begin(Input);
|
||||
InputIteratorT itEnd=::boost::end(Input);
|
||||
|
||||
// Construct container to hold the result
|
||||
ResultT Result;
|
||||
|
||||
// Append first element
|
||||
if(itBegin!=itEnd)
|
||||
{
|
||||
detail::insert(Result, ::boost::end(Result), *itBegin);
|
||||
++itBegin;
|
||||
}
|
||||
|
||||
for(;itBegin!=itEnd; ++itBegin)
|
||||
{
|
||||
// Add separator
|
||||
detail::insert(Result, ::boost::end(Result), ::boost::as_literal(Separator));
|
||||
// Add element
|
||||
detail::insert(Result, ::boost::end(Result), *itBegin);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
// join_if ----------------------------------------------------------//
|
||||
|
||||
//! Conditional join algorithm
|
||||
/*!
|
||||
This algorithm joins all strings in a 'list' into one long string.
|
||||
Segments are concatenated by given separator. Only segments that
|
||||
satisfy the predicate will be added to the result.
|
||||
|
||||
\param Input A container that holds the input strings. It must be a container-of-containers.
|
||||
\param Separator A string that will separate the joined segments.
|
||||
\param Pred A segment selection predicate
|
||||
\return Concatenated string.
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template< typename SequenceSequenceT, typename Range1T, typename PredicateT>
|
||||
inline typename range_value<SequenceSequenceT>::type
|
||||
join_if(
|
||||
const SequenceSequenceT& Input,
|
||||
const Range1T& Separator,
|
||||
PredicateT Pred)
|
||||
{
|
||||
// Define working types
|
||||
typedef typename range_value<SequenceSequenceT>::type ResultT;
|
||||
typedef typename range_const_iterator<SequenceSequenceT>::type InputIteratorT;
|
||||
|
||||
// Parse input
|
||||
InputIteratorT itBegin=::boost::begin(Input);
|
||||
InputIteratorT itEnd=::boost::end(Input);
|
||||
|
||||
// Construct container to hold the result
|
||||
ResultT Result;
|
||||
|
||||
// Roll to the first element that will be added
|
||||
while(itBegin!=itEnd && !Pred(*itBegin)) ++itBegin;
|
||||
// Add this element
|
||||
if(itBegin!=itEnd)
|
||||
{
|
||||
detail::insert(Result, ::boost::end(Result), *itBegin);
|
||||
++itBegin;
|
||||
}
|
||||
|
||||
for(;itBegin!=itEnd; ++itBegin)
|
||||
{
|
||||
if(Pred(*itBegin))
|
||||
{
|
||||
// Add separator
|
||||
detail::insert(Result, ::boost::end(Result), ::boost::as_literal(Separator));
|
||||
// Add element
|
||||
detail::insert(Result, ::boost::end(Result), *itBegin);
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull names to the boost namespace
|
||||
using algorithm::join;
|
||||
using algorithm::join_if;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_JOIN_HPP
|
||||
|
||||
@ -1,475 +0,0 @@
|
||||
// Boost string_algo library predicate.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_PREDICATE_HPP
|
||||
#define BOOST_STRING_PREDICATE_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/range/iterator.hpp>
|
||||
#include <boost/range/const_iterator.hpp>
|
||||
#include <boost/range/as_literal.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
|
||||
#include <boost/algorithm/string/compare.hpp>
|
||||
#include <boost/algorithm/string/find.hpp>
|
||||
#include <boost/algorithm/string/detail/predicate.hpp>
|
||||
|
||||
/*! \file boost/algorithm/string/predicate.hpp
|
||||
Defines string-related predicates.
|
||||
The predicates determine whether a substring is contained in the input string
|
||||
under various conditions: a string starts with the substring, ends with the
|
||||
substring, simply contains the substring or if both strings are equal.
|
||||
Additionaly the algorithm \c all() checks all elements of a container to satisfy a
|
||||
condition.
|
||||
|
||||
All predicates provide the strong exception guarantee.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// starts_with predicate -----------------------------------------------//
|
||||
|
||||
//! 'Starts with' predicate
|
||||
/*!
|
||||
This predicate holds when the test string is a prefix of the Input.
|
||||
In other words, if the input starts with the test.
|
||||
When the optional predicate is specified, it is used for character-wise
|
||||
comparison.
|
||||
|
||||
\param Input An input sequence
|
||||
\param Test A test sequence
|
||||
\param Comp An element comparison predicate
|
||||
\return The result of the test
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T, typename PredicateT>
|
||||
inline bool starts_with(
|
||||
const Range1T& Input,
|
||||
const Range2T& Test,
|
||||
PredicateT Comp)
|
||||
{
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range1T>::type> lit_input(::boost::as_literal(Input));
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range2T>::type> lit_test(::boost::as_literal(Test));
|
||||
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
range_const_iterator<Range1T>::type Iterator1T;
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
range_const_iterator<Range2T>::type Iterator2T;
|
||||
|
||||
Iterator1T InputEnd=::boost::end(lit_input);
|
||||
Iterator2T TestEnd=::boost::end(lit_test);
|
||||
|
||||
Iterator1T it=::boost::begin(lit_input);
|
||||
Iterator2T pit=::boost::begin(lit_test);
|
||||
for(;
|
||||
it!=InputEnd && pit!=TestEnd;
|
||||
++it,++pit)
|
||||
{
|
||||
if( !(Comp(*it,*pit)) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return pit==TestEnd;
|
||||
}
|
||||
|
||||
//! 'Starts with' predicate
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline bool starts_with(
|
||||
const Range1T& Input,
|
||||
const Range2T& Test)
|
||||
{
|
||||
return ::boost::algorithm::starts_with(Input, Test, is_equal());
|
||||
}
|
||||
|
||||
//! 'Starts with' predicate ( case insensitive )
|
||||
/*!
|
||||
This predicate holds when the test string is a prefix of the Input.
|
||||
In other words, if the input starts with the test.
|
||||
Elements are compared case insensitively.
|
||||
|
||||
\param Input An input sequence
|
||||
\param Test A test sequence
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return The result of the test
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline bool istarts_with(
|
||||
const Range1T& Input,
|
||||
const Range2T& Test,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
return ::boost::algorithm::starts_with(Input, Test, is_iequal(Loc));
|
||||
}
|
||||
|
||||
|
||||
// ends_with predicate -----------------------------------------------//
|
||||
|
||||
//! 'Ends with' predicate
|
||||
/*!
|
||||
This predicate holds when the test string is a suffix of the Input.
|
||||
In other words, if the input ends with the test.
|
||||
When the optional predicate is specified, it is used for character-wise
|
||||
comparison.
|
||||
|
||||
|
||||
\param Input An input sequence
|
||||
\param Test A test sequence
|
||||
\param Comp An element comparison predicate
|
||||
\return The result of the test
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T, typename PredicateT>
|
||||
inline bool ends_with(
|
||||
const Range1T& Input,
|
||||
const Range2T& Test,
|
||||
PredicateT Comp)
|
||||
{
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range1T>::type> lit_input(::boost::as_literal(Input));
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range2T>::type> lit_test(::boost::as_literal(Test));
|
||||
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
range_const_iterator<Range1T>::type Iterator1T;
|
||||
typedef BOOST_STRING_TYPENAME boost::detail::
|
||||
iterator_traits<Iterator1T>::iterator_category category;
|
||||
|
||||
return detail::
|
||||
ends_with_iter_select(
|
||||
::boost::begin(lit_input),
|
||||
::boost::end(lit_input),
|
||||
::boost::begin(lit_test),
|
||||
::boost::end(lit_test),
|
||||
Comp,
|
||||
category());
|
||||
}
|
||||
|
||||
|
||||
//! 'Ends with' predicate
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline bool ends_with(
|
||||
const Range1T& Input,
|
||||
const Range2T& Test)
|
||||
{
|
||||
return ::boost::algorithm::ends_with(Input, Test, is_equal());
|
||||
}
|
||||
|
||||
//! 'Ends with' predicate ( case insensitive )
|
||||
/*!
|
||||
This predicate holds when the test container is a suffix of the Input.
|
||||
In other words, if the input ends with the test.
|
||||
Elements are compared case insensitively.
|
||||
|
||||
\param Input An input sequence
|
||||
\param Test A test sequence
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return The result of the test
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline bool iends_with(
|
||||
const Range1T& Input,
|
||||
const Range2T& Test,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
return ::boost::algorithm::ends_with(Input, Test, is_iequal(Loc));
|
||||
}
|
||||
|
||||
// contains predicate -----------------------------------------------//
|
||||
|
||||
//! 'Contains' predicate
|
||||
/*!
|
||||
This predicate holds when the test container is contained in the Input.
|
||||
When the optional predicate is specified, it is used for character-wise
|
||||
comparison.
|
||||
|
||||
\param Input An input sequence
|
||||
\param Test A test sequence
|
||||
\param Comp An element comparison predicate
|
||||
\return The result of the test
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T, typename PredicateT>
|
||||
inline bool contains(
|
||||
const Range1T& Input,
|
||||
const Range2T& Test,
|
||||
PredicateT Comp)
|
||||
{
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range1T>::type> lit_input(::boost::as_literal(Input));
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range2T>::type> lit_test(::boost::as_literal(Test));
|
||||
|
||||
if (::boost::empty(lit_test))
|
||||
{
|
||||
// Empty range is contained always
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use the temporary variable to make VACPP happy
|
||||
bool bResult=(::boost::algorithm::first_finder(lit_test,Comp)(::boost::begin(lit_input), ::boost::end(lit_input)));
|
||||
return bResult;
|
||||
}
|
||||
|
||||
//! 'Contains' predicate
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline bool contains(
|
||||
const Range1T& Input,
|
||||
const Range2T& Test)
|
||||
{
|
||||
return ::boost::algorithm::contains(Input, Test, is_equal());
|
||||
}
|
||||
|
||||
//! 'Contains' predicate ( case insensitive )
|
||||
/*!
|
||||
This predicate holds when the test container is contained in the Input.
|
||||
Elements are compared case insensitively.
|
||||
|
||||
\param Input An input sequence
|
||||
\param Test A test sequence
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return The result of the test
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline bool icontains(
|
||||
const Range1T& Input,
|
||||
const Range2T& Test,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
return ::boost::algorithm::contains(Input, Test, is_iequal(Loc));
|
||||
}
|
||||
|
||||
// equals predicate -----------------------------------------------//
|
||||
|
||||
//! 'Equals' predicate
|
||||
/*!
|
||||
This predicate holds when the test container is equal to the
|
||||
input container i.e. all elements in both containers are same.
|
||||
When the optional predicate is specified, it is used for character-wise
|
||||
comparison.
|
||||
|
||||
\param Input An input sequence
|
||||
\param Test A test sequence
|
||||
\param Comp An element comparison predicate
|
||||
\return The result of the test
|
||||
|
||||
\note This is a two-way version of \c std::equal algorithm
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T, typename PredicateT>
|
||||
inline bool equals(
|
||||
const Range1T& Input,
|
||||
const Range2T& Test,
|
||||
PredicateT Comp)
|
||||
{
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range1T>::type> lit_input(::boost::as_literal(Input));
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range2T>::type> lit_test(::boost::as_literal(Test));
|
||||
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
range_const_iterator<Range1T>::type Iterator1T;
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
range_const_iterator<Range2T>::type Iterator2T;
|
||||
|
||||
Iterator1T InputEnd=::boost::end(lit_input);
|
||||
Iterator2T TestEnd=::boost::end(lit_test);
|
||||
|
||||
Iterator1T it=::boost::begin(lit_input);
|
||||
Iterator2T pit=::boost::begin(lit_test);
|
||||
for(;
|
||||
it!=InputEnd && pit!=TestEnd;
|
||||
++it,++pit)
|
||||
{
|
||||
if( !(Comp(*it,*pit)) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return (pit==TestEnd) && (it==InputEnd);
|
||||
}
|
||||
|
||||
//! 'Equals' predicate
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline bool equals(
|
||||
const Range1T& Input,
|
||||
const Range2T& Test)
|
||||
{
|
||||
return ::boost::algorithm::equals(Input, Test, is_equal());
|
||||
}
|
||||
|
||||
//! 'Equals' predicate ( case insensitive )
|
||||
/*!
|
||||
This predicate holds when the test container is equal to the
|
||||
input container i.e. all elements in both containers are same.
|
||||
Elements are compared case insensitively.
|
||||
|
||||
\param Input An input sequence
|
||||
\param Test A test sequence
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return The result of the test
|
||||
|
||||
\note This is a two-way version of \c std::equal algorithm
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline bool iequals(
|
||||
const Range1T& Input,
|
||||
const Range2T& Test,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
return ::boost::algorithm::equals(Input, Test, is_iequal(Loc));
|
||||
}
|
||||
|
||||
// lexicographical_compare predicate -----------------------------//
|
||||
|
||||
//! Lexicographical compare predicate
|
||||
/*!
|
||||
This predicate is an overload of std::lexicographical_compare
|
||||
for range arguments
|
||||
|
||||
It check whether the first argument is lexicographically less
|
||||
then the second one.
|
||||
|
||||
If the optional predicate is specified, it is used for character-wise
|
||||
comparison
|
||||
|
||||
\param Arg1 First argument
|
||||
\param Arg2 Second argument
|
||||
\param Pred Comparison predicate
|
||||
\return The result of the test
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T, typename PredicateT>
|
||||
inline bool lexicographical_compare(
|
||||
const Range1T& Arg1,
|
||||
const Range2T& Arg2,
|
||||
PredicateT Pred)
|
||||
{
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range1T>::type> lit_arg1(::boost::as_literal(Arg1));
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range2T>::type> lit_arg2(::boost::as_literal(Arg2));
|
||||
|
||||
return std::lexicographical_compare(
|
||||
::boost::begin(lit_arg1),
|
||||
::boost::end(lit_arg1),
|
||||
::boost::begin(lit_arg2),
|
||||
::boost::end(lit_arg2),
|
||||
Pred);
|
||||
}
|
||||
|
||||
//! Lexicographical compare predicate
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline bool lexicographical_compare(
|
||||
const Range1T& Arg1,
|
||||
const Range2T& Arg2)
|
||||
{
|
||||
return ::boost::algorithm::lexicographical_compare(Arg1, Arg2, is_less());
|
||||
}
|
||||
|
||||
//! Lexicographical compare predicate (case-insensitive)
|
||||
/*!
|
||||
This predicate is an overload of std::lexicographical_compare
|
||||
for range arguments.
|
||||
It check whether the first argument is lexicographically less
|
||||
then the second one.
|
||||
Elements are compared case insensitively
|
||||
|
||||
|
||||
\param Arg1 First argument
|
||||
\param Arg2 Second argument
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return The result of the test
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename Range1T, typename Range2T>
|
||||
inline bool ilexicographical_compare(
|
||||
const Range1T& Arg1,
|
||||
const Range2T& Arg2,
|
||||
const std::locale& Loc=std::locale())
|
||||
{
|
||||
return ::boost::algorithm::lexicographical_compare(Arg1, Arg2, is_iless(Loc));
|
||||
}
|
||||
|
||||
|
||||
// all predicate -----------------------------------------------//
|
||||
|
||||
//! 'All' predicate
|
||||
/*!
|
||||
This predicate holds it all its elements satisfy a given
|
||||
condition, represented by the predicate.
|
||||
|
||||
\param Input An input sequence
|
||||
\param Pred A predicate
|
||||
\return The result of the test
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<typename RangeT, typename PredicateT>
|
||||
inline bool all(
|
||||
const RangeT& Input,
|
||||
PredicateT Pred)
|
||||
{
|
||||
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> lit_input(::boost::as_literal(Input));
|
||||
|
||||
typedef BOOST_STRING_TYPENAME
|
||||
range_const_iterator<RangeT>::type Iterator1T;
|
||||
|
||||
Iterator1T InputEnd=::boost::end(lit_input);
|
||||
for( Iterator1T It=::boost::begin(lit_input); It!=InputEnd; ++It)
|
||||
{
|
||||
if (!Pred(*It))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull names to the boost namespace
|
||||
using algorithm::starts_with;
|
||||
using algorithm::istarts_with;
|
||||
using algorithm::ends_with;
|
||||
using algorithm::iends_with;
|
||||
using algorithm::contains;
|
||||
using algorithm::icontains;
|
||||
using algorithm::equals;
|
||||
using algorithm::iequals;
|
||||
using algorithm::all;
|
||||
using algorithm::lexicographical_compare;
|
||||
using algorithm::ilexicographical_compare;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_PREDICATE_HPP
|
||||
@ -1,42 +0,0 @@
|
||||
// Boost string_algo library predicate_facade.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_PREDICATE_FACADE_HPP
|
||||
#define BOOST_STRING_PREDICATE_FACADE_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
|
||||
/*
|
||||
\file boost/algorith/string/predicate_facade.hpp
|
||||
This file contains predicate_facade definition. This template class is used
|
||||
to identify classification predicates, so they can be combined using
|
||||
composition operators.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// predicate facade ------------------------------------------------------//
|
||||
|
||||
//! Predicate facade
|
||||
/*!
|
||||
This class allows to recognize classification
|
||||
predicates, so that they can be combined using
|
||||
composition operators.
|
||||
Every classification predicate must be derived from this class.
|
||||
*/
|
||||
template<typename Derived>
|
||||
struct predicate_facade {};
|
||||
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_CLASSIFICATION_DETAIL_HPP
|
||||
@ -1,926 +0,0 @@
|
||||
// Boost string_algo library replace.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2006.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_REPLACE_HPP
|
||||
#define BOOST_STRING_REPLACE_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/range/iterator.hpp>
|
||||
#include <boost/range/const_iterator.hpp>
|
||||
|
||||
#include <boost/algorithm/string/find_format.hpp>
|
||||
#include <boost/algorithm/string/finder.hpp>
|
||||
#include <boost/algorithm/string/formatter.hpp>
|
||||
#include <boost/algorithm/string/compare.hpp>
|
||||
|
||||
/*! \file
|
||||
Defines various replace algorithms. Each algorithm replaces
|
||||
part(s) of the input according to set of searching and replace criteria.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// replace_range --------------------------------------------------------------------//
|
||||
|
||||
//! Replace range algorithm
|
||||
/*!
|
||||
Replace the given range in the input string.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param SearchRange A range in the input to be substituted
|
||||
\param Format A substitute string
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T>
|
||||
inline OutputIteratorT replace_range_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const iterator_range<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_const_iterator<Range1T>::type>& SearchRange,
|
||||
const Range2T& Format)
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::range_finder(SearchRange),
|
||||
::boost::algorithm::const_formatter(Format));
|
||||
}
|
||||
|
||||
//! Replace range algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline SequenceT replace_range_copy(
|
||||
const SequenceT& Input,
|
||||
const iterator_range<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_const_iterator<SequenceT>::type>& SearchRange,
|
||||
const RangeT& Format)
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::range_finder(SearchRange),
|
||||
::boost::algorithm::const_formatter(Format));
|
||||
}
|
||||
|
||||
//! Replace range algorithm
|
||||
/*!
|
||||
Replace the given range in the input string.
|
||||
The input sequence is modified in-place.
|
||||
|
||||
\param Input An input string
|
||||
\param SearchRange A range in the input to be substituted
|
||||
\param Format A substitute string
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline void replace_range(
|
||||
SequenceT& Input,
|
||||
const iterator_range<
|
||||
BOOST_STRING_TYPENAME
|
||||
range_iterator<SequenceT>::type>& SearchRange,
|
||||
const RangeT& Format)
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::range_finder(SearchRange),
|
||||
::boost::algorithm::const_formatter(Format));
|
||||
}
|
||||
|
||||
// replace_first --------------------------------------------------------------------//
|
||||
|
||||
//! Replace first algorithm
|
||||
/*!
|
||||
Replace the first match of the search substring in the input
|
||||
with the format string.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Format A substitute string
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T,
|
||||
typename Range3T>
|
||||
inline OutputIteratorT replace_first_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search,
|
||||
const Range3T& Format)
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace first algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline SequenceT replace_first_copy(
|
||||
const SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
const Range2T& Format )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace first algorithm
|
||||
/*!
|
||||
replace the first match of the search substring in the input
|
||||
with the format string. The input sequence is modified in-place.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Format A substitute string
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline void replace_first(
|
||||
SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
const Range2T& Format )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
// replace_first ( case insensitive ) ---------------------------------------------//
|
||||
|
||||
//! Replace first algorithm ( case insensitive )
|
||||
/*!
|
||||
Replace the first match of the search substring in the input
|
||||
with the format string.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Format A substitute string
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T,
|
||||
typename Range3T>
|
||||
inline OutputIteratorT ireplace_first_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search,
|
||||
const Range3T& Format,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace first algorithm ( case insensitive )
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename Range2T, typename Range1T>
|
||||
inline SequenceT ireplace_first_copy(
|
||||
const SequenceT& Input,
|
||||
const Range2T& Search,
|
||||
const Range1T& Format,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace first algorithm ( case insensitive )
|
||||
/*!
|
||||
Replace the first match of the search substring in the input
|
||||
with the format string. Input sequence is modified in-place.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Format A substitute string
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline void ireplace_first(
|
||||
SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
const Range2T& Format,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
// replace_last --------------------------------------------------------------------//
|
||||
|
||||
//! Replace last algorithm
|
||||
/*!
|
||||
Replace the last match of the search string in the input
|
||||
with the format string.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Format A substitute string
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T,
|
||||
typename Range3T>
|
||||
inline OutputIteratorT replace_last_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search,
|
||||
const Range3T& Format )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::last_finder(Search),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace last algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline SequenceT replace_last_copy(
|
||||
const SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
const Range2T& Format )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::last_finder(Search),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace last algorithm
|
||||
/*!
|
||||
Replace the last match of the search string in the input
|
||||
with the format string. Input sequence is modified in-place.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Format A substitute string
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline void replace_last(
|
||||
SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
const Range2T& Format )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::last_finder(Search),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
// replace_last ( case insensitive ) -----------------------------------------------//
|
||||
|
||||
//! Replace last algorithm ( case insensitive )
|
||||
/*!
|
||||
Replace the last match of the search string in the input
|
||||
with the format string.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Format A substitute string
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T,
|
||||
typename Range3T>
|
||||
inline OutputIteratorT ireplace_last_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search,
|
||||
const Range3T& Format,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::last_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace last algorithm ( case insensitive )
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline SequenceT ireplace_last_copy(
|
||||
const SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
const Range2T& Format,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::last_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace last algorithm ( case insensitive )
|
||||
/*!
|
||||
Replace the last match of the search string in the input
|
||||
with the format string.The input sequence is modified in-place.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Format A substitute string
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline void ireplace_last(
|
||||
SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
const Range2T& Format,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::last_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
// replace_nth --------------------------------------------------------------------//
|
||||
|
||||
//! Replace nth algorithm
|
||||
/*!
|
||||
Replace an Nth (zero-indexed) match of the search string in the input
|
||||
with the format string.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Nth An index of the match to be replaced. The index is 0-based.
|
||||
For negative N, matches are counted from the end of string.
|
||||
\param Format A substitute string
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T,
|
||||
typename Range3T>
|
||||
inline OutputIteratorT replace_nth_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search,
|
||||
int Nth,
|
||||
const Range3T& Format )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::nth_finder(Search, Nth),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace nth algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline SequenceT replace_nth_copy(
|
||||
const SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
int Nth,
|
||||
const Range2T& Format )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::nth_finder(Search, Nth),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace nth algorithm
|
||||
/*!
|
||||
Replace an Nth (zero-indexed) match of the search string in the input
|
||||
with the format string. Input sequence is modified in-place.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Nth An index of the match to be replaced. The index is 0-based.
|
||||
For negative N, matches are counted from the end of string.
|
||||
\param Format A substitute string
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline void replace_nth(
|
||||
SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
int Nth,
|
||||
const Range2T& Format )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::nth_finder(Search, Nth),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
// replace_nth ( case insensitive ) -----------------------------------------------//
|
||||
|
||||
//! Replace nth algorithm ( case insensitive )
|
||||
/*!
|
||||
Replace an Nth (zero-indexed) match of the search string in the input
|
||||
with the format string.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Nth An index of the match to be replaced. The index is 0-based.
|
||||
For negative N, matches are counted from the end of string.
|
||||
\param Format A substitute string
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T,
|
||||
typename Range3T>
|
||||
inline OutputIteratorT ireplace_nth_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search,
|
||||
int Nth,
|
||||
const Range3T& Format,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc) ),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace nth algorithm ( case insensitive )
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline SequenceT ireplace_nth_copy(
|
||||
const SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
int Nth,
|
||||
const Range2T& Format,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace nth algorithm ( case insensitive )
|
||||
/*!
|
||||
Replace an Nth (zero-indexed) match of the search string in the input
|
||||
with the format string. Input sequence is modified in-place.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Nth An index of the match to be replaced. The index is 0-based.
|
||||
For negative N, matches are counted from the end of string.
|
||||
\param Format A substitute string
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline void ireplace_nth(
|
||||
SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
int Nth,
|
||||
const Range2T& Format,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
// replace_all --------------------------------------------------------------------//
|
||||
|
||||
//! Replace all algorithm
|
||||
/*!
|
||||
Replace all occurrences of the search string in the input
|
||||
with the format string.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Format A substitute string
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T,
|
||||
typename Range3T>
|
||||
inline OutputIteratorT replace_all_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search,
|
||||
const Range3T& Format )
|
||||
{
|
||||
return ::boost::algorithm::find_format_all_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace all algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline SequenceT replace_all_copy(
|
||||
const SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
const Range2T& Format )
|
||||
{
|
||||
return ::boost::algorithm::find_format_all_copy(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace all algorithm
|
||||
/*!
|
||||
Replace all occurrences of the search string in the input
|
||||
with the format string. The input sequence is modified in-place.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Format A substitute string
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline void replace_all(
|
||||
SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
const Range2T& Format )
|
||||
{
|
||||
::boost::algorithm::find_format_all(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
// replace_all ( case insensitive ) -----------------------------------------------//
|
||||
|
||||
//! Replace all algorithm ( case insensitive )
|
||||
/*!
|
||||
Replace all occurrences of the search string in the input
|
||||
with the format string.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Format A substitute string
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T,
|
||||
typename Range3T>
|
||||
inline OutputIteratorT ireplace_all_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
const Range2T& Search,
|
||||
const Range3T& Format,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_all_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace all algorithm ( case insensitive )
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline SequenceT ireplace_all_copy(
|
||||
const SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
const Range2T& Format,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::find_format_all_copy(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace all algorithm ( case insensitive )
|
||||
/*!
|
||||
Replace all occurrences of the search string in the input
|
||||
with the format string.The input sequence is modified in-place.
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Input An input string
|
||||
\param Search A substring to be searched for
|
||||
\param Format A substitute string
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
*/
|
||||
template<typename SequenceT, typename Range1T, typename Range2T>
|
||||
inline void ireplace_all(
|
||||
SequenceT& Input,
|
||||
const Range1T& Search,
|
||||
const Range2T& Format,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
::boost::algorithm::find_format_all(
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
// replace_head --------------------------------------------------------------------//
|
||||
|
||||
//! Replace head algorithm
|
||||
/*!
|
||||
Replace the head of the input with the given format string.
|
||||
The head is a prefix of a string of given size.
|
||||
If the sequence is shorter then required, whole string if
|
||||
considered to be the head.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param N Length of the head.
|
||||
For N>=0, at most N characters are extracted.
|
||||
For N<0, size(Input)-|N| characters are extracted.
|
||||
\param Format A substitute string
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T>
|
||||
inline OutputIteratorT replace_head_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
int N,
|
||||
const Range2T& Format )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::head_finder(N),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace head algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline SequenceT replace_head_copy(
|
||||
const SequenceT& Input,
|
||||
int N,
|
||||
const RangeT& Format )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::head_finder(N),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace head algorithm
|
||||
/*!
|
||||
Replace the head of the input with the given format string.
|
||||
The head is a prefix of a string of given size.
|
||||
If the sequence is shorter then required, the whole string is
|
||||
considered to be the head. The input sequence is modified in-place.
|
||||
|
||||
\param Input An input string
|
||||
\param N Length of the head.
|
||||
For N>=0, at most N characters are extracted.
|
||||
For N<0, size(Input)-|N| characters are extracted.
|
||||
\param Format A substitute string
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline void replace_head(
|
||||
SequenceT& Input,
|
||||
int N,
|
||||
const RangeT& Format )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::head_finder(N),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
// replace_tail --------------------------------------------------------------------//
|
||||
|
||||
//! Replace tail algorithm
|
||||
/*!
|
||||
Replace the tail of the input with the given format string.
|
||||
The tail is a suffix of a string of given size.
|
||||
If the sequence is shorter then required, whole string is
|
||||
considered to be the tail.
|
||||
The result is a modified copy of the input. It is returned as a sequence
|
||||
or copied to the output iterator.
|
||||
|
||||
\param Output An output iterator to which the result will be copied
|
||||
\param Input An input string
|
||||
\param N Length of the tail.
|
||||
For N>=0, at most N characters are extracted.
|
||||
For N<0, size(Input)-|N| characters are extracted.
|
||||
\param Format A substitute string
|
||||
\return An output iterator pointing just after the last inserted character or
|
||||
a modified copy of the input
|
||||
|
||||
\note The second variant of this function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template<
|
||||
typename OutputIteratorT,
|
||||
typename Range1T,
|
||||
typename Range2T>
|
||||
inline OutputIteratorT replace_tail_copy(
|
||||
OutputIteratorT Output,
|
||||
const Range1T& Input,
|
||||
int N,
|
||||
const Range2T& Format )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Output,
|
||||
Input,
|
||||
::boost::algorithm::tail_finder(N),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace tail algorithm
|
||||
/*!
|
||||
\overload
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline SequenceT replace_tail_copy(
|
||||
const SequenceT& Input,
|
||||
int N,
|
||||
const RangeT& Format )
|
||||
{
|
||||
return ::boost::algorithm::find_format_copy(
|
||||
Input,
|
||||
::boost::algorithm::tail_finder(N),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
//! Replace tail algorithm
|
||||
/*!
|
||||
Replace the tail of the input with the given format sequence.
|
||||
The tail is a suffix of a string of given size.
|
||||
If the sequence is shorter then required, the whole string is
|
||||
considered to be the tail. The input sequence is modified in-place.
|
||||
|
||||
\param Input An input string
|
||||
\param N Length of the tail.
|
||||
For N>=0, at most N characters are extracted.
|
||||
For N<0, size(Input)-|N| characters are extracted.
|
||||
\param Format A substitute string
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline void replace_tail(
|
||||
SequenceT& Input,
|
||||
int N,
|
||||
const RangeT& Format )
|
||||
{
|
||||
::boost::algorithm::find_format(
|
||||
Input,
|
||||
::boost::algorithm::tail_finder(N),
|
||||
::boost::algorithm::const_formatter(Format) );
|
||||
}
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull names to the boost namespace
|
||||
using algorithm::replace_range_copy;
|
||||
using algorithm::replace_range;
|
||||
using algorithm::replace_first_copy;
|
||||
using algorithm::replace_first;
|
||||
using algorithm::ireplace_first_copy;
|
||||
using algorithm::ireplace_first;
|
||||
using algorithm::replace_last_copy;
|
||||
using algorithm::replace_last;
|
||||
using algorithm::ireplace_last_copy;
|
||||
using algorithm::ireplace_last;
|
||||
using algorithm::replace_nth_copy;
|
||||
using algorithm::replace_nth;
|
||||
using algorithm::ireplace_nth_copy;
|
||||
using algorithm::ireplace_nth;
|
||||
using algorithm::replace_all_copy;
|
||||
using algorithm::replace_all;
|
||||
using algorithm::ireplace_all_copy;
|
||||
using algorithm::ireplace_all;
|
||||
using algorithm::replace_head_copy;
|
||||
using algorithm::replace_head;
|
||||
using algorithm::replace_tail_copy;
|
||||
using algorithm::replace_tail;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_REPLACE_HPP
|
||||
@ -1,120 +0,0 @@
|
||||
// Boost string_algo library sequence_traits.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_SEQUENCE_TRAITS_HPP
|
||||
#define BOOST_STRING_SEQUENCE_TRAITS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/algorithm/string/yes_no_type.hpp>
|
||||
|
||||
/*! \file
|
||||
Traits defined in this header are used by various algorithms to achieve
|
||||
better performance for specific containers.
|
||||
Traits provide fail-safe defaults. If a container supports some of these
|
||||
features, it is possible to specialize the specific trait for this container.
|
||||
For lacking compilers, it is possible of define an override for a specific tester
|
||||
function.
|
||||
|
||||
Due to a language restriction, it is not currently possible to define specializations for
|
||||
stl containers without including the corresponding header. To decrease the overhead
|
||||
needed by this inclusion, user can selectively include a specialization
|
||||
header for a specific container. They are located in boost/algorithm/string/stl
|
||||
directory. Alternatively she can include boost/algorithm/string/std_collection_traits.hpp
|
||||
header which contains specializations for all stl containers.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// sequence traits -----------------------------------------------//
|
||||
|
||||
|
||||
//! Native replace trait
|
||||
/*!
|
||||
This trait specifies that the sequence has \c std::string like replace method
|
||||
*/
|
||||
template< typename T >
|
||||
class has_native_replace
|
||||
{
|
||||
|
||||
public:
|
||||
# if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
enum { value = false };
|
||||
# else
|
||||
BOOST_STATIC_CONSTANT(bool, value=false);
|
||||
# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
|
||||
|
||||
typedef mpl::bool_<has_native_replace<T>::value> type;
|
||||
};
|
||||
|
||||
|
||||
//! Stable iterators trait
|
||||
/*!
|
||||
This trait specifies that the sequence has stable iterators. It means
|
||||
that operations like insert/erase/replace do not invalidate iterators.
|
||||
*/
|
||||
template< typename T >
|
||||
class has_stable_iterators
|
||||
{
|
||||
public:
|
||||
# if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
enum { value = false };
|
||||
# else
|
||||
BOOST_STATIC_CONSTANT(bool, value=false);
|
||||
# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
|
||||
typedef mpl::bool_<has_stable_iterators<T>::value> type;
|
||||
};
|
||||
|
||||
|
||||
//! Const time insert trait
|
||||
/*!
|
||||
This trait specifies that the sequence's insert method has
|
||||
constant time complexity.
|
||||
*/
|
||||
template< typename T >
|
||||
class has_const_time_insert
|
||||
{
|
||||
public:
|
||||
# if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
enum { value = false };
|
||||
# else
|
||||
BOOST_STATIC_CONSTANT(bool, value=false);
|
||||
# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
|
||||
typedef mpl::bool_<has_const_time_insert<T>::value> type;
|
||||
};
|
||||
|
||||
|
||||
//! Const time erase trait
|
||||
/*!
|
||||
This trait specifies that the sequence's erase method has
|
||||
constant time complexity.
|
||||
*/
|
||||
template< typename T >
|
||||
class has_const_time_erase
|
||||
{
|
||||
public:
|
||||
# if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
enum { value = false };
|
||||
# else
|
||||
BOOST_STATIC_CONSTANT(bool, value=false);
|
||||
# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
|
||||
typedef mpl::bool_<has_const_time_erase<T>::value> type;
|
||||
};
|
||||
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_SEQUENCE_TRAITS_HPP
|
||||
@ -1,163 +0,0 @@
|
||||
// Boost string_algo library split.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2006.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_SPLIT_HPP
|
||||
#define BOOST_STRING_SPLIT_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
|
||||
#include <boost/algorithm/string/iter_find.hpp>
|
||||
#include <boost/algorithm/string/finder.hpp>
|
||||
#include <boost/algorithm/string/compare.hpp>
|
||||
|
||||
/*! \file
|
||||
Defines basic split algorithms.
|
||||
Split algorithms can be used to divide a string
|
||||
into several parts according to given criteria.
|
||||
|
||||
Each part is copied and added as a new element to the
|
||||
output container.
|
||||
Thus the result container must be able to hold copies
|
||||
of the matches (in a compatible structure like std::string) or
|
||||
a reference to it (e.g. using the iterator range class).
|
||||
Examples of such a container are \c std::vector<std::string>
|
||||
or \c std::list<boost::iterator_range<std::string::iterator>>
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// find_all ------------------------------------------------------------//
|
||||
|
||||
//! Find all algorithm
|
||||
/*!
|
||||
This algorithm finds all occurrences of the search string
|
||||
in the input.
|
||||
|
||||
Each part is copied and added as a new element to the
|
||||
output container.
|
||||
Thus the result container must be able to hold copies
|
||||
of the matches (in a compatible structure like std::string) or
|
||||
a reference to it (e.g. using the iterator range class).
|
||||
Examples of such a container are \c std::vector<std::string>
|
||||
or \c std::list<boost::iterator_range<std::string::iterator>>
|
||||
|
||||
\param Result A container that can hold copies of references to the substrings
|
||||
\param Input A container which will be searched.
|
||||
\param Search A substring to be searched for.
|
||||
\return A reference the result
|
||||
|
||||
\note Prior content of the result will be overwritten.
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template< typename SequenceSequenceT, typename Range1T, typename Range2T >
|
||||
inline SequenceSequenceT& find_all(
|
||||
SequenceSequenceT& Result,
|
||||
Range1T& Input,
|
||||
const Range2T& Search)
|
||||
{
|
||||
return ::boost::algorithm::iter_find(
|
||||
Result,
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search) );
|
||||
}
|
||||
|
||||
//! Find all algorithm ( case insensitive )
|
||||
/*!
|
||||
This algorithm finds all occurrences of the search string
|
||||
in the input.
|
||||
Each part is copied and added as a new element to the
|
||||
output container. Thus the result container must be able to hold copies
|
||||
of the matches (in a compatible structure like std::string) or
|
||||
a reference to it (e.g. using the iterator range class).
|
||||
Examples of such a container are \c std::vector<std::string>
|
||||
or \c std::list<boost::iterator_range<std::string::iterator>>
|
||||
|
||||
Searching is case insensitive.
|
||||
|
||||
\param Result A container that can hold copies of references to the substrings
|
||||
\param Input A container which will be searched.
|
||||
\param Search A substring to be searched for.
|
||||
\param Loc A locale used for case insensitive comparison
|
||||
\return A reference the result
|
||||
|
||||
\note Prior content of the result will be overwritten.
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template< typename SequenceSequenceT, typename Range1T, typename Range2T >
|
||||
inline SequenceSequenceT& ifind_all(
|
||||
SequenceSequenceT& Result,
|
||||
Range1T& Input,
|
||||
const Range2T& Search,
|
||||
const std::locale& Loc=std::locale() )
|
||||
{
|
||||
return ::boost::algorithm::iter_find(
|
||||
Result,
|
||||
Input,
|
||||
::boost::algorithm::first_finder(Search, is_iequal(Loc) ) );
|
||||
}
|
||||
|
||||
|
||||
// tokenize -------------------------------------------------------------//
|
||||
|
||||
//! Split algorithm
|
||||
/*!
|
||||
Tokenize expression. This function is equivalent to C strtok. Input
|
||||
sequence is split into tokens, separated by separators. Separators
|
||||
are given by means of the predicate.
|
||||
|
||||
Each part is copied and added as a new element to the
|
||||
output container.
|
||||
Thus the result container must be able to hold copies
|
||||
of the matches (in a compatible structure like std::string) or
|
||||
a reference to it (e.g. using the iterator range class).
|
||||
Examples of such a container are \c std::vector<std::string>
|
||||
or \c std::list<boost::iterator_range<std::string::iterator>>
|
||||
|
||||
\param Result A container that can hold copies of references to the substrings
|
||||
\param Input A container which will be searched.
|
||||
\param Pred A predicate to identify separators. This predicate is
|
||||
supposed to return true if a given element is a separator.
|
||||
\param eCompress If eCompress argument is set to token_compress_on, adjacent
|
||||
separators are merged together. Otherwise, every two separators
|
||||
delimit a token.
|
||||
\return A reference the result
|
||||
|
||||
\note Prior content of the result will be overwritten.
|
||||
|
||||
\note This function provides the strong exception-safety guarantee
|
||||
*/
|
||||
template< typename SequenceSequenceT, typename RangeT, typename PredicateT >
|
||||
inline SequenceSequenceT& split(
|
||||
SequenceSequenceT& Result,
|
||||
RangeT& Input,
|
||||
PredicateT Pred,
|
||||
token_compress_mode_type eCompress=token_compress_off )
|
||||
{
|
||||
return ::boost::algorithm::iter_split(
|
||||
Result,
|
||||
Input,
|
||||
::boost::algorithm::token_finder( Pred, eCompress ) );
|
||||
}
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
// pull names to the boost namespace
|
||||
using algorithm::find_all;
|
||||
using algorithm::ifind_all;
|
||||
using algorithm::split;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_SPLIT_HPP
|
||||
|
||||
@ -1,68 +0,0 @@
|
||||
// Boost string_algo library list_traits.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_STD_LIST_TRAITS_HPP
|
||||
#define BOOST_STRING_STD_LIST_TRAITS_HPP
|
||||
|
||||
#include <boost/algorithm/string/yes_no_type.hpp>
|
||||
#include <list>
|
||||
#include <boost/algorithm/string/sequence_traits.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// std::list<> traits -----------------------------------------------//
|
||||
|
||||
|
||||
// stable iterators trait
|
||||
template<typename T, typename AllocT>
|
||||
class has_stable_iterators< ::std::list<T,AllocT> >
|
||||
{
|
||||
public:
|
||||
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
enum { value = true };
|
||||
#else
|
||||
BOOST_STATIC_CONSTANT(bool, value=true);
|
||||
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
typedef mpl::bool_<has_stable_iterators<T>::value> type;
|
||||
};
|
||||
|
||||
// const time insert trait
|
||||
template<typename T, typename AllocT>
|
||||
class has_const_time_insert< ::std::list<T,AllocT> >
|
||||
{
|
||||
public:
|
||||
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
enum { value = true };
|
||||
#else
|
||||
BOOST_STATIC_CONSTANT(bool, value=true);
|
||||
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
typedef mpl::bool_<has_const_time_insert<T>::value> type;
|
||||
};
|
||||
|
||||
// const time erase trait
|
||||
template<typename T, typename AllocT>
|
||||
class has_const_time_erase< ::std::list<T,AllocT> >
|
||||
{
|
||||
public:
|
||||
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
enum { value = true };
|
||||
#else
|
||||
BOOST_STATIC_CONSTANT(bool, value=true);
|
||||
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
typedef mpl::bool_<has_const_time_erase<T>::value> type;
|
||||
};
|
||||
|
||||
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_STD_LIST_TRAITS_HPP
|
||||
@ -1,69 +0,0 @@
|
||||
// Boost string_algo library slist_traits.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_STD_SLIST_TRAITS_HPP
|
||||
#define BOOST_STRING_STD_SLIST_TRAITS_HPP
|
||||
|
||||
#include <boost/algorithm/string/config.hpp>
|
||||
#include <boost/algorithm/string/yes_no_type.hpp>
|
||||
#include BOOST_SLIST_HEADER
|
||||
#include <boost/algorithm/string/sequence_traits.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// SGI's std::slist<> traits -----------------------------------------------//
|
||||
|
||||
|
||||
// stable iterators trait
|
||||
template<typename T, typename AllocT>
|
||||
class has_stable_iterators< BOOST_STD_EXTENSION_NAMESPACE::slist<T,AllocT> >
|
||||
{
|
||||
public:
|
||||
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
enum { value = true };
|
||||
#else
|
||||
BOOST_STATIC_CONSTANT(bool, value=true);
|
||||
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
typedef mpl::bool_<has_stable_iterators<T>::value> type;
|
||||
};
|
||||
|
||||
// const time insert trait
|
||||
template<typename T, typename AllocT>
|
||||
class has_const_time_insert< BOOST_STD_EXTENSION_NAMESPACE::slist<T,AllocT> >
|
||||
{
|
||||
public:
|
||||
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
enum { value = true };
|
||||
#else
|
||||
BOOST_STATIC_CONSTANT(bool, value=true);
|
||||
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
typedef mpl::bool_<has_const_time_insert<T>::value> type;
|
||||
};
|
||||
|
||||
// const time erase trait
|
||||
template<typename T, typename AllocT>
|
||||
class has_const_time_erase< BOOST_STD_EXTENSION_NAMESPACE::slist<T,AllocT> >
|
||||
{
|
||||
public:
|
||||
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
enum { value = true };
|
||||
#else
|
||||
BOOST_STATIC_CONSTANT(bool, value=true);
|
||||
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
typedef mpl::bool_<has_const_time_erase<T>::value> type;
|
||||
};
|
||||
|
||||
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_STD_LIST_TRAITS_HPP
|
||||
@ -1,44 +0,0 @@
|
||||
// Boost string_algo library string_traits.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_STD_STRING_TRAITS_HPP
|
||||
#define BOOST_STRING_STD_STRING_TRAITS_HPP
|
||||
|
||||
#include <boost/algorithm/string/yes_no_type.hpp>
|
||||
#include <string>
|
||||
#include <boost/algorithm/string/sequence_traits.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace algorithm {
|
||||
|
||||
// std::basic_string<> traits -----------------------------------------------//
|
||||
|
||||
|
||||
// native replace trait
|
||||
template<typename T, typename TraitsT, typename AllocT>
|
||||
class has_native_replace< std::basic_string<T, TraitsT, AllocT> >
|
||||
{
|
||||
public:
|
||||
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
enum { value = true } ;
|
||||
#else
|
||||
BOOST_STATIC_CONSTANT(bool, value=true);
|
||||
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
|
||||
|
||||
typedef mpl::bool_<has_native_replace<T>::value> type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace algorithm
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_STRING_LIST_TRAITS_HPP
|
||||
@ -1,26 +0,0 @@
|
||||
// Boost string_algo library std_containers_traits.hpp header file ---------------------------//
|
||||
|
||||
// Copyright Pavol Droba 2002-2003.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org/ for updates, documentation, and revision history.
|
||||
|
||||
#ifndef BOOST_STRING_STD_CONTAINERS_TRAITS_HPP
|
||||
#define BOOST_STRING_STD_CONTAINERS_TRAITS_HPP
|
||||
|
||||
/*!\file
|
||||
This file includes sequence traits for stl containers.
|
||||
*/
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/algorithm/string/std/string_traits.hpp>
|
||||
#include <boost/algorithm/string/std/list_traits.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_SLIST
|
||||
# include <boost/algorithm/string/std/slist_traits.hpp>
|
||||
#endif
|
||||
|
||||
#endif // BOOST_STRING_STD_CONTAINERS_TRAITS_HPP
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user